diff --git a/lib/backend/modules/contacts.dart b/lib/backend/modules/contacts.dart index 0fed98f..153e95e 100644 --- a/lib/backend/modules/contacts.dart +++ b/lib/backend/modules/contacts.dart @@ -159,7 +159,7 @@ class ContactsModule { final resp = await api.sendRequest(Opcode.contactUpdate, { 'action': 'ADD', 'contactId': id, - 'firstName': firstName, + if (firstName.isNotEmpty) 'firstName': firstName, }); final profile = await AppDatabase.loadActiveProfile(); diff --git a/lib/frontend/screens/chats/chat_info_screen.dart b/lib/frontend/screens/chats/chat_info_screen.dart index ceed797..3b4443a 100644 --- a/lib/frontend/screens/chats/chat_info_screen.dart +++ b/lib/frontend/screens/chats/chat_info_screen.dart @@ -134,6 +134,7 @@ class _ChatInfoScreenState extends State int _lastEventTime = 0; bool _blocked = false; bool _muteBusy = false; + bool _addContactBusy = false; @override void initState() { @@ -810,17 +811,63 @@ class _ChatInfoScreenState extends State return Padding( padding: const EdgeInsets.symmetric(horizontal: 12), - child: Row( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - for (int i = 0; i < btns.length; i++) ...[ - _actionBtn(cs, btns[i].icon, btns[i].label, btns[i].onTap), - if (i < btns.length - 1) const SizedBox(width: 8), + Row( + children: [ + for (int i = 0; i < btns.length; i++) ...[ + _actionBtn(cs, btns[i].icon, btns[i].label, btns[i].onTap), + if (i < btns.length - 1) const SizedBox(width: 8), + ], + ], + ), + if (_canAddContact) ...[ + const SizedBox(height: 8), + _wideActionBtn( + cs, + Symbols.person_add, + l10n.contactProfileActionAddContact, + _addContactBusy ? null : _addToContacts, + ), ], ], ), ); } + bool get _canAddContact => + widget.chatType == 'DIALOG' && + !_isContact && + !_isBot && + !_peerDeleted && + _otherId != null && + _otherId != _myId; + + Future _addToContacts() async { + final peerId = _otherId; + if (peerId == null || _addContactBusy) return; + setState(() => _addContactBusy = true); + + CachedContact? contact; + try { + contact = await ContactsModule.addContact(api, peerId, ''); + } catch (_) {} + + if (!mounted) return; + setState(() { + _addContactBusy = false; + if (contact != null) { + _localContact = contact; + _showRealName = false; + } + }); + showCustomNotification( + context, + contact != null ? l10n.nfcContactAdded : l10n.addContactError, + ); + } + void _openChat() { if (widget.openedFromChat) { Navigator.of(context).pop(); @@ -1071,6 +1118,37 @@ class _ChatInfoScreenState extends State ); } + Widget _wideActionBtn( + ColorScheme cs, + IconData icon, + String label, [ + VoidCallback? onTap, + ]) { + return GlossyPill( + onTap: onTap, + color: cs.surfaceContainerHigh, + borderRadius: BorderRadius.circular(14), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 12), + depth: 6, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(icon, color: cs.primary, size: 22), + const SizedBox(width: 8), + Flexible( + child: Text( + label, + style: TextStyle(color: cs.onSurface, fontSize: 13), + textAlign: TextAlign.center, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ); + } + Widget _buildPersistentInfo(ColorScheme cs) { final items = []; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f1f0403..99f9849 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -454,6 +454,7 @@ "contactProfileActionChat": "Chat", "contactProfileActionSound": "Sound", "contactProfileActionCall": "Call", + "contactProfileActionAddContact": "Add to contacts", "contactProfileInfoPhone": "Phone", "contactProfileInfoCountry": "Country", "contactProfileInfoGender": "Gender", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 5d8cfee..49555ab 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -2360,6 +2360,12 @@ abstract class AppLocalizations { /// **'Call'** String get contactProfileActionCall; + /// No description provided for @contactProfileActionAddContact. + /// + /// In en, this message translates to: + /// **'Add to contacts'** + String get contactProfileActionAddContact; + /// No description provided for @contactProfileInfoPhone. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 49d259b..d4eba1d 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -1195,6 +1195,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get contactProfileActionCall => 'Call'; + @override + String get contactProfileActionAddContact => 'Add to contacts'; + @override String get contactProfileInfoPhone => 'Phone'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index be0dead..a207683 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -1200,6 +1200,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get contactProfileActionCall => 'Звонок'; + @override + String get contactProfileActionAddContact => 'Добавить в контакты'; + @override String get contactProfileInfoPhone => 'Телефон'; diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 61a9775..a94a85a 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -398,6 +398,7 @@ "contactProfileActionChat": "Чат", "contactProfileActionSound": "Звук", "contactProfileActionCall": "Звонок", + "contactProfileActionAddContact": "Добавить в контакты", "contactProfileInfoPhone": "Телефон", "contactProfileInfoCountry": "Страна", "contactProfileInfoGender": "Пол",