diff --git a/lib/apis/contact_api.dart b/lib/apis/contact_api.dart index 1cd6517..b4cc9fe 100644 --- a/lib/apis/contact_api.dart +++ b/lib/apis/contact_api.dart @@ -1,28 +1,28 @@ import 'dart:convert'; import 'package:recon/clients/api_client.dart'; -import 'package:recon/models/users/friend.dart'; -import 'package:recon/models/users/friend_status.dart'; +import 'package:recon/models/users/contact.dart'; +import 'package:recon/models/users/contact_status.dart'; import 'package:recon/models/users/user.dart'; import 'package:recon/models/users/user_profile.dart'; import 'package:recon/models/users/user_status.dart'; class ContactApi { - static Future> getFriendsList(ApiClient client, {DateTime? lastStatusUpdate}) async { + static Future> getFriendsList(ApiClient client, {DateTime? lastStatusUpdate}) async { final response = await client.get("/users/${client.userId}/contacts${lastStatusUpdate != null ? "?lastStatusUpdate=${lastStatusUpdate.toUtc().toIso8601String()}" : ""}"); client.checkResponse(response); final data = jsonDecode(response.body) as List; - return data.map((e) => Friend.fromMap(e)).toList(); + return data.map((e) => Contact.fromMap(e)).toList(); } static Future addUserAsFriend(ApiClient client, {required User user}) async { - final friend = Friend( + final friend = Contact( id: user.id, - username: user.username, + contactUsername: user.username, ownerId: client.userId, userStatus: UserStatus.empty(), userProfile: UserProfile.empty(), - contactStatus: FriendStatus.accepted, + friendStatus: ContactStatus.accepted, latestMessageTime: DateTime.now(), ); final body = jsonEncode(friend.toMap(shallow: true)); diff --git a/lib/clients/messaging_client.dart b/lib/clients/messaging_client.dart index fc54cdb..21fbd5f 100644 --- a/lib/clients/messaging_client.dart +++ b/lib/clients/messaging_client.dart @@ -12,8 +12,9 @@ import 'package:recon/hub_manager.dart'; import 'package:recon/models/hub_events.dart'; import 'package:recon/models/message.dart'; import 'package:recon/models/session.dart'; -import 'package:recon/models/users/friend.dart'; +import 'package:recon/models/users/contact.dart'; import 'package:recon/models/users/online_status.dart'; +import 'package:recon/models/users/user.dart'; import 'package:recon/models/users/user_status.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; @@ -21,7 +22,6 @@ import 'package:hive_flutter/hive_flutter.dart'; import 'package:logging/logging.dart'; import 'package:package_info_plus/package_info_plus.dart'; - class MessagingClient extends ChangeNotifier { static const Duration _autoRefreshDuration = Duration(seconds: 10); static const Duration _unreadSafeguardDuration = Duration(seconds: 120); @@ -30,7 +30,7 @@ class MessagingClient extends ChangeNotifier { static const String _lastUpdateKey = "__last-update-time"; final ApiClient _apiClient; - final List _sortedFriendsCache = []; // Keep a sorted copy so as to not have to sort during build() + final List _sortedFriendsCache = []; // Keep a sorted copy so as to not have to sort during build() final Map _messageCache = {}; final Map> _unreads = {}; final Logger _logger = Logger("Messaging"); @@ -39,7 +39,7 @@ class MessagingClient extends ChangeNotifier { final Map _sessionMap = {}; final Set _knownSessionKeys = {}; final SettingsClient _settingsClient; - Friend? selectedFriend; + Contact? selectedFriend; Timer? _statusHeartbeat; Timer? _autoRefresh; @@ -49,11 +49,13 @@ class MessagingClient extends ChangeNotifier { UserStatus get userStatus => _userStatus; - MessagingClient({required ApiClient apiClient, required NotificationClient notificationClient, required SettingsClient settingsClient}) + MessagingClient( + {required ApiClient apiClient, + required NotificationClient notificationClient, + required SettingsClient settingsClient}) : _apiClient = apiClient, _notificationClient = notificationClient, - _settingsClient = settingsClient - { + _settingsClient = settingsClient { debugPrint("mClient created: $hashCode"); Hive.openBox(_messageBoxKey).then((box) async { await box.delete(_lastUpdateKey); @@ -75,16 +77,16 @@ class MessagingClient extends ChangeNotifier { String? get initStatus => _initStatus; - List get cachedFriends => _sortedFriendsCache; + List get cachedFriends => _sortedFriendsCache; - List getUnreadsForFriend(Friend friend) => _unreads[friend.id] ?? []; + List getUnreadsForFriend(Contact friend) => _unreads[friend.id] ?? []; - bool friendHasUnreads(Friend friend) => _unreads.containsKey(friend.id); + bool friendHasUnreads(Contact friend) => _unreads.containsKey(friend.id); bool messageIsUnread(Message message) => _unreads[message.senderId]?.any((element) => element.id == message.id) ?? false; - Friend? getAsFriend(String userId) => Friend.fromMapOrNull(Hive.box(_messageBoxKey).get(userId)); + Contact? getAsFriend(String userId) => Contact.fromMapOrNull(Hive.box(_messageBoxKey).get(userId)); MessageCache? getUserMessageCache(String userId) => _messageCache[userId]; @@ -106,7 +108,7 @@ class MessagingClient extends ChangeNotifier { final friends = await ContactApi.getFriendsList(_apiClient, lastStatusUpdate: lastUpdateUtc); for (final friend in friends) { - await _updateContact(friend); + await _updateContactLocal(friend); } _initStatus = ""; @@ -153,7 +155,7 @@ class MessagingClient extends ChangeNotifier { final self = getAsFriend(_apiClient.userId); if (self != null) { - await _updateContact(self.copyWith(userStatus: _userStatus)); + await _updateContactLocal(self.copyWith(userStatus: _userStatus)); } notifyListeners(); } @@ -206,7 +208,7 @@ class MessagingClient extends ChangeNotifier { final friend = getAsFriend(userId); if (friend == null) return; final newStatus = await UserApi.getUserStatus(_apiClient, userId: userId); - await _updateContact(friend.copyWith(userStatus: newStatus)); + await _updateContactLocal(friend.copyWith(userStatus: newStatus)); notifyListeners(); } @@ -215,6 +217,10 @@ class MessagingClient extends ChangeNotifier { notifyListeners(); } + void addUserAsFriend(User user) { + _hubManager.send("UpdateContact", arguments: [user.asContactRequest(_apiClient.userId)]); + } + Future _refreshUnreads() async { try { final unreadMessages = await MessageApi.getUserMessages(_apiClient, unreadOnly: true); @@ -233,7 +239,7 @@ class MessagingClient extends ChangeNotifier { }); } - Future _updateContact(Friend friend) async { + Future _updateContactLocal(Contact friend) async { final box = Hive.box(_messageBoxKey); box.put(friend.id, friend.toMap()); final lastStatusUpdate = box.get(_lastUpdateKey); @@ -271,16 +277,17 @@ class MessagingClient extends ChangeNotifier { "InitializeStatus", responseHandler: (Map data) async { final rawContacts = data["contacts"] as List; - final contacts = rawContacts.map((e) => Friend.fromMap(e)).toList(); + final contacts = rawContacts.map((e) => Contact.fromMap(e)).toList(); for (final contact in contacts) { - await _updateContact(contact); + await _updateContactLocal(contact); } _initStatus = ""; notifyListeners(); await _refreshUnreads(); _unreadSafeguard = Timer.periodic(_unreadSafeguardDuration, (timer) => _refreshUnreads()); _hubManager.send("RequestStatus", arguments: [null, false]); - final lastOnline = OnlineStatus.values.elementAtOrNull(_settingsClient.currentSettings.lastOnlineStatus.valueOrDefault); + final lastOnline = + OnlineStatus.values.elementAtOrNull(_settingsClient.currentSettings.lastOnlineStatus.valueOrDefault); await setOnlineStatus(lastOnline ?? OnlineStatus.online); _statusHeartbeat = Timer.periodic(_statusHeartbeatDuration, (timer) { setOnlineStatus(_userStatus.onlineStatus); @@ -332,10 +339,12 @@ class MessagingClient extends ChangeNotifier { var status = UserStatus.fromMap(statusUpdate); final sessionMap = createSessionMap(status.hashSalt); status = status.copyWith( - decodedSessions: status.sessions.map((e) => sessionMap[e.sessionHash] ?? Session.none().copyWith(accessLevel: e.accessLevel)).toList()); + decodedSessions: status.sessions + .map((e) => sessionMap[e.sessionHash] ?? Session.none().copyWith(accessLevel: e.accessLevel)) + .toList()); final friend = getAsFriend(statusUpdate["userId"])?.copyWith(userStatus: status); if (friend != null) { - _updateContact(friend); + _updateContactLocal(friend); } for (var session in status.sessions) { if (session.broadcastKey != null && _knownSessionKeys.add(session.broadcastKey ?? "")) { diff --git a/lib/models/users/friend.dart b/lib/models/users/contact.dart similarity index 60% rename from lib/models/users/friend.dart rename to lib/models/users/contact.dart index 35a92e8..df020c4 100644 --- a/lib/models/users/friend.dart +++ b/lib/models/users/contact.dart @@ -1,70 +1,70 @@ import 'package:recon/auxiliary.dart'; import 'package:recon/models/users/user_profile.dart'; -import 'package:recon/models/users/friend_status.dart'; +import 'package:recon/models/users/contact_status.dart'; import 'package:recon/models/users/online_status.dart'; import 'package:recon/models/users/user_status.dart'; -class Friend implements Comparable { +class Contact implements Comparable { static const _emptyId = "-1"; static const _resoniteBotId = "U-Resonite"; final String id; - final String username; + final String contactUsername; final String ownerId; final UserStatus userStatus; final UserProfile userProfile; - final FriendStatus contactStatus; + final ContactStatus friendStatus; final DateTime latestMessageTime; - const Friend({required this.id, required this.username, required this.ownerId, required this.userStatus, required this.userProfile, - required this.contactStatus, required this.latestMessageTime, + const Contact({required this.id, required this.contactUsername, required this.ownerId, required this.userStatus, required this.userProfile, + required this.friendStatus, required this.latestMessageTime, }); bool get isHeadless => userStatus.outputDevice == "Headless"; - factory Friend.fromMap(Map map) { + factory Contact.fromMap(Map map) { var userStatus = map["userStatus"] == null ? UserStatus.empty() : UserStatus.fromMap(map["userStatus"]); - return Friend( + return Contact( id: map["id"], - username: map["contactUsername"], + contactUsername: map["contactUsername"], ownerId: map["ownerId"] ?? map["id"], // Neos bot status is always offline but should be displayed as online userStatus: map["id"] == _resoniteBotId ? userStatus.copyWith(onlineStatus: OnlineStatus.online) : userStatus, userProfile: UserProfile.fromMap(map["profile"] ?? {}), - contactStatus: FriendStatus.fromString(map["contactStatus"]), + friendStatus: ContactStatus.fromString(map["contactStatus"]), latestMessageTime: map["latestMessageTime"] == null ? DateTime.fromMillisecondsSinceEpoch(0) : DateTime.parse(map["latestMessageTime"]), ); } - static Friend? fromMapOrNull(Map? map) { + static Contact? fromMapOrNull(Map? map) { if (map == null) return null; - return Friend.fromMap(map); + return Contact.fromMap(map); } - factory Friend.empty() { - return Friend( + factory Contact.empty() { + return Contact( id: _emptyId, - username: "", + contactUsername: "", ownerId: "", userStatus: UserStatus.empty(), userProfile: UserProfile.empty(), - contactStatus: FriendStatus.none, + friendStatus: ContactStatus.none, latestMessageTime: DateTimeX.epoch ); } bool get isEmpty => id == _emptyId; - Friend copyWith({ - String? id, String? username, String? ownerId, UserStatus? userStatus, UserProfile? userProfile, - FriendStatus? contactStatus, DateTime? latestMessageTime}) { - return Friend( + Contact copyWith({ + String? id, String? contactUsername, String? ownerId, UserStatus? userStatus, UserProfile? userProfile, + ContactStatus? friendStatus, DateTime? latestMessageTime}) { + return Contact( id: id ?? this.id, - username: username ?? this.username, + contactUsername: contactUsername ?? this.contactUsername, ownerId: ownerId ?? this.ownerId, userStatus: userStatus ?? this.userStatus, userProfile: userProfile ?? this.userProfile, - contactStatus: contactStatus ?? this.contactStatus, + friendStatus: friendStatus ?? this.friendStatus, latestMessageTime: latestMessageTime ?? this.latestMessageTime, ); } @@ -72,17 +72,17 @@ class Friend implements Comparable { Map toMap({bool shallow=false}) { return { "id": id, - "contactUsername": username, + "contactUsername": contactUsername, "ownerId": ownerId, "userStatus": userStatus.toMap(shallow: shallow), "profile": userProfile.toMap(), - "contactStatus": contactStatus.name, + "contactStatus": friendStatus.name, "latestMessageTime": latestMessageTime.toIso8601String(), }; } @override - int compareTo(covariant Friend other) { - return username.compareTo(other.username); + int compareTo(covariant Contact other) { + return contactUsername.compareTo(other.contactUsername); } } diff --git a/lib/models/users/contact_status.dart b/lib/models/users/contact_status.dart new file mode 100644 index 0000000..57bfe28 --- /dev/null +++ b/lib/models/users/contact_status.dart @@ -0,0 +1,14 @@ +enum ContactStatus { + none, + searchResult, + requested, + ignored, + blocked, + accepted; + + factory ContactStatus.fromString(String text) { + return ContactStatus.values.firstWhere((element) => element.name.toLowerCase() == text.toLowerCase(), + orElse: () => ContactStatus.none, + ); + } +} diff --git a/lib/models/users/friend_status.dart b/lib/models/users/friend_status.dart deleted file mode 100644 index 1177b2d..0000000 --- a/lib/models/users/friend_status.dart +++ /dev/null @@ -1,14 +0,0 @@ -enum FriendStatus { - none, - searchResult, - requested, - ignored, - blocked, - accepted; - - factory FriendStatus.fromString(String text) { - return FriendStatus.values.firstWhere((element) => element.name.toLowerCase() == text.toLowerCase(), - orElse: () => FriendStatus.none, - ); - } -} diff --git a/lib/models/users/user.dart b/lib/models/users/user.dart index 91ca1d1..b1e0b7b 100644 --- a/lib/models/users/user.dart +++ b/lib/models/users/user.dart @@ -1,3 +1,4 @@ +import 'package:recon/models/users/contact_status.dart'; import 'package:recon/models/users/user_profile.dart'; class User { @@ -31,4 +32,13 @@ class User { "profile": userProfile?.toMap(), }; } + + Map asContactRequest(String ownerId) { + return { + "ownerId": ownerId, + "id": id, + "contactUsername": username, + "contactStatus": ContactStatus.accepted.name, + }; + } } \ No newline at end of file diff --git a/lib/widgets/friends/friend_list_tile.dart b/lib/widgets/friends/friend_list_tile.dart index 87a748d..a2a7d34 100644 --- a/lib/widgets/friends/friend_list_tile.dart +++ b/lib/widgets/friends/friend_list_tile.dart @@ -4,7 +4,7 @@ import 'package:provider/provider.dart'; import 'package:recon/auxiliary.dart'; import 'package:recon/clients/messaging_client.dart'; import 'package:recon/models/message.dart'; -import 'package:recon/models/users/friend.dart'; +import 'package:recon/models/users/contact.dart'; import 'package:recon/models/users/online_status.dart'; import 'package:recon/widgets/formatted_text.dart'; import 'package:recon/widgets/friends/friend_online_status_indicator.dart'; @@ -14,7 +14,7 @@ import 'package:recon/widgets/messages/messages_list.dart'; class FriendListTile extends StatelessWidget { const FriendListTile({required this.friend, required this.unreads, this.onTap, super.key}); - final Friend friend; + final Contact friend; final int unreads; final Function? onTap; @@ -38,7 +38,7 @@ class FriendListTile extends StatelessWidget { : null, title: Row( children: [ - Text(friend.username), + Text(friend.contactUsername), if (friend.isHeadless) Padding( padding: const EdgeInsets.only(left: 8), diff --git a/lib/widgets/friends/friends_list.dart b/lib/widgets/friends/friends_list.dart index 3fd2430..c162c36 100644 --- a/lib/widgets/friends/friends_list.dart +++ b/lib/widgets/friends/friends_list.dart @@ -45,9 +45,9 @@ class _FriendsListState extends State with AutomaticKeepAliveClient var friends = List.from(mClient.cachedFriends); // Explicit copy. if (_searchFilter.isNotEmpty) { friends = friends - .where((element) => element.username.toLowerCase().contains(_searchFilter.toLowerCase())) + .where((element) => element.contactUsername.toLowerCase().contains(_searchFilter.toLowerCase())) .toList(); - friends.sort((a, b) => a.username.length.compareTo(b.username.length)); + friends.sort((a, b) => a.contactUsername.length.compareTo(b.contactUsername.length)); } return ListView.builder( physics: const BouncingScrollPhysics(decelerationRate: ScrollDecelerationRate.fast), diff --git a/lib/widgets/friends/user_list_tile.dart b/lib/widgets/friends/user_list_tile.dart index 2cd3999..0d6b01d 100644 --- a/lib/widgets/friends/user_list_tile.dart +++ b/lib/widgets/friends/user_list_tile.dart @@ -1,13 +1,20 @@ +import 'package:provider/provider.dart'; import 'package:recon/apis/contact_api.dart'; import 'package:recon/auxiliary.dart'; import 'package:recon/client_holder.dart'; +import 'package:recon/clients/messaging_client.dart'; import 'package:recon/models/users/user.dart'; import 'package:recon/widgets/generic_avatar.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; class UserListTile extends StatefulWidget { - const UserListTile({required this.user, required this.isFriend, required this.onChanged, super.key}); + const UserListTile({ + required this.user, + required this.isFriend, + required this.onChanged, + super.key, + }); final User user; final bool isFriend; @@ -24,24 +31,20 @@ class _UserListTileState extends State { @override Widget build(BuildContext context) { - final colorScheme = Theme - .of(context) - .colorScheme; - final style = _localAdded ? IconButton.styleFrom( - foregroundColor: colorScheme.onBackground, - side: BorderSide( - color: colorScheme.error, - width: 2 - ), - ) : IconButton.styleFrom( - foregroundColor: colorScheme.onBackground, - side: BorderSide( - color: colorScheme.primary, - width: 2 - ), - ); + final colorScheme = Theme.of(context).colorScheme; + final style = _localAdded + ? IconButton.styleFrom( + foregroundColor: colorScheme.onBackground, + side: BorderSide(color: colorScheme.error, width: 2), + ) + : IconButton.styleFrom( + foregroundColor: colorScheme.onBackground, + side: BorderSide(color: colorScheme.primary, width: 2), + ); return ListTile( - leading: GenericAvatar(imageUri: Aux.resdbToHttp(widget.user.userProfile?.iconUrl),), + leading: GenericAvatar( + imageUri: Aux.resdbToHttp(widget.user.userProfile?.iconUrl), + ), title: Text(widget.user.username), subtitle: Text(_regDateFormat.format(widget.user.registrationDate)), trailing: IconButton( @@ -49,48 +52,48 @@ class _UserListTileState extends State { iconSize: 20, icon: _localAdded ? const Icon(Icons.person_remove) : const Icon(Icons.person_add), style: style, - onPressed: _loading ? null : () async { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Sorry, this feature is not yet available"))); - return; - setState(() { - _loading = true; - }); - try { - if (_localAdded) { - await ContactApi.removeUserAsFriend(ClientHolder - .of(context) - .apiClient, user: widget.user); - } else { - await ContactApi.addUserAsFriend(ClientHolder - .of(context) - .apiClient, user: widget.user); - } - setState(() { - _loading = false; - _localAdded = !_localAdded; - }); - widget.onChanged?.call(); - } catch (e, s) { - FlutterError.reportError(FlutterErrorDetails(exception: e, stack: s)); - if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - duration: const Duration(seconds: 5), - content: Text( - "Something went wrong: $e", - softWrap: true, - maxLines: null, - ), - ), - ); - } - setState(() { - _loading = false; - }); - return; - } - }, + onPressed: _loading + ? null + : () async { + final mClient = Provider.of(context, listen: false); + setState(() { + _loading = true; + }); + try { + if (_localAdded) { + await ContactApi.removeUserAsFriend( + ClientHolder.of(context).apiClient, + user: widget.user, + ); + } else { + mClient.addUserAsFriend(widget.user); + } + setState(() { + _loading = false; + _localAdded = !_localAdded; + }); + widget.onChanged?.call(); + } catch (e, s) { + FlutterError.reportError(FlutterErrorDetails(exception: e, stack: s)); + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + duration: const Duration(seconds: 5), + content: Text( + "Something went wrong: $e", + softWrap: true, + maxLines: null, + ), + ), + ); + } + setState(() { + _loading = false; + }); + return; + } + }, ), ); } -} \ No newline at end of file +} diff --git a/lib/widgets/friends/user_search.dart b/lib/widgets/friends/user_search.dart index fa36fe2..f694272 100644 --- a/lib/widgets/friends/user_search.dart +++ b/lib/widgets/friends/user_search.dart @@ -29,24 +29,19 @@ class _UserSearchState extends State { late Future?>? _usersFuture = _emptySearch; Future> get _emptySearch => - Future(() => - throw const SearchError( - message: "Start typing to search for users", icon: Icons.search) - ); + Future(() => throw const SearchError(message: "Start typing to search for users", icon: Icons.search)); void _querySearch(BuildContext context, String needle) { if (needle.isEmpty) { _usersFuture = _emptySearch; return; } - _usersFuture = UserApi.searchUsers(ClientHolder - .of(context) - .apiClient, needle: needle).then((value) { + _usersFuture = UserApi.searchUsers(ClientHolder.of(context).apiClient, needle: needle).then((value) { final res = value.toList(); - if (res.isEmpty) throw SearchError(message: "No user found with username '$needle'", icon: Icons.search_off); - res.sort( - (a, b) => a.username.length.compareTo(b.username.length) - ); + if (res.isEmpty) { + throw SearchError(message: "No user found with username '$needle'", icon: Icons.search_off); + } + res.sort((a, b) => a.username.length.compareTo(b.username.length)); return res; }); } @@ -72,9 +67,13 @@ class _UserSearchState extends State { itemCount: users.length, itemBuilder: (context, index) { final user = users[index]; - return UserListTile(user: user, onChanged: () { - mClient.refreshFriendsList(); - }, isFriend: mClient.getAsFriend(user.id) != null,); + return UserListTile( + user: user, + onChanged: () { + mClient.refreshFriendsList(); + }, + isFriend: mClient.getAsFriend(user.id) != null, + ); }, ); } else if (snapshot.hasError) { @@ -85,9 +84,13 @@ class _UserSearchState extends State { iconOverride: err.icon, ); } else { - FlutterError.reportError( - FlutterErrorDetails(exception: snapshot.error!, stack: snapshot.stackTrace)); - return DefaultErrorWidget(title: "${snapshot.error}",); + FlutterError.reportError(FlutterErrorDetails( + exception: snapshot.error!, + stack: snapshot.stackTrace, + )); + return DefaultErrorWidget( + title: "${snapshot.error}", + ); } } else { return const Column( @@ -106,10 +109,7 @@ class _UserSearchState extends State { isDense: true, hintText: "Search for users...", contentPadding: const EdgeInsets.all(16), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(24) - ) - ), + border: OutlineInputBorder(borderRadius: BorderRadius.circular(24))), autocorrect: false, controller: _searchInputController, onChanged: (String value) { @@ -136,4 +136,4 @@ class _UserSearchState extends State { ), ); } -} \ No newline at end of file +} diff --git a/lib/widgets/messages/message_input_bar.dart b/lib/widgets/messages/message_input_bar.dart index ebe1a35..41f55eb 100644 --- a/lib/widgets/messages/message_input_bar.dart +++ b/lib/widgets/messages/message_input_bar.dart @@ -13,7 +13,7 @@ import 'package:recon/client_holder.dart'; import 'package:recon/clients/api_client.dart'; import 'package:recon/clients/messaging_client.dart'; import 'package:recon/models/message.dart'; -import 'package:recon/models/users/friend.dart'; +import 'package:recon/models/users/contact.dart'; import 'package:recon/widgets/messages/message_attachment_list.dart'; import 'package:record/record.dart'; @@ -21,7 +21,7 @@ class MessageInputBar extends StatefulWidget { const MessageInputBar({this.disabled = false, required this.recipient, this.onMessageSent, super.key}); final bool disabled; - final Friend recipient; + final Contact recipient; final Function()? onMessageSent; @override @@ -403,7 +403,7 @@ class _MessageInputBarState extends State { style: Theme.of(context).textTheme.bodyLarge, decoration: InputDecoration( isDense: true, - hintText: _isRecording ? "" : "Message ${widget.recipient.username}...", + hintText: _isRecording ? "" : "Message ${widget.recipient.contactUsername}...", hintMaxLines: 1, contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), fillColor: Colors.black26, diff --git a/lib/widgets/messages/messages_list.dart b/lib/widgets/messages/messages_list.dart index a3311c8..f37d6ea 100644 --- a/lib/widgets/messages/messages_list.dart +++ b/lib/widgets/messages/messages_list.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:recon/clients/audio_cache_client.dart'; import 'package:recon/clients/messaging_client.dart'; -import 'package:recon/models/users/friend.dart'; +import 'package:recon/models/users/contact.dart'; import 'package:recon/widgets/default_error_widget.dart'; import 'package:recon/widgets/friends/friend_online_status_indicator.dart'; import 'package:recon/widgets/messages/message_input_bar.dart'; @@ -54,7 +54,7 @@ class _MessagesListState extends State with SingleTickerProviderSt Widget build(BuildContext context) { final appBarColor = Theme.of(context).colorScheme.surface; return Consumer(builder: (context, mClient, _) { - final friend = mClient.selectedFriend ?? Friend.empty(); + final friend = mClient.selectedFriend ?? Contact.empty(); final cache = mClient.getUserMessageCache(friend.id); final sessions = friend.userStatus.decodedSessions.where((element) => element.isVisible).toList(); return Scaffold( @@ -66,7 +66,7 @@ class _MessagesListState extends State with SingleTickerProviderSt const SizedBox( width: 8, ), - Text(friend.username), + Text(friend.contactUsername), if (friend.isHeadless) Padding( padding: const EdgeInsets.only(left: 12), diff --git a/pubspec.yaml b/pubspec.yaml index 88b7998..82ccde5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 0.11.0-beta+1 +version: 0.11.1-beta+1 environment: sdk: ">=3.0.1" diff --git a/windows/installer-script.nsi b/windows/installer-script.nsi new file mode 100644 index 0000000..9cafcbc --- /dev/null +++ b/windows/installer-script.nsi @@ -0,0 +1,16 @@ +OutFile "ReCon-Installer.exe" + +# define the directory to install to, the desktop in this case as specified +# by the predefined $DESKTOP variable +InstallDir $DESKTOP + +# default section +Section + +# define the output path for this file +SetOutPath $INSTDIR + +# define what to install and place it in the output path +File test.txt + +SectionEnd \ No newline at end of file diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp index d97c34f..b710c33 100644 --- a/windows/runner/main.cpp +++ b/windows/runner/main.cpp @@ -26,8 +26,8 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); - Win32Window::Size size(1280, 720); - if (!window.Create(L"recon", origin, size)) { + Win32Window::Size size(480, 900); + if (!window.Create(L"ReCon", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico index c04e20c..a65eba9 100644 Binary files a/windows/runner/resources/app_icon.ico and b/windows/runner/resources/app_icon.ico differ