diff --git a/assets/svg/ic_activate.svg b/assets/svg/ic_activate.svg
new file mode 100644
index 00000000..fada1032
--- /dev/null
+++ b/assets/svg/ic_activate.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/ic_add.svg b/assets/svg/ic_add.svg
new file mode 100644
index 00000000..73e8ce7f
--- /dev/null
+++ b/assets/svg/ic_add.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/svg/ic_arrow.svg b/assets/svg/ic_arrow.svg
new file mode 100644
index 00000000..dde75b5f
--- /dev/null
+++ b/assets/svg/ic_arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/ic_big_trust.svg b/assets/svg/ic_big_trust.svg
new file mode 100644
index 00000000..6578e037
--- /dev/null
+++ b/assets/svg/ic_big_trust.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/ic_big_trust_activated.svg b/assets/svg/ic_big_trust_activated.svg
new file mode 100644
index 00000000..14c15f08
--- /dev/null
+++ b/assets/svg/ic_big_trust_activated.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/ic_block.svg b/assets/svg/ic_block.svg
new file mode 100644
index 00000000..8385597a
--- /dev/null
+++ b/assets/svg/ic_block.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/ic_contact_group.svg b/assets/svg/ic_contact_group.svg
new file mode 100644
index 00000000..c24d2bf2
--- /dev/null
+++ b/assets/svg/ic_contact_group.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/svg/ic_image.svg b/assets/svg/ic_image.svg
new file mode 100644
index 00000000..e43c4ce2
--- /dev/null
+++ b/assets/svg/ic_image.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/svg/ic_trash.svg b/assets/svg/ic_trash.svg
new file mode 100644
index 00000000..d4719184
--- /dev/null
+++ b/assets/svg/ic_trash.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/ic_trust.svg b/assets/svg/ic_trust.svg
new file mode 100644
index 00000000..27103ea7
--- /dev/null
+++ b/assets/svg/ic_trust.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/app.dart b/lib/app.dart
index b553c55c..c070f41b 100644
--- a/lib/app.dart
+++ b/lib/app.dart
@@ -1,3 +1,4 @@
+import 'package:atsign_atmosphere_pro/view_models/add_contact_provider.dart';
import 'package:atsign_atmosphere_pro/view_models/file_download_checker.dart';
import 'package:atsign_atmosphere_pro/desktop_routes/desktop_routes.dart';
import 'package:atsign_atmosphere_pro/view_models/file_progress_provider.dart';
@@ -50,6 +51,7 @@ class _MyAppState extends State {
ChangeNotifierProvider(
create: (context) => SideBarProvider()),
ChangeNotifierProvider(create: (context) => TrustedContactProvider()),
+ ChangeNotifierProvider(create: (context) => AddContactProvider()),
ChangeNotifierProvider(create: (context) => NestedRouteProvider()),
ChangeNotifierProvider(create: (context) => SwitchAtsignProvider()),
ChangeNotifierProvider(create: (context) => FileDownloadChecker()),
diff --git a/lib/screens/common_widgets/app_bar_custom.dart b/lib/screens/common_widgets/app_bar_custom.dart
index 88aa02d4..2c0450dc 100644
--- a/lib/screens/common_widgets/app_bar_custom.dart
+++ b/lib/screens/common_widgets/app_bar_custom.dart
@@ -42,7 +42,7 @@ class AppBarCustom extends StatelessWidget implements PreferredSizeWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
- Expanded(
+ Flexible(
child: Text(
title ?? '',
textAlign: TextAlign.left,
diff --git a/lib/screens/common_widgets/avatar_widget.dart b/lib/screens/common_widgets/avatar_widget.dart
new file mode 100644
index 00000000..71ad2f8d
--- /dev/null
+++ b/lib/screens/common_widgets/avatar_widget.dart
@@ -0,0 +1,74 @@
+import 'dart:typed_data';
+
+import 'package:at_contact/at_contact.dart';
+import 'package:at_contacts_flutter/widgets/custom_circle_avatar.dart';
+import 'package:at_contacts_group_flutter/widgets/contact_initial.dart';
+import 'package:flutter/material.dart';
+
+class AvatarWidget extends StatefulWidget {
+ final AtContact contact;
+ final double? borderRadius;
+ final double size;
+
+ const AvatarWidget({
+ Key? key,
+ this.size = 40,
+ this.borderRadius,
+ required this.contact,
+ }) : super(key: key);
+
+ @override
+ State createState() => _AvatarWidgetState();
+}
+
+class _AvatarWidgetState extends State {
+ String contactName = 'UG';
+ Uint8List? image;
+
+ @override
+ void initState() {
+ getNameAndImage();
+ super.initState();
+ }
+
+ void getNameAndImage() {
+ try {
+ contactName = widget.contact.atSign ?? 'UG';
+
+ if (contactName[0] == '@') {
+ contactName = contactName.substring(1);
+ }
+
+ if (widget.contact.tags != null &&
+ widget.contact.tags?['image'] != null) {
+ List intList = widget.contact.tags!['image'].cast();
+ image = Uint8List.fromList(intList);
+ }
+ } catch (e) {
+ contactName = 'UG';
+ print('Error in getting image $e');
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ height: widget.size,
+ width: widget.size,
+ decoration: const BoxDecoration(
+ color: Colors.black,
+ shape: BoxShape.circle,
+ ),
+ child: image != null
+ ? CustomCircleAvatar(
+ byteImage: image,
+ nonAsset: true,
+ )
+ : ContactInitial(
+ borderRadius: widget.borderRadius,
+ size: widget.size,
+ initials: contactName,
+ ),
+ );
+ }
+}
diff --git a/lib/screens/common_widgets/card_widget.dart b/lib/screens/common_widgets/card_widget.dart
new file mode 100644
index 00000000..72ef70e7
--- /dev/null
+++ b/lib/screens/common_widgets/card_widget.dart
@@ -0,0 +1,55 @@
+import 'package:atsign_atmosphere_pro/utils/colors.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+
+class CardButton extends StatelessWidget {
+ final String icon;
+ final String title;
+ final TextStyle? style;
+ final Function()? onTap;
+ final Color? backgroundColor;
+ final Color? borderColor;
+
+ const CardButton({
+ Key? key,
+ required this.icon,
+ required this.title,
+ this.style,
+ this.onTap,
+ this.backgroundColor,
+ this.borderColor,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return InkWell(
+ onTap: onTap,
+ child: Container(
+ height: 62,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(10),
+ color: backgroundColor ?? ColorConstants.lightGrey,
+ border: Border.all(
+ color: borderColor ?? ColorConstants.grey,
+ ),
+ ),
+ padding: const EdgeInsets.symmetric(horizontal: 32),
+ child: Row(
+ children: [
+ SvgPicture.asset(icon),
+ const SizedBox(width: 8),
+ Text(
+ title,
+ style: style ??
+ TextStyle(
+ fontSize: 18,
+ fontWeight: FontWeight.w500,
+ color: ColorConstants.grey,
+ ),
+ )
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screens/common_widgets/gradient_outline_input_border.dart b/lib/screens/common_widgets/gradient_outline_input_border.dart
new file mode 100644
index 00000000..280532cd
--- /dev/null
+++ b/lib/screens/common_widgets/gradient_outline_input_border.dart
@@ -0,0 +1,176 @@
+import 'dart:math' as math;
+import 'dart:ui';
+
+import 'package:flutter/material.dart';
+
+class GradientOutlineInputBorder extends InputBorder {
+ const GradientOutlineInputBorder({
+ required this.gradient,
+ this.width = 1.0,
+ this.gapPadding = 4.0,
+ this.borderRadius = const BorderRadius.all(Radius.circular(4)),
+ });
+
+ final double width;
+
+ final BorderRadius borderRadius;
+
+ final Gradient gradient;
+
+ final double gapPadding;
+
+ @override
+ InputBorder copyWith({BorderSide? borderSide}) {
+ return this;
+ }
+
+ @override
+ bool get isOutline => true;
+
+ @override
+ EdgeInsetsGeometry get dimensions => EdgeInsets.all(width);
+
+ @override
+ Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
+ return Path()
+ ..addRRect(
+ borderRadius
+ .resolve(textDirection)
+ .toRRect(rect)
+ .deflate(borderSide.width),
+ );
+ }
+
+ @override
+ Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
+ return Path()..addRRect(borderRadius.resolve(textDirection).toRRect(rect));
+ }
+
+ @override
+ void paint(
+ Canvas canvas,
+ Rect rect, {
+ double? gapStart,
+ double gapExtent = 0.0,
+ double gapPercentage = 0.0,
+ TextDirection? textDirection,
+ }) {
+ final paint = _getPaint(rect);
+ final outer = borderRadius.toRRect(rect);
+ final center = outer.deflate(borderSide.width / 2.0);
+ if (gapStart == null || gapExtent <= 0.0 || gapPercentage == 0.0) {
+ canvas.drawRRect(center, paint);
+ } else {
+ final extent =
+ lerpDouble(0.0, gapExtent + gapPadding * 2.0, gapPercentage)!;
+ switch (textDirection!) {
+ case TextDirection.rtl:
+ final path = _gapBorderPath(
+ canvas,
+ center,
+ math.max(0, gapStart + gapPadding - extent),
+ extent,
+ );
+ canvas.drawPath(path, paint);
+ break;
+
+ case TextDirection.ltr:
+ final path = _gapBorderPath(
+ canvas,
+ center,
+ math.max(0, gapStart - gapPadding),
+ extent,
+ );
+ canvas.drawPath(path, paint);
+ break;
+ }
+ }
+ }
+
+ @override
+ ShapeBorder scale(double t) {
+ return GradientOutlineInputBorder(
+ width: width * t,
+ borderRadius: borderRadius * t,
+ gradient: gradient,
+ );
+ }
+
+ Paint _getPaint(Rect rect) {
+ return Paint()
+ ..strokeWidth = width
+ ..shader = gradient.createShader(rect)
+ ..style = PaintingStyle.stroke;
+ }
+
+ Path _gapBorderPath(
+ Canvas canvas,
+ RRect center,
+ double start,
+ double extent,
+ ) {
+ // When the corner radii on any side add up to be greater than the
+ // given height, each radius has to be scaled to not exceed the
+ // size of the width/height of the RRect.
+ final scaledRRect = center.scaleRadii();
+
+ final tlCorner = Rect.fromLTWH(
+ scaledRRect.left,
+ scaledRRect.top,
+ scaledRRect.tlRadiusX * 2.0,
+ scaledRRect.tlRadiusY * 2.0,
+ );
+ final trCorner = Rect.fromLTWH(
+ scaledRRect.right - scaledRRect.trRadiusX * 2.0,
+ scaledRRect.top,
+ scaledRRect.trRadiusX * 2.0,
+ scaledRRect.trRadiusY * 2.0,
+ );
+ final brCorner = Rect.fromLTWH(
+ scaledRRect.right - scaledRRect.brRadiusX * 2.0,
+ scaledRRect.bottom - scaledRRect.brRadiusY * 2.0,
+ scaledRRect.brRadiusX * 2.0,
+ scaledRRect.brRadiusY * 2.0,
+ );
+ final blCorner = Rect.fromLTWH(
+ scaledRRect.left,
+ scaledRRect.bottom - scaledRRect.blRadiusY * 2.0,
+ scaledRRect.blRadiusX * 2.0,
+ scaledRRect.blRadiusX * 2.0,
+ );
+
+ const cornerArcSweep = math.pi / 2.0;
+ final tlCornerArcSweep = start < scaledRRect.tlRadiusX
+ ? math.asin((start / scaledRRect.tlRadiusX).clamp(-1.0, 1.0))
+ : math.pi / 2.0;
+
+ final path = Path()
+ ..addArc(tlCorner, math.pi, tlCornerArcSweep)
+ ..moveTo(scaledRRect.left + scaledRRect.tlRadiusX, scaledRRect.top);
+
+ if (start > scaledRRect.tlRadiusX) {
+ path.lineTo(scaledRRect.left + start, scaledRRect.top);
+ }
+
+ const trCornerArcStart = (3 * math.pi) / 2.0;
+ const trCornerArcSweep = cornerArcSweep;
+ if (start + extent < scaledRRect.width - scaledRRect.trRadiusX) {
+ path
+ ..relativeMoveTo(extent, 0)
+ ..lineTo(scaledRRect.right - scaledRRect.trRadiusX, scaledRRect.top)
+ ..addArc(trCorner, trCornerArcStart, trCornerArcSweep);
+ } else if (start + extent < scaledRRect.width) {
+ final dx = scaledRRect.width - (start + extent);
+ final sweep = math.acos(dx / scaledRRect.trRadiusX);
+ path.addArc(trCorner, trCornerArcStart + sweep, trCornerArcSweep - sweep);
+ }
+
+ return path
+ ..moveTo(scaledRRect.right, scaledRRect.top + scaledRRect.trRadiusY)
+ ..lineTo(scaledRRect.right, scaledRRect.bottom - scaledRRect.brRadiusY)
+ ..addArc(brCorner, 0, cornerArcSweep)
+ ..lineTo(scaledRRect.left + scaledRRect.blRadiusX, scaledRRect.bottom)
+ ..addArc(blCorner, math.pi / 2.0, cornerArcSweep)
+ ..lineTo(scaledRRect.left, scaledRRect.top + scaledRRect.tlRadiusY);
+ }
+}
\ No newline at end of file
diff --git a/lib/screens/common_widgets/gradient_text_field_widget.dart b/lib/screens/common_widgets/gradient_text_field_widget.dart
new file mode 100644
index 00000000..1d0e0dc8
--- /dev/null
+++ b/lib/screens/common_widgets/gradient_text_field_widget.dart
@@ -0,0 +1,77 @@
+import 'package:atsign_atmosphere_pro/screens/common_widgets/gradient_outline_input_border.dart';
+import 'package:atsign_atmosphere_pro/utils/colors.dart';
+import 'package:flutter/material.dart';
+
+class GradientTextFieldWidget extends StatefulWidget {
+ final String? hintText;
+ final TextStyle? hintTextStyle;
+ final TextEditingController? controller;
+ final Function(String value)? onchange;
+ final Function(String value)? onSubmitted;
+ final String? prefixText;
+ final TextStyle? prefixStyle;
+
+ const GradientTextFieldWidget({
+ Key? key,
+ this.hintText,
+ this.controller,
+ this.hintTextStyle,
+ this.onchange,
+ this.onSubmitted,
+ this.prefixText,
+ this.prefixStyle,
+ }) : super(key: key);
+
+ @override
+ State createState() =>
+ _GradientTextFieldWidgetState();
+}
+
+class _GradientTextFieldWidgetState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return SizedBox(
+ height: 44,
+ child: TextFormField(
+ controller: widget.controller,
+ onChanged: (value) {
+ widget.onchange?.call(value);
+ },
+ onFieldSubmitted: (value) {
+ widget.onSubmitted?.call(value);
+ },
+ decoration: InputDecoration(
+ prefixText: widget.prefixText,
+ prefixStyle: widget.prefixStyle,
+ border: GradientOutlineInputBorder(
+ gradient: LinearGradient(
+ colors: [
+ ColorConstants.orangeColor,
+ ColorConstants.yellow.withOpacity(0.65),
+ ],
+ ),
+ width: 2,
+ borderRadius: BorderRadius.circular(10),
+ ),
+ focusedBorder: GradientOutlineInputBorder(
+ gradient: LinearGradient(
+ colors: [
+ ColorConstants.orangeColor,
+ ColorConstants.yellow.withOpacity(0.65),
+ ],
+ ),
+ width: 2,
+ borderRadius: BorderRadius.circular(10),
+ ),
+ hintText: widget.hintText,
+ hintStyle: widget.hintTextStyle ??
+ TextStyle(
+ fontSize: 12,
+ fontWeight: FontWeight.w400,
+ color: ColorConstants.grey,
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screens/common_widgets/header_widget.dart b/lib/screens/common_widgets/header_widget.dart
new file mode 100644
index 00000000..5b7ef28f
--- /dev/null
+++ b/lib/screens/common_widgets/header_widget.dart
@@ -0,0 +1,150 @@
+import 'package:atsign_atmosphere_pro/utils/colors.dart';
+import 'package:atsign_atmosphere_pro/utils/vectors.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+
+class HeaderWidget extends StatefulWidget {
+ final Function()? onReloadCallback;
+ final TextEditingController? controller;
+ final Function(String)? onSearch;
+ final EdgeInsetsGeometry? margin;
+
+ const HeaderWidget({
+ Key? key,
+ this.onReloadCallback,
+ this.controller,
+ this.onSearch,
+ this.margin,
+ }) : super(key: key);
+
+ @override
+ State createState() => _HeaderWidgetState();
+}
+
+class _HeaderWidgetState extends State {
+ bool isSearch = false;
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ margin: widget.margin ?? const EdgeInsets.symmetric(horizontal: 28),
+ padding: const EdgeInsets.fromLTRB(14, 11, 8, 14),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(8),
+ color: ColorConstants.textBoxBg,
+ ),
+ child: Row(
+ children: [
+ _buildButton(
+ title: "Refresh",
+ icon: AppVectors.icReload,
+ onTap: widget.onReloadCallback,
+ ),
+ const SizedBox(width: 24),
+ Expanded(
+ child: _buildSearchWidget(),
+ ),
+ ],
+ ),
+ );
+ }
+
+ Widget _buildButton({
+ String? title,
+ required String icon,
+ Function()? onTap,
+ }) {
+ return InkWell(
+ onTap: () {
+ onTap?.call();
+ },
+ child: Column(
+ children: [
+ Text(
+ title ?? '',
+ style: TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.w600,
+ color: ColorConstants.sidebarTextUnselected,
+ ),
+ ),
+ const SizedBox(height: 5),
+ Container(
+ height: 48,
+ width: 48,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(10),
+ border: Border.all(
+ color: ColorConstants.grey,
+ ),
+ color: Colors.white,
+ ),
+ child: Center(
+ child: SvgPicture.asset(
+ icon,
+ color: ColorConstants.grey,
+ ),
+ ),
+ )
+ ],
+ ),
+ );
+ }
+
+ Widget _buildSearchWidget() {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ "Search",
+ style: TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.w600,
+ color: ColorConstants.sidebarTextUnselected,
+ ),
+ ),
+ const SizedBox(height: 5),
+ Container(
+ height: 48,
+ margin: const EdgeInsets.only(right: 12),
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: ColorConstants.grey,
+ ),
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(10),
+ ),
+ padding: const EdgeInsets.only(left: 6, right: 8),
+ child: Row(
+ children: [
+ Expanded(
+ child: TextField(
+ controller: widget.controller,
+ decoration: InputDecoration.collapsed(
+ hintText: 'Search History by atSign',
+ hintStyle: TextStyle(
+ color: ColorConstants.grey,
+ fontSize: 14,
+ fontWeight: FontWeight.w500,
+ fontStyle: FontStyle.italic,
+ ),
+ ),
+ onChanged: widget.onSearch,
+ ),
+ ),
+ SizedBox(width: 4),
+ SizedBox(
+ width: 20,
+ height: 20,
+ child: SvgPicture.asset(
+ AppVectors.icSearch,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/screens/contact_new_version/add_contact_screen.dart b/lib/screens/contact_new_version/add_contact_screen.dart
new file mode 100644
index 00000000..c088df95
--- /dev/null
+++ b/lib/screens/contact_new_version/add_contact_screen.dart
@@ -0,0 +1,218 @@
+import 'package:atsign_atmosphere_pro/screens/common_widgets/gradient_text_field_widget.dart';
+import 'package:atsign_atmosphere_pro/utils/colors.dart';
+import 'package:atsign_atmosphere_pro/view_models/add_contact_provider.dart';
+import 'package:atsign_atmosphere_pro/view_models/base_model.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+
+class AddContactScreen extends StatefulWidget {
+ const AddContactScreen({Key? key}) : super(key: key);
+
+ @override
+ State createState() => _AddContactScreenState();
+}
+
+class _AddContactScreenState extends State {
+ late TextEditingController atSignController;
+ late TextEditingController nicknameController;
+ late AddContactProvider addContactProvider, state;
+
+ @override
+ void initState() {
+ addContactProvider = context.read();
+ atSignController = TextEditingController();
+ nicknameController = TextEditingController();
+ super.initState();
+ addContactProvider.initData();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Consumer(
+ builder: (_c, provider, _) {
+ state = context.watch();
+ return Scaffold(
+ backgroundColor: Colors.transparent,
+ resizeToAvoidBottomInset: false,
+ body: Align(
+ alignment: Alignment.bottomCenter,
+ child: Container(
+ margin: EdgeInsets.only(top: 120),
+ width: double.infinity,
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(20),
+ topRight: Radius.circular(20),
+ ),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.25),
+ offset: const Offset(0, 4),
+ )
+ ],
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ height: 2,
+ width: 45,
+ margin: const EdgeInsets.only(left: 27, top: 38),
+ decoration: BoxDecoration(
+ color: Colors.black,
+ borderRadius: BorderRadius.circular(20),
+ ),
+ ),
+ const SizedBox(height: 24),
+ Expanded(
+ child: Stack(
+ children: [
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 27),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Text(
+ "Add Contact",
+ style: TextStyle(
+ fontSize: 25,
+ fontWeight: FontWeight.bold,
+ color: Colors.black,
+ ),
+ ),
+ const SizedBox(height: 53),
+ GradientTextFieldWidget(
+ hintText: 'Enter atSign',
+ controller: atSignController,
+ prefixText: "@",
+ prefixStyle: TextStyle(
+ fontSize: 14,
+ color: Colors.black,
+ ),
+ onSubmitted: (value) {
+ _checkValid();
+ },
+ ),
+ Visibility(
+ visible: state.atSignError.isNotEmpty,
+ child: Padding(
+ padding: const EdgeInsets.only(top: 6),
+ child: Text(
+ state.atSignError,
+ style: const TextStyle(
+ color: Colors.red,
+ fontSize: 12,
+ fontWeight: FontWeight.w400,
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(height: 24),
+ GradientTextFieldWidget(
+ hintText: 'Enter nickname',
+ controller: nicknameController,
+ onSubmitted: (value) {
+ _checkValid();
+ },
+ ),
+ const SizedBox(height: 44),
+ Container(
+ height: 1,
+ decoration: BoxDecoration(
+ color: ColorConstants.darkGray,
+ ),
+ ),
+ const SizedBox(height: 24),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const Text(
+ "atSign verified",
+ style: TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.w500,
+ color: Color(0xffCACACA),
+ ),
+ ),
+ const SizedBox(width: 10),
+ Icon(
+ Icons.check_circle_outlined,
+ color: state.isVerify
+ ? Colors.green
+ : ColorConstants.darkGray,
+ )
+ ],
+ ),
+ ],
+ ),
+ ),
+ state.status['add_contact_status'] == Status.Loading
+ ? Center(
+ child: CircularProgressIndicator(
+ valueColor: AlwaysStoppedAnimation(
+ ColorConstants.orange,
+ ),
+ ),
+ )
+ : SizedBox(),
+ ],
+ ),
+ ),
+ SafeArea(
+ top: false,
+ child: Padding(
+ padding: const EdgeInsets.fromLTRB(27, 0, 27, 40),
+ child: InkWell(
+ onTap: () async {
+ if (addContactProvider.isVerify) {
+ var response = await addContactProvider.addContact(
+ atSign: atSignController.text,
+ nickname: nicknameController.text,
+ );
+
+ if (response ?? false) {
+ Navigator.of(context).pop(true);
+ }
+ }
+ },
+ child: Container(
+ height: 60,
+ width: double.infinity,
+ decoration: BoxDecoration(
+ color: Colors.black,
+ borderRadius: BorderRadius.circular(8),
+ ),
+ child: const Center(
+ child: Text(
+ "Create New Contact",
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 16,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ )
+ ],
+ ),
+ ),
+ ),
+ );
+ },
+ );
+ }
+
+ void _checkValid() {
+ if (atSignController.text.isNotEmpty &&
+ nicknameController.text.isNotEmpty) {
+ addContactProvider.changeVerifyStatus(true);
+ } else {
+ addContactProvider.changeVerifyStatus(false);
+ }
+ }
+}
diff --git a/lib/screens/contact_new_version/blocked_contact_screen.dart b/lib/screens/contact_new_version/blocked_contact_screen.dart
new file mode 100644
index 00000000..4d0c4359
--- /dev/null
+++ b/lib/screens/contact_new_version/blocked_contact_screen.dart
@@ -0,0 +1,280 @@
+import 'package:at_contacts_flutter/models/contact_base_model.dart';
+import 'package:at_contacts_flutter/services/contact_service.dart';
+import 'package:atsign_atmosphere_pro/screens/common_widgets/header_widget.dart';
+import 'package:atsign_atmosphere_pro/utils/colors.dart';
+import 'package:flutter/material.dart';
+
+class BlockedContactScreen extends StatefulWidget {
+ const BlockedContactScreen({Key? key}) : super(key: key);
+
+ @override
+ State createState() => _BlockedContactScreenState();
+}
+
+class _BlockedContactScreenState extends State {
+ late ContactService _contactService;
+ late TextEditingController searchController;
+
+ @override
+ void initState() {
+ super.initState();
+ _contactService = ContactService();
+ searchController = TextEditingController();
+
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
+ await _contactService.fetchBlockContactList();
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.transparent,
+ body: Align(
+ alignment: Alignment.bottomCenter,
+ child: Container(
+ height: MediaQuery.of(context).size.height - 120,
+ width: double.infinity,
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(20),
+ topRight: Radius.circular(20),
+ ),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.25),
+ offset: const Offset(0, 4),
+ )
+ ],
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ _buildHeaderWidget(),
+ const SizedBox(height: 24),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 27),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Text(
+ "Blocked atSigns",
+ style: TextStyle(
+ fontSize: 25,
+ fontWeight: FontWeight.bold,
+ color: Colors.black,
+ ),
+ ),
+ const SizedBox(height: 30),
+ HeaderWidget(
+ margin: EdgeInsets.only(bottom: 28),
+ onReloadCallback: () async {
+ await _contactService.fetchBlockContactList();
+ searchController.clear();
+ },
+ controller: searchController,
+ onSearch: (value) {
+ setState(() {});
+ },
+ ),
+ Container(
+ height: 37,
+ padding: const EdgeInsets.only(left: 24),
+ alignment: Alignment.centerLeft,
+ decoration: BoxDecoration(
+ borderRadius: const BorderRadius.only(
+ topRight: Radius.circular(10),
+ topLeft: Radius.circular(10),
+ ),
+ color: ColorConstants.textBoxBg),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ "atSign",
+ style: TextStyle(
+ fontSize: 15,
+ fontWeight: FontWeight.w500,
+ color: ColorConstants.sidebarTextUnselected,
+ ),
+ ),
+ Icon(
+ Icons.arrow_downward_outlined,
+ color: ColorConstants.sidebarTextUnselected,
+ )
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 27),
+ child: _buildListBlocked(),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+
+ Widget _buildHeaderWidget() {
+ return Padding(
+ padding: const EdgeInsets.fromLTRB(27, 24, 27, 0),
+ child: Row(
+ children: [
+ Container(
+ height: 2,
+ width: 45,
+ decoration: BoxDecoration(
+ color: Colors.black,
+ borderRadius: BorderRadius.circular(20),
+ ),
+ ),
+ const Spacer(),
+ Align(
+ alignment: Alignment.topRight,
+ child: InkWell(
+ onTap: () {
+ Navigator.of(context).pop();
+ },
+ child: Container(
+ height: 31,
+ alignment: Alignment.topRight,
+ padding: const EdgeInsets.symmetric(
+ horizontal: 30,
+ ),
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: ColorConstants.grey,
+ ),
+ borderRadius: BorderRadius.circular(28),
+ ),
+ child: Center(
+ child: Text(
+ "Close",
+ style: TextStyle(
+ fontSize: 17,
+ fontWeight: FontWeight.w600,
+ color: ColorConstants.grey,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
+ _buildListBlocked() {
+ return StreamBuilder>(
+ stream: _contactService.blockedContactStream,
+ initialData: _contactService.baseBlockedList,
+ builder: (context, snapshot) {
+ if (snapshot.connectionState == ConnectionState.active) {
+ var listContact = snapshot.data!;
+ listContact = listContact
+ .where(
+ (element) => (element?.contact?.atSign ?? '')
+ .contains(searchController.text),
+ )
+ .toList();
+ return ListView.builder(
+ itemCount: listContact.length,
+ physics: ClampingScrollPhysics(),
+ padding: EdgeInsets.zero,
+ itemBuilder: (context, index) {
+ return Container(
+ height: 58,
+ color: Colors.white,
+ child: Column(
+ children: [
+ Expanded(
+ child: Row(
+ children: [
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.only(left: 18),
+ child: Text(
+ listContact[index]?.contact?.atSign ?? '',
+ style: TextStyle(
+ fontSize: 13,
+ fontWeight: FontWeight.w500,
+ color: ColorConstants.textBlack,
+ ),
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(right: 24),
+ child: InkWell(
+ onTap: () async {
+ await _contactService.blockUnblockContact(
+ contact: listContact[index]!.contact!,
+ blockAction: false,
+ );
+ },
+ child: Container(
+ height: 31,
+ padding: const EdgeInsets.symmetric(
+ horizontal: 14,
+ vertical: 7,
+ ),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(15),
+ color: ColorConstants.boxGrey,
+ border: Border.all(
+ color: ColorConstants.grey,
+ ),
+ ),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ "Unblock?",
+ style: TextStyle(
+ fontSize: 13,
+ fontWeight: FontWeight.w600,
+ color: ColorConstants.grey,
+ ),
+ ),
+ const SizedBox(width: 16),
+ const Icon(
+ Icons.block,
+ color: Colors.red,
+ size: 16,
+ )
+ ],
+ ),
+ ),
+ ),
+ )
+ ],
+ ),
+ ),
+ Container(
+ color: ColorConstants.textBoxBg,
+ height: 1,
+ width: double.infinity,
+ )
+ ],
+ ),
+ );
+ },
+ );
+ } else {
+ return const Center(
+ child: CircularProgressIndicator(),
+ );
+ }
+ },
+ );
+ }
+}
diff --git a/lib/screens/contact_new_version/contact_detail_screen.dart b/lib/screens/contact_new_version/contact_detail_screen.dart
new file mode 100644
index 00000000..53239ec0
--- /dev/null
+++ b/lib/screens/contact_new_version/contact_detail_screen.dart
@@ -0,0 +1,260 @@
+import 'package:at_contact/at_contact.dart';
+import 'package:at_contacts_flutter/services/contact_service.dart';
+import 'package:atsign_atmosphere_pro/screens/common_widgets/avatar_widget.dart';
+import 'package:atsign_atmosphere_pro/screens/common_widgets/card_widget.dart';
+import 'package:atsign_atmosphere_pro/utils/colors.dart';
+import 'package:atsign_atmosphere_pro/utils/vectors.dart';
+import 'package:atsign_atmosphere_pro/view_models/trusted_sender_view_model.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+
+class ContactDetailScreen extends StatefulWidget {
+ final AtContact contact;
+
+ const ContactDetailScreen({
+ Key? key,
+ required this.contact,
+ }) : super(key: key);
+
+ @override
+ State createState() => _ContactDetailScreenState();
+}
+
+class _ContactDetailScreenState extends State {
+ late TrustedContactProvider _trustedContactProvider;
+ late ContactService _contactService;
+
+ bool isTrusted = false;
+
+ @override
+ void initState() {
+ _trustedContactProvider = TrustedContactProvider();
+ _contactService = ContactService();
+ checkTrustedContact();
+ super.initState();
+ }
+
+ void checkTrustedContact() {
+ _trustedContactProvider.trustedContacts.forEach((element) {
+ if (element.atSign == widget.contact.atSign) {
+ setState(() {
+ isTrusted = true;
+ });
+ }
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.transparent,
+ body: Align(
+ alignment: Alignment.bottomCenter,
+ child: Container(
+ height: double.infinity,
+ width: double.infinity,
+ margin: EdgeInsets.only(top: 120),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(20),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.25),
+ offset: const Offset(0, 4),
+ )
+ ],
+ ),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Row(
+ children: [
+ const Spacer(),
+ Align(
+ alignment: Alignment.topRight,
+ child: InkWell(
+ onTap: () {
+ Navigator.of(context).pop();
+ },
+ child: Container(
+ height: 31,
+ alignment: Alignment.topRight,
+ padding: const EdgeInsets.symmetric(
+ horizontal: 30,
+ ),
+ margin: const EdgeInsets.only(right: 27, top: 30),
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: ColorConstants.grey,
+ ),
+ borderRadius: BorderRadius.circular(28),
+ ),
+ child: Center(
+ child: Text(
+ "Close",
+ style: TextStyle(
+ fontSize: 17,
+ fontWeight: FontWeight.w600,
+ color: ColorConstants.grey,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ const SizedBox(height: 11),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 42),
+ child: Row(
+ children: [
+ AvatarWidget(
+ size: 83,
+ borderRadius: 24,
+ contact: widget.contact,
+ ),
+ const SizedBox(width: 25),
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Flexible(
+ child: Text(
+ widget.contact.atSign ?? '',
+ style: const TextStyle(
+ fontSize: 18,
+ fontWeight: FontWeight.w600,
+ ),
+ overflow: TextOverflow.ellipsis,
+ ),
+ ),
+ const SizedBox(height: 5),
+ Flexible(
+ child: Text(
+ widget.contact.tags?['name'] ??
+ widget.contact.atSign!.substring(1),
+ style: const TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.w400,
+ ),
+ ),
+ ),
+ ],
+ ),
+ )
+ ],
+ ),
+ ),
+ const SizedBox(height: 25),
+ Flexible(
+ child: SingleChildScrollView(
+ physics: ClampingScrollPhysics(),
+ padding: const EdgeInsets.symmetric(
+ horizontal: 36,
+ vertical: 25,
+ ),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ height: 63,
+ decoration: BoxDecoration(
+ gradient: const LinearGradient(
+ begin: Alignment.topLeft,
+ end: Alignment.bottomRight,
+ colors: [
+ Color(0xfff05e3f),
+ Color(0xffeaa743),
+ ],
+ ),
+ borderRadius: BorderRadius.circular(10),
+ ),
+ child: Center(
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const Text(
+ "Transfer Now",
+ style: TextStyle(
+ fontSize: 20,
+ fontWeight: FontWeight.w700,
+ color: Colors.white,
+ ),
+ ),
+ const SizedBox(width: 24),
+ SvgPicture.asset(
+ AppVectors.icArrow,
+ ),
+ ],
+ ),
+ ),
+ ),
+ const SizedBox(height: 46),
+ isTrusted
+ ? CardButton(
+ icon: AppVectors.icBigTrustActivated,
+ title: "Trusted",
+ style: TextStyle(
+ fontSize: 18,
+ fontWeight: FontWeight.w500,
+ color: ColorConstants.orange,
+ ),
+ borderColor: ColorConstants.orange,
+ backgroundColor:
+ ColorConstants.orange.withOpacity(0.2),
+ onTap: () async {
+ await _trustedContactProvider
+ .removeTrustedContacts(widget.contact);
+ setState(() {
+ isTrusted = false;
+ });
+ },
+ )
+ : CardButton(
+ icon: AppVectors.icTrust,
+ title: "Add To Trusted",
+ onTap: () async {
+ await _trustedContactProvider
+ .addTrustedContacts(widget.contact);
+ setState(() {
+ isTrusted = true;
+ });
+ },
+ ),
+ const SizedBox(height: 25),
+ CardButton(
+ icon: AppVectors.icTrash,
+ title: "Delete",
+ onTap: () async {
+ await _contactService.deleteAtSign(
+ atSign: widget.contact.atSign!,
+ );
+ Navigator.of(context).pop(true);
+ },
+ ),
+ const SizedBox(height: 25),
+ CardButton(
+ icon: AppVectors.icBlock,
+ title: "Block",
+ onTap: () async {
+ await _contactService.blockUnblockContact(
+ contact: widget.contact,
+ blockAction: true,
+ );
+ Navigator.of(context).pop(true);
+ },
+ ),
+ const SizedBox(height: 25),
+ ],
+ ),
+ ),
+ )
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screens/contact_new_version/contact_screen.dart b/lib/screens/contact_new_version/contact_screen.dart
new file mode 100644
index 00000000..9e2bf444
--- /dev/null
+++ b/lib/screens/contact_new_version/contact_screen.dart
@@ -0,0 +1,199 @@
+import 'package:at_contacts_group_flutter/screens/new_version/contact_screen.dart';
+import 'package:at_contacts_group_flutter/services/group_service.dart';
+import 'package:atsign_atmosphere_pro/screens/common_widgets/app_bar_custom.dart';
+import 'package:atsign_atmosphere_pro/screens/contact_new_version/add_contact_screen.dart';
+import 'package:atsign_atmosphere_pro/screens/contact_new_version/blocked_contact_screen.dart';
+import 'package:atsign_atmosphere_pro/screens/contact_new_version/contact_detail_screen.dart';
+import 'package:atsign_atmosphere_pro/screens/contact_new_version/group_contact_screen.dart';
+import 'package:atsign_atmosphere_pro/screens/contact_new_version/trusted_contact_screen.dart';
+import 'package:atsign_atmosphere_pro/utils/colors.dart';
+import 'package:atsign_atmosphere_pro/utils/vectors.dart';
+import 'package:atsign_atmosphere_pro/view_models/trusted_sender_view_model.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:provider/provider.dart';
+
+class ContactScreen extends StatefulWidget {
+ const ContactScreen({Key? key}) : super(key: key);
+
+ @override
+ State createState() => _ContactScreenState();
+}
+
+class _ContactScreenState extends State {
+ late TrustedContactProvider trustedProvider;
+ late GroupService _groupService;
+
+ @override
+ void initState() {
+ trustedProvider = context.read();
+ _groupService = GroupService();
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBarCustom(
+ height: 130,
+ title: "Contacts",
+ description: '${_groupService.listContact.length}',
+ suffixIcon: Padding(
+ padding: const EdgeInsets.only(right: 30),
+ child: InkWell(
+ onTap: () async {
+ final result = await showModalBottomSheet(
+ context: context,
+ isScrollControlled: true,
+ useRootNavigator: true,
+ backgroundColor: Colors.transparent,
+ builder: (BuildContext context) {
+ return AddContactScreen();
+ },
+ );
+ if (result == true) {
+ reloadPage();
+ }
+ },
+ child: SvgPicture.asset(
+ AppVectors.icAdd,
+ ),
+ ),
+ ),
+ ),
+ body: buildBody(),
+ );
+ }
+
+ Widget buildBody() {
+ return Column(
+ children: [
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 30),
+ child: Row(
+ children: [
+ _buildHeaderItem(
+ title: 'Blocked atSign',
+ icon: AppVectors.icBlock,
+ onTap: () async {
+ await showModalBottomSheet(
+ context: context,
+ isScrollControlled: true,
+ useRootNavigator: true,
+ backgroundColor: Colors.transparent,
+ builder: (BuildContext context) {
+ return BlockedContactScreen();
+ },
+ );
+ reloadPage();
+ },
+ ),
+ _buildHeaderItem(
+ title: 'Trusted Senders',
+ icon: AppVectors.icTrust,
+ onTap: () async {
+ await showModalBottomSheet(
+ context: context,
+ isScrollControlled: true,
+ useRootNavigator: true,
+ backgroundColor: Colors.transparent,
+ builder: (BuildContext context) {
+ return TrustedContactScreen();
+ },
+ );
+ reloadPage();
+ },
+ ),
+ _buildHeaderItem(
+ title: 'My Groups',
+ icon: AppVectors.icContactGroup,
+ onTap: () {
+ return showModalBottomSheet(
+ context: context,
+ isScrollControlled: true,
+ useRootNavigator: true,
+ backgroundColor: Colors.transparent,
+ builder: (BuildContext context) {
+ return GroupContactScreen();
+ },
+ );
+ },
+ ),
+ ],
+ ),
+ ),
+ Expanded(
+ child: ListContactScreen(
+ contactsTrusted: trustedProvider.trustedContacts,
+ onTapContact: (contact) async {
+ await showModalBottomSheet(
+ context: context,
+ isScrollControlled: true,
+ useRootNavigator: true,
+ backgroundColor: Colors.transparent,
+ builder: (BuildContext context) {
+ return ContactDetailScreen(
+ contact: contact,
+ );
+ },
+ );
+
+ reloadPage();
+ },
+ ),
+ ),
+ SizedBox(height: 80),
+ ],
+ );
+ }
+
+ Widget _buildHeaderItem({
+ required String title,
+ required String icon,
+ required Function onTap,
+ }) {
+ return Expanded(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 15),
+ child: InkWell(
+ onTap: () {
+ onTap.call();
+ },
+ child: Container(
+ padding: EdgeInsets.symmetric(horizontal: 4, vertical: 12),
+ decoration: BoxDecoration(
+ color: ColorConstants.fadedGreyN,
+ border: Border.all(
+ color: ColorConstants.grey,
+ ),
+ borderRadius: BorderRadius.circular(8),
+ ),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ SvgPicture.asset(icon),
+ SizedBox(height: 8),
+ Text(
+ title,
+ style: TextStyle(
+ fontSize: 13,
+ fontWeight: FontWeight.w500,
+ color: ColorConstants.grey,
+ ),
+ textAlign: TextAlign.center,
+ )
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ void reloadPage() async {
+ await Future.delayed(Duration(milliseconds: 500), () async {
+ await _groupService.fetchGroupsAndContacts();
+ setState(() {});
+ });
+ }
+}
diff --git a/lib/screens/contact_new_version/group_contact_screen.dart b/lib/screens/contact_new_version/group_contact_screen.dart
new file mode 100644
index 00000000..7dd7aa3f
--- /dev/null
+++ b/lib/screens/contact_new_version/group_contact_screen.dart
@@ -0,0 +1,196 @@
+import 'package:at_contacts_group_flutter/screens/group_view/group_view.dart';
+import 'package:at_contacts_group_flutter/screens/new_group/create_group.dart';
+import 'package:at_contacts_group_flutter/screens/new_version/contact_screen.dart';
+import 'package:at_contacts_group_flutter/services/group_service.dart';
+import 'package:atsign_atmosphere_pro/utils/colors.dart';
+import 'package:atsign_atmosphere_pro/view_models/trusted_sender_view_model.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+
+class GroupContactScreen extends StatefulWidget {
+ const GroupContactScreen({Key? key}) : super(key: key);
+
+ @override
+ State createState() => _GroupContactScreenState();
+}
+
+class _GroupContactScreenState extends State {
+ late GroupService groupService;
+ late TrustedContactProvider trustedProvider;
+
+ @override
+ void initState() {
+ groupService = GroupService();
+ trustedProvider = context.read();
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.transparent,
+ body: Align(
+ alignment: Alignment.bottomCenter,
+ child: Container(
+ height: MediaQuery.of(context).size.height - 120,
+ width: double.infinity,
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(20),
+ topRight: Radius.circular(20),
+ ),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.25),
+ offset: const Offset(0, 4),
+ )
+ ],
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Padding(
+ padding: const EdgeInsets.fromLTRB(27, 24, 27, 0),
+ child: Row(
+ children: [
+ Container(
+ height: 2,
+ width: 45,
+ decoration: BoxDecoration(
+ color: Colors.black,
+ borderRadius: BorderRadius.circular(20),
+ ),
+ ),
+ const Spacer(),
+ Align(
+ alignment: Alignment.topRight,
+ child: InkWell(
+ onTap: () {
+ Navigator.of(context).pop();
+ },
+ child: Container(
+ height: 31,
+ alignment: Alignment.topRight,
+ padding: const EdgeInsets.symmetric(
+ horizontal: 30,
+ ),
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: ColorConstants.grey,
+ ),
+ borderRadius: BorderRadius.circular(28),
+ ),
+ child: Center(
+ child: Text(
+ "Close",
+ style: TextStyle(
+ fontSize: 17,
+ fontWeight: FontWeight.w600,
+ color: ColorConstants.grey,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 24),
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Padding(
+ padding: EdgeInsets.only(left: 27),
+ child: Text(
+ "My Groups",
+ style: TextStyle(
+ fontSize: 25,
+ fontWeight: FontWeight.bold,
+ color: Colors.black,
+ ),
+ ),
+ ),
+ const SizedBox(height: 30),
+ Expanded(
+ child: ListContactScreen(
+ showGroups: true,
+ showContacts: false,
+ isHiddenAlpha: true,
+ onTapGroup: (group) async {
+ WidgetsBinding.instance
+ .addPostFrameCallback((_) async {
+ groupService.groupViewSink.add(group);
+ });
+
+ await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => GroupView(
+ group: group,
+ ),
+ ),
+ );
+ },
+ ),
+ ),
+ SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.only(bottom: 24, top: 18),
+ child: InkWell(
+ onTap: () async {
+ final result = await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (_) => CreateGroupScreen(
+ trustContacts:
+ trustedProvider.trustedContacts,
+ ),
+ ),
+ );
+
+ if (result == true) {
+ await groupService.fetchGroupsAndContacts();
+ setState(() {});
+ }
+ },
+ child: Container(
+ height: 67,
+ margin: const EdgeInsets.symmetric(horizontal: 27),
+ width: double.infinity,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(8),
+ gradient: LinearGradient(
+ colors: [
+ const Color(0xfff05e3f),
+ const Color(0xffeaa743).withOpacity(0.65),
+ ],
+ ),
+ ),
+ child: const Center(
+ child: Text(
+ "Create Group",
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 20,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ )
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screens/contact_new_version/trusted_contact_screen.dart b/lib/screens/contact_new_version/trusted_contact_screen.dart
new file mode 100644
index 00000000..ac0f22dd
--- /dev/null
+++ b/lib/screens/contact_new_version/trusted_contact_screen.dart
@@ -0,0 +1,208 @@
+import 'package:at_contact/at_contact.dart';
+import 'package:at_contacts_group_flutter/screens/new_version/widget/single_contact_widget.dart';
+import 'package:atsign_atmosphere_pro/screens/contact_new_version/contact_detail_screen.dart';
+import 'package:atsign_atmosphere_pro/utils/colors.dart';
+import 'package:atsign_atmosphere_pro/view_models/trusted_sender_view_model.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+
+class TrustedContactScreen extends StatefulWidget {
+ const TrustedContactScreen({Key? key}) : super(key: key);
+
+ @override
+ State createState() => _TrustedContactScreenState();
+}
+
+class _TrustedContactScreenState extends State {
+ late TrustedContactProvider provider;
+ late TextEditingController searchController;
+
+ List trustedContacts = [];
+
+ @override
+ void initState() {
+ provider = context.read();
+ searchController = TextEditingController();
+ super.initState();
+ trustedContacts = provider.trustedContacts;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.transparent,
+ body: Align(
+ alignment: Alignment.bottomCenter,
+ child: Container(
+ margin: EdgeInsets.only(top: 120),
+ height: double.infinity,
+ width: double.infinity,
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(20),
+ topRight: Radius.circular(20),
+ ),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.25),
+ offset: const Offset(0, 4),
+ )
+ ],
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ _buildHeaderWidget(),
+ const SizedBox(height: 24),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 27),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Text(
+ "Trusted Senders",
+ style: TextStyle(
+ fontSize: 25,
+ fontWeight: FontWeight.bold,
+ color: Colors.black,
+ ),
+ ),
+ const SizedBox(height: 30),
+ Container(
+ height: 48,
+ margin: const EdgeInsets.only(right: 12),
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: ColorConstants.grey,
+ ),
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(10),
+ ),
+ padding: const EdgeInsets.symmetric(horizontal: 12),
+ child: Row(
+ children: [
+ Expanded(
+ child: TextField(
+ controller: searchController,
+ onChanged: (value) {
+ setState(() {
+ trustedContacts = provider.trustedContacts
+ .where((element) => (element.atSign ?? '')
+ .contains(value))
+ .toList();
+ });
+ },
+ decoration: InputDecoration.collapsed(
+ hintText: 'Search by atSign or nickname',
+ hintStyle: TextStyle(
+ color: ColorConstants.grey,
+ fontSize: 14,
+ fontWeight: FontWeight.w500,
+ fontStyle: FontStyle.italic,
+ ),
+ ),
+ // onChanged: widget.onSearch,
+ ),
+ ),
+ SizedBox(
+ width: 20,
+ height: 20,
+ child: Icon(
+ Icons.search,
+ color: ColorConstants.grey,
+ ),
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 24),
+ ],
+ ),
+ ),
+ Expanded(
+ child: Consumer(
+ builder: (context, myProvider, child) {
+ return Scrollbar(
+ child: SingleContactWidget(
+ contacts: trustedContacts,
+ onTapContact: (contact) async {
+ await showModalBottomSheet(
+ context: context,
+ isScrollControlled: true,
+ useRootNavigator: true,
+ backgroundColor: Colors.transparent,
+ builder: (BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.only(top: 120),
+ child: ContactDetailScreen(
+ contact: contact,
+ ),
+ );
+ },
+ );
+ },
+ ),
+ );
+ },
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+
+ Widget _buildHeaderWidget() {
+ return Padding(
+ padding: const EdgeInsets.fromLTRB(27, 24, 27, 0),
+ child: Row(
+ children: [
+ Container(
+ height: 2,
+ width: 45,
+ decoration: BoxDecoration(
+ color: Colors.black,
+ borderRadius: BorderRadius.circular(20),
+ ),
+ ),
+ const Spacer(),
+ Align(
+ alignment: Alignment.topRight,
+ child: InkWell(
+ onTap: () {
+ Navigator.of(context).pop();
+ },
+ child: Container(
+ height: 31,
+ alignment: Alignment.topRight,
+ padding: const EdgeInsets.symmetric(
+ horizontal: 30,
+ ),
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: ColorConstants.grey,
+ ),
+ borderRadius: BorderRadius.circular(28),
+ ),
+ child: Center(
+ child: Text(
+ "Close",
+ style: TextStyle(
+ fontSize: 17,
+ fontWeight: FontWeight.w600,
+ color: ColorConstants.grey,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/screens/welcome_screen/welcome_screen.dart b/lib/screens/welcome_screen/welcome_screen.dart
index 7b310534..c90afe83 100644
--- a/lib/screens/welcome_screen/welcome_screen.dart
+++ b/lib/screens/welcome_screen/welcome_screen.dart
@@ -1,7 +1,7 @@
-import 'package:at_contacts_flutter/screens/contacts_screen.dart';
import 'package:at_contacts_flutter/utils/init_contacts_service.dart';
import 'package:at_contacts_group_flutter/services/group_service.dart';
import 'package:atsign_atmosphere_pro/screens/common_widgets/error_screen.dart';
+import 'package:atsign_atmosphere_pro/screens/contact_new_version/contact_screen.dart';
import 'package:atsign_atmosphere_pro/screens/history/history_screen.dart';
import 'package:atsign_atmosphere_pro/screens/history/transfer_history_screen.dart';
import 'package:atsign_atmosphere_pro/screens/my_files/my_files_screen.dart';
@@ -101,7 +101,7 @@ class _WelcomeScreenState extends State {
static List _bottomSheetWidgetOptions = [
WelcomeScreenHome(),
- ContactsScreen(),
+ ContactScreen(),
MyFilesScreen(),
TransferHistoryScreen(),
SettingsScreen()
diff --git a/lib/utils/colors.dart b/lib/utils/colors.dart
index 8e73c4f1..2301abe9 100644
--- a/lib/utils/colors.dart
+++ b/lib/utils/colors.dart
@@ -42,6 +42,11 @@ class ColorConstants {
static const Color fadedGreyN = Color(0xFFF1F1F1);
static const Color dividerGrey = Color(0xFFD9D9D9);
static const Color grey = Color(0xFF939393);
+ static const Color orange = Color(0xFFF07C50);
+ static const Color lightGrey = Color(0xFFF1F1F1);
+ static const Color boxGrey = Color(0xFFEFEFEF);
+ static const Color darkGray = Color(0xFFC0C0C0);
+ static const Color buttonGrey = Color(0xFFC7C7C7);
static const Color sidebarTextUnselected = Color(0xFFA4A4A5);
static const Color sidebarTextSelected = Color(0xFF000000);
diff --git a/lib/utils/vectors.dart b/lib/utils/vectors.dart
index 125351d7..dcde9d8e 100644
--- a/lib/utils/vectors.dart
+++ b/lib/utils/vectors.dart
@@ -13,4 +13,14 @@ class AppVectors {
static String icReceiveBorder = '$_basePath/ic_receive_border.svg';
static String icSendBorder = '$_basePath/ic_send_border.svg';
static String icNote = '$_basePath/ic_note.svg';
+ static String icActivate = '$_basePath/ic_activate.svg';
+ static String icAdd = '$_basePath/ic_add.svg';
+ static String icBlock = '$_basePath/ic_block.svg';
+ static String icContactGroup = '$_basePath/ic_contact_group.svg';
+ static String icTrust = '$_basePath/ic_trust.svg';
+ static String icBigTrust = '$_basePath/ic_big_trust.svg';
+ static String icBigTrustActivated = '$_basePath/ic_big_trust_activated.svg';
+ static String icTrash = '$_basePath/ic_trash.svg';
+ static String icArrow = '$_basePath/ic_arrow.svg';
+ static String icImage = '$_basePath/ic_image.svg';
}
diff --git a/lib/view_models/add_contact_provider.dart b/lib/view_models/add_contact_provider.dart
new file mode 100644
index 00000000..04df454e
--- /dev/null
+++ b/lib/view_models/add_contact_provider.dart
@@ -0,0 +1,45 @@
+import 'package:at_contacts_flutter/services/contact_service.dart';
+import 'package:atsign_atmosphere_pro/view_models/base_model.dart';
+
+class AddContactProvider extends BaseModel {
+ String addContactStatus = 'add_contact_status';
+ ContactService contactService = ContactService();
+ bool isVerify = false;
+ String atSignError = '';
+
+ void initData() {
+ contactService.resetData();
+ isVerify = false;
+ }
+
+ void changeVerifyStatus(bool verify) {
+ if (verify) atSignError = '';
+ isVerify = verify;
+ notifyListeners();
+ }
+
+ Future addContact({
+ required String atSign,
+ required String nickname,
+ }) async {
+ setStatus(addContactStatus, Status.Loading);
+ try {
+ await Future.delayed(Duration(seconds: 2));
+ var response = await contactService.addAtSign(
+ atSign: atSign,
+ nickName: nickname,
+ );
+
+ if (response && (contactService.checkAtSign ?? false)) {
+ setStatus(addContactStatus, Status.Done);
+ return true;
+ } else {
+ atSignError = contactService.getAtSignError;
+ setStatus(addContactStatus, Status.Done);
+ }
+ } catch (e) {
+ setStatus(addContactStatus, Status.Error);
+ }
+ return null;
+ }
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index ae1a3982..3ac09218 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -54,7 +54,7 @@ dependencies:
webview_flutter: ^3.0.4
http: ^0.13.4
package_info_plus: ^1.4.2
- fluttertoast: ^8.0.9
+ fluttertoast: 8.1.2
file_selector: ^0.8.3
file_selector_macos: ^0.8.2
carousel_slider: ^4.0.0
@@ -85,9 +85,9 @@ dependency_overrides:
biometric_storage: ^4.1.3
at_contacts_group_flutter:
git:
- url: https://github.com/atsign-foundation/at_widgets.git
- path: at_contacts_group_flutter
- ref: trunk
+ url: https://github.com/atsign-foundation/at_widgets
+ path: packages/at_contacts_group_flutter
+ ref: feature/new-version-contacts-group
at_backupkey_flutter:
git:
url: https://github.com/atsign-foundation/at_widgets.git