Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 30 additions & 19 deletions .github/workflows/create_release_from_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@ jobs:
channel: stable
version: 3.35.7

- name: Install dependencies
- name: Install flutter dependencies
run: flutter pub get

- name: Build Windows package
run: flutter build windows
- name: Flutter Build Windows
run: flutter build windows --release

- name: Zip Windows build for release
- name: Zip Windows build
# Compress the entire Release folder into a single zip for attaching to the GitHub Release.
run: |
Compress-Archive -Path (Get-ChildItem -Path 'build/windows/x64/runner/Release' -Recurse | ForEach-Object FullName) -DestinationPath 'windows-build.zip' -Force
Compress-Archive -Path (Get-ChildItem -Path 'build/windows/x64/runner/Release' -Recurse | ForEach-Object FullName) -DestinationPath 'recon-windows.zip' -Force
shell: powershell

- name: Upload Windows artifact
uses: actions/upload-artifact@v4
with:
name: windows-build
path: windows-build.zip
name: recon-windows
path: recon-windows.zip

build_linux_appimage:
name: Build Linux (AppImage)
Expand Down Expand Up @@ -82,7 +82,7 @@ jobs:
- name: Install flutter dependencies
run: flutter pub get

- name: Build Linux binary
- name: Flutter Build Linux
run: flutter build linux --release

- name: Prepare for AppImage build
Expand All @@ -100,8 +100,8 @@ jobs:
- name: Upload Linux AppImage artifact
uses: actions/upload-artifact@v4
with:
name: ReCon-latest-x86_64.AppImage
path: ReCon-latest-x86_64.AppImage
name: recon-linux.AppImage
path: recon-linux.AppImage

build_android:
name: Build Android
Expand Down Expand Up @@ -132,13 +132,13 @@ jobs:
run: |
flutter build apk --release
cd ../build/app/outputs/flutter-apk
mv app-release.apk recon-build.apk
mv app-release.apk recon-android.apk

- name: Upload Android artifact
uses: actions/upload-artifact@v4
with:
name: recon-build
path: build/app/outputs/flutter-apk/recon-build.apk
name: recon-android
path: build/app/outputs/flutter-apk/recon-android.apk

release:
name: Create Release and attach artifacts
Expand All @@ -159,7 +159,7 @@ jobs:
run: |
VERSION=$(grep '^version: ' pubspec.yaml | sed 's/version: //')
echo "Project version: $VERSION"
echo "::set-output name=version::$VERSION"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

- name: Create release
id: create_release
Expand All @@ -174,14 +174,14 @@ jobs:
prerelease: false

- name: Upload Windows Build to Release
id: upload-release-asset
id: upload-release-asset-windows
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: release_artifacts/windows-build/windows-build.zip
asset_name: ReConRunner-Windows-${{ steps.get_version.outputs.version }}.zip
asset_path: release_artifacts/recon-windows/recon-windows.zip
asset_name: ReCon-Windows-${{ steps.get_version.outputs.version }}.zip
asset_content_type: application/zip

- name: Upload Android APK to Release
Expand All @@ -191,6 +191,17 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: release_artifacts/recon-build/recon-build.apk
asset_name: ReConRunner-Android-${{ steps.get_version.outputs.version }}.apk
asset_path: release_artifacts/recon-android/recon-android.apk
asset_name: ReCon-Android-${{ steps.get_version.outputs.version }}.apk
asset_content_type: application/vnd.android.package-archive

- name: Upload Linux AppImage to Release
id: upload-release-asset-linux
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: release_artifacts/recon-linux/recon-linux.AppImage
asset_name: ReCon-Linux-${{ steps.get_version.outputs.version }}.AppImage
asset_content_type: application/x-executable
1 change: 0 additions & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ linter:
- prefer_void_to_null
- unnecessary_statements
- always_declare_return_types
- avoid_annotating_with_dynamic
- avoid_bool_literals_in_conditional_expressions
- avoid_escaping_inner_quotes
- avoid_field_initializers_in_const_classes
Expand Down
26 changes: 1 addition & 25 deletions lib/apis/contact_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ 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/user.dart';
import 'package:recon/models/users/user_profile.dart';
import 'package:recon/models/users/user_status.dart';

class ContactApi {
static Future<List<Friend>> getFriendsList(ApiClient client, {DateTime? lastStatusUpdate}) async {
Expand All @@ -14,24 +10,4 @@ class ContactApi {
final data = jsonDecode(response.body) as List;
return data.map((e) => Friend.fromMap(e)).toList();
}

static Future<void> addUserAsFriend(ApiClient client, {required User user}) async {
final friend = Friend(
id: user.id,
username: user.username,
ownerId: client.userId,
userStatus: UserStatus.empty(),
userProfile: UserProfile.empty(),
contactStatus: FriendStatus.accepted,
latestMessageTime: DateTime.now(),
);
final body = jsonEncode(friend.toMap(shallow: true));
final response = await client.put("/users/${client.userId}/contacts/${user.id}", body: body);
client.checkResponse(response);
}

static Future<void> removeUserAsFriend(ApiClient client, {required User user}) async {
final response = await client.delete("/users/${client.userId}/friends/${user.id}");
client.checkResponse(response);
}
}
}
1 change: 0 additions & 1 deletion lib/clients/api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class ApiClient {
final AuthenticationData _authenticationData;
final Logger _logger = Logger("API");

// Saving the context here feels kinda cringe ngl
final _logoutNotifier = EventNotifier();
final http.Client _client = http.Client();

Expand Down
89 changes: 63 additions & 26 deletions lib/clients/messaging_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ 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/friend_status.dart';
import 'package:recon/models/users/online_status.dart';
import 'package:recon/models/users/user.dart';
import 'package:recon/models/users/user_status.dart';

class MessagingClient extends ChangeNotifier {
Expand Down Expand Up @@ -73,9 +75,9 @@ class MessagingClient extends ChangeNotifier {

List<Friend> get cachedFriends => _sortedFriendsCache;

List<Message> getUnreadsForFriend(Friend friend) => _unreads[friend.id] ?? [];
List<Message> getUnreadsForFriend(Friend friend) => _unreads[friend.contactUserId] ?? [];

bool friendHasUnreads(Friend friend) => _unreads.containsKey(friend.id);
bool friendHasUnreads(Friend friend) => _unreads.containsKey(friend.contactUserId);

bool messageIsUnread(Message message) => _unreads[message.senderId]?.any((element) => element.id == message.id) ?? false;

Expand All @@ -95,7 +97,7 @@ class MessagingClient extends ChangeNotifier {
}

Future<void> initFriendsList() async {
_hubManager.send(
_hubManager.send<Map>(
"InitializeStatus",
responseHandler: (data) async {
final rawContacts = data["contacts"] as List;
Expand Down Expand Up @@ -176,6 +178,39 @@ class MessagingClient extends ChangeNotifier {
notifyListeners();
}

Future<bool> addContact(User user) async {
return _hubUpdateContact(
Friend.empty().copyWith(
ownerId: _apiClient.userId,
contactUserId: user.id,
contactUsername: user.username,
contactStatus: ContactStatus.accepted,
),
);
}

Future<bool> removeContact(Friend friend) async {
return _hubUpdateContact(
friend.copyWith(
contactStatus: ContactStatus.ignored,
),
);
}

Future<bool> _hubUpdateContact(Friend friend) async {
final response = await _hubManager.sendAndWait<bool>(
"UpdateContact",
arguments: [
friend.toMap(),
],
) ??
false;
if (response) {
await _updateContact(friend);
}
return response;
}

void addUnread(Message message) {
var messages = _unreads[message.senderId];
if (messages == null) {
Expand Down Expand Up @@ -253,42 +288,44 @@ class MessagingClient extends ChangeNotifier {
}

void _sortFriendsCache() {
_sortedFriendsCache.sort((a, b) {
// Check for unreads and sort by latest message time if either has unreads
final aHasUnreads = friendHasUnreads(a);
final bHasUnreads = friendHasUnreads(b);
if (aHasUnreads || bHasUnreads) {
if (aHasUnreads && bHasUnreads) {
return -a.latestMessageTime.compareTo(b.latestMessageTime);
}
_sortedFriendsCache
..removeWhere((element) => element.contactStatus != ContactStatus.accepted)
..sort((a, b) {
// Check for unreads and sort by latest message time if either has unreads
final aHasUnreads = friendHasUnreads(a);
final bHasUnreads = friendHasUnreads(b);
if (aHasUnreads || bHasUnreads) {
if (aHasUnreads && bHasUnreads) {
return -a.latestMessageTime.compareTo(b.latestMessageTime);
}

return aHasUnreads ? -1 : 1;
}
return aHasUnreads ? -1 : 1;
}

final onlineStatusComparison = getOnlineStatusValue(a).compareTo(getOnlineStatusValue(b));
if (onlineStatusComparison != 0) {
return onlineStatusComparison;
}
final onlineStatusComparison = getOnlineStatusValue(a).compareTo(getOnlineStatusValue(b));
if (onlineStatusComparison != 0) {
return onlineStatusComparison;
}

return -a.latestMessageTime.compareTo(b.latestMessageTime);
});
return -a.latestMessageTime.compareTo(b.latestMessageTime);
});
}

Future<void> _updateContacts(List<Friend> friends) async {
final box = Hive.box(_messageBoxKey);
for (final friend in friends) {
await box.put(friend.id, friend.toMap());
await box.put(friend.contactUserId, friend.toMap());
final lastStatusUpdate = box.get(_lastUpdateKey);
if (lastStatusUpdate == null || friend.userStatus.lastStatusChange.isAfter(lastStatusUpdate)) {
await box.put(_lastUpdateKey, friend.userStatus.lastStatusChange);
}
final sIndex = _sortedFriendsCache.indexWhere((element) => element.id == friend.id);
final sIndex = _sortedFriendsCache.indexWhere((element) => element.contactUserId == friend.contactUserId);
if (sIndex == -1) {
_sortedFriendsCache.add(friend);
} else {
_sortedFriendsCache[sIndex] = friend;
}
if (friend.id == selectedFriend?.id) {
if (friend.contactUserId == selectedFriend?.contactUserId) {
selectedFriend = friend;
}
}
Expand All @@ -297,18 +334,18 @@ class MessagingClient extends ChangeNotifier {

Future<void> _updateContact(Friend friend) async {
final box = Hive.box(_messageBoxKey);
await box.put(friend.id, friend.toMap());
await box.put(friend.contactUserId, friend.toMap());
final lastStatusUpdate = box.get(_lastUpdateKey);
if (lastStatusUpdate == null || friend.userStatus.lastStatusChange.isAfter(lastStatusUpdate)) {
await box.put(_lastUpdateKey, friend.userStatus.lastStatusChange);
}
final sIndex = _sortedFriendsCache.indexWhere((element) => element.id == friend.id);
final sIndex = _sortedFriendsCache.indexWhere((element) => element.contactUserId == friend.contactUserId);
if (sIndex == -1) {
_sortedFriendsCache.add(friend);
} else {
_sortedFriendsCache[sIndex] = friend;
}
if (friend.id == selectedFriend?.id) {
if (friend.contactUserId == selectedFriend?.contactUserId) {
selectedFriend = friend;
}
_sortFriendsCache();
Expand Down Expand Up @@ -346,7 +383,7 @@ class MessagingClient extends ChangeNotifier {
final msg = args[0];
final message = Message.fromMap(msg);
(getUserMessageCache(message.senderId) ?? _createUserMessageCache(message.senderId)).addMessage(message);
if (message.senderId != selectedFriend?.id) {
if (message.senderId != selectedFriend?.contactUserId) {
addUnread(message);
requestUserStatus(message.senderId);
} else {
Expand Down
Loading
Loading