parent
023ed9edc1
commit
fcd34d4fb1
9 changed files with 41 additions and 16 deletions
|
@ -31,6 +31,13 @@ class RecordApi {
|
||||||
return body.map((e) => Record.fromMap(e)).toList();
|
return body.map((e) => Record.fromMap(e)).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<List<Record>> getGroupRecordsAt(ApiClient client, {required String path, required String groupId}) async {
|
||||||
|
final response = await client.get("/users/$groupId/records?path=$path");
|
||||||
|
client.checkResponse(response);
|
||||||
|
final body = jsonDecode(response.body) as List;
|
||||||
|
return body.map((e) => Record.fromMap(e)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
static Future<void> deleteRecord(ApiClient client, {required String recordId}) async {
|
static Future<void> deleteRecord(ApiClient client, {required String recordId}) async {
|
||||||
final response = await client.delete("/users/${client.userId}/records/$recordId");
|
final response = await client.delete("/users/${client.userId}/records/$recordId");
|
||||||
client.checkResponse(response);
|
client.checkResponse(response);
|
||||||
|
|
|
@ -24,6 +24,7 @@ import 'package:package_info_plus/package_info_plus.dart';
|
||||||
class MessagingClient extends ChangeNotifier {
|
class MessagingClient extends ChangeNotifier {
|
||||||
static const Duration _autoRefreshDuration = Duration(seconds: 10);
|
static const Duration _autoRefreshDuration = Duration(seconds: 10);
|
||||||
static const Duration _unreadSafeguardDuration = Duration(seconds: 120);
|
static const Duration _unreadSafeguardDuration = Duration(seconds: 120);
|
||||||
|
static const Duration _statusHeartbeatDuration = Duration(seconds: 150);
|
||||||
static const String _messageBoxKey = "message-box";
|
static const String _messageBoxKey = "message-box";
|
||||||
static const String _lastUpdateKey = "__last-update-time";
|
static const String _lastUpdateKey = "__last-update-time";
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ class MessagingClient extends ChangeNotifier {
|
||||||
final Set<String> _knownSessionKeys = {};
|
final Set<String> _knownSessionKeys = {};
|
||||||
Friend? selectedFriend;
|
Friend? selectedFriend;
|
||||||
|
|
||||||
Timer? _notifyOnlineTimer;
|
Timer? _statusHeartbeat;
|
||||||
Timer? _autoRefresh;
|
Timer? _autoRefresh;
|
||||||
Timer? _unreadSafeguard;
|
Timer? _unreadSafeguard;
|
||||||
String? _initStatus;
|
String? _initStatus;
|
||||||
|
@ -62,7 +63,7 @@ class MessagingClient extends ChangeNotifier {
|
||||||
void dispose() {
|
void dispose() {
|
||||||
debugPrint("mClient disposed: $hashCode");
|
debugPrint("mClient disposed: $hashCode");
|
||||||
_autoRefresh?.cancel();
|
_autoRefresh?.cancel();
|
||||||
_notifyOnlineTimer?.cancel();
|
_statusHeartbeat?.cancel();
|
||||||
_unreadSafeguard?.cancel();
|
_unreadSafeguard?.cancel();
|
||||||
_hubManager.dispose();
|
_hubManager.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
@ -117,6 +118,7 @@ class MessagingClient extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
void markMessagesRead(MarkReadBatch batch) {
|
void markMessagesRead(MarkReadBatch batch) {
|
||||||
|
if (_userStatus.onlineStatus == OnlineStatus.invisible || _userStatus.onlineStatus == OnlineStatus.offline) return;
|
||||||
final msgBody = batch.toMap();
|
final msgBody = batch.toMap();
|
||||||
_hubManager.send("MarkMessagesRead", arguments: [msgBody]);
|
_hubManager.send("MarkMessagesRead", arguments: [msgBody]);
|
||||||
clearUnreadsForUser(batch.senderId);
|
clearUnreadsForUser(batch.senderId);
|
||||||
|
@ -124,11 +126,14 @@ class MessagingClient extends ChangeNotifier {
|
||||||
|
|
||||||
Future<void> setOnlineStatus(OnlineStatus status) async {
|
Future<void> setOnlineStatus(OnlineStatus status) async {
|
||||||
final pkginfo = await PackageInfo.fromPlatform();
|
final pkginfo = await PackageInfo.fromPlatform();
|
||||||
|
final now = DateTime.now();
|
||||||
_userStatus = _userStatus.copyWith(
|
_userStatus = _userStatus.copyWith(
|
||||||
|
userId: _apiClient.userId,
|
||||||
appVersion: "${pkginfo.version} of ${pkginfo.appName}",
|
appVersion: "${pkginfo.version} of ${pkginfo.appName}",
|
||||||
lastStatusChange: DateTime.now(),
|
lastPresenceTimestamp: now,
|
||||||
|
lastStatusChange: now,
|
||||||
onlineStatus: status,
|
onlineStatus: status,
|
||||||
|
isPresent: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
_hubManager.send(
|
_hubManager.send(
|
||||||
|
@ -258,7 +263,6 @@ class MessagingClient extends ChangeNotifier {
|
||||||
_hubManager.setHandler(EventTarget.removeSession, _onRemoveSession);
|
_hubManager.setHandler(EventTarget.removeSession, _onRemoveSession);
|
||||||
|
|
||||||
await _hubManager.start();
|
await _hubManager.start();
|
||||||
await setOnlineStatus(OnlineStatus.online);
|
|
||||||
_hubManager.send(
|
_hubManager.send(
|
||||||
"InitializeStatus",
|
"InitializeStatus",
|
||||||
responseHandler: (Map data) async {
|
responseHandler: (Map data) async {
|
||||||
|
@ -272,6 +276,10 @@ class MessagingClient extends ChangeNotifier {
|
||||||
await _refreshUnreads();
|
await _refreshUnreads();
|
||||||
_unreadSafeguard = Timer.periodic(_unreadSafeguardDuration, (timer) => _refreshUnreads());
|
_unreadSafeguard = Timer.periodic(_unreadSafeguardDuration, (timer) => _refreshUnreads());
|
||||||
_hubManager.send("RequestStatus", arguments: [null, false]);
|
_hubManager.send("RequestStatus", arguments: [null, false]);
|
||||||
|
await setOnlineStatus(OnlineStatus.online);
|
||||||
|
_statusHeartbeat = Timer.periodic(_statusHeartbeatDuration, (timer) {
|
||||||
|
setOnlineStatus(_userStatus.onlineStatus);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,10 +107,10 @@ class HubManager {
|
||||||
void _handleInvocation(body) async {
|
void _handleInvocation(body) async {
|
||||||
final target = EventTarget.parse(body["target"]);
|
final target = EventTarget.parse(body["target"]);
|
||||||
final args = body["arguments"] ?? [];
|
final args = body["arguments"] ?? [];
|
||||||
if (kDebugMode) _logger.info("Invocation target: ${target.name}, args:\n$args");
|
|
||||||
final handler = _handlers[target];
|
final handler = _handlers[target];
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
_logger.info("Unhandled event received");
|
_logger.warning("Unhandled event received");
|
||||||
|
if (kDebugMode) _logger.warning("Invocation target: ${target.name}, args:\n$args");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handler(args);
|
handler(args);
|
||||||
|
|
|
@ -36,7 +36,6 @@ class AuthenticationData {
|
||||||
|
|
||||||
Map<String, String> get authorizationHeader => {
|
Map<String, String> get authorizationHeader => {
|
||||||
"Authorization": "res $userId:$token",
|
"Authorization": "res $userId:$token",
|
||||||
"UID": uid,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Map<String, dynamic> toMap() {
|
Map<String, dynamic> toMap() {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:recon/config.dart';
|
||||||
import 'package:recon/crypto_helper.dart';
|
import 'package:recon/crypto_helper.dart';
|
||||||
import 'package:recon/models/session.dart';
|
import 'package:recon/models/session.dart';
|
||||||
import 'package:recon/models/session_metadata.dart';
|
import 'package:recon/models/session_metadata.dart';
|
||||||
|
@ -10,7 +12,7 @@ enum UserSessionType
|
||||||
graphicalClient,
|
graphicalClient,
|
||||||
chatClient,
|
chatClient,
|
||||||
headless,
|
headless,
|
||||||
not;
|
bot;
|
||||||
|
|
||||||
factory UserSessionType.fromString(String? text) {
|
factory UserSessionType.fromString(String? text) {
|
||||||
return UserSessionType.values.firstWhere((element) => element.name.toLowerCase() == text?.toLowerCase(),
|
return UserSessionType.values.firstWhere((element) => element.name.toLowerCase() == text?.toLowerCase(),
|
||||||
|
@ -20,6 +22,7 @@ enum UserSessionType
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserStatus {
|
class UserStatus {
|
||||||
|
final String userId;
|
||||||
final OnlineStatus onlineStatus;
|
final OnlineStatus onlineStatus;
|
||||||
final DateTime lastStatusChange;
|
final DateTime lastStatusChange;
|
||||||
final DateTime lastPresenceTimestamp;
|
final DateTime lastPresenceTimestamp;
|
||||||
|
@ -36,6 +39,7 @@ class UserStatus {
|
||||||
final List<Session> decodedSessions;
|
final List<Session> decodedSessions;
|
||||||
|
|
||||||
const UserStatus({
|
const UserStatus({
|
||||||
|
required this.userId,
|
||||||
required this.onlineStatus,
|
required this.onlineStatus,
|
||||||
required this.lastStatusChange,
|
required this.lastStatusChange,
|
||||||
required this.lastPresenceTimestamp,
|
required this.lastPresenceTimestamp,
|
||||||
|
@ -54,15 +58,18 @@ class UserStatus {
|
||||||
|
|
||||||
factory UserStatus.initial() =>
|
factory UserStatus.initial() =>
|
||||||
UserStatus.empty().copyWith(
|
UserStatus.empty().copyWith(
|
||||||
|
compatibilityHash: Config.latestCompatHash,
|
||||||
onlineStatus: OnlineStatus.online,
|
onlineStatus: OnlineStatus.online,
|
||||||
hashSalt: CryptoHelper.cryptoToken(),
|
hashSalt: CryptoHelper.cryptoToken(),
|
||||||
outputDevice: "Screen",
|
outputDevice: "Unknown",
|
||||||
userSessionId: const Uuid().v4().toString(),
|
userSessionId: const Uuid().v4().toString(),
|
||||||
sessionType: UserSessionType.chatClient,
|
sessionType: UserSessionType.chatClient,
|
||||||
|
isPresent: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
factory UserStatus.empty() =>
|
factory UserStatus.empty() =>
|
||||||
UserStatus(
|
UserStatus(
|
||||||
|
userId: "",
|
||||||
onlineStatus: OnlineStatus.offline,
|
onlineStatus: OnlineStatus.offline,
|
||||||
lastStatusChange: DateTime.now(),
|
lastStatusChange: DateTime.now(),
|
||||||
lastPresenceTimestamp: DateTime.now(),
|
lastPresenceTimestamp: DateTime.now(),
|
||||||
|
@ -82,6 +89,7 @@ class UserStatus {
|
||||||
final statusString = map["onlineStatus"].toString();
|
final statusString = map["onlineStatus"].toString();
|
||||||
final status = OnlineStatus.fromString(statusString);
|
final status = OnlineStatus.fromString(statusString);
|
||||||
return UserStatus(
|
return UserStatus(
|
||||||
|
userId: map["userId"] ?? "",
|
||||||
onlineStatus: status,
|
onlineStatus: status,
|
||||||
lastStatusChange: DateTime.tryParse(map["lastStatusChange"] ?? "") ?? DateTime.now(),
|
lastStatusChange: DateTime.tryParse(map["lastStatusChange"] ?? "") ?? DateTime.now(),
|
||||||
lastPresenceTimestamp: DateTime.tryParse(map["lastPresenceTimestamp"] ?? "") ?? DateTime.now(),
|
lastPresenceTimestamp: DateTime.tryParse(map["lastPresenceTimestamp"] ?? "") ?? DateTime.now(),
|
||||||
|
@ -92,7 +100,7 @@ class UserStatus {
|
||||||
appVersion: map["appVersion"] ?? "",
|
appVersion: map["appVersion"] ?? "",
|
||||||
outputDevice: map["outputDevice"] ?? "Unknown",
|
outputDevice: map["outputDevice"] ?? "Unknown",
|
||||||
isMobile: map["isMobile"] ?? false,
|
isMobile: map["isMobile"] ?? false,
|
||||||
compatibilityHash: map["compatabilityHash"] ?? "",
|
compatibilityHash: map["compatibilityHash"] ?? "",
|
||||||
hashSalt: map["hashSalt"] ?? "",
|
hashSalt: map["hashSalt"] ?? "",
|
||||||
sessionType: UserSessionType.fromString(map["sessionType"])
|
sessionType: UserSessionType.fromString(map["sessionType"])
|
||||||
);
|
);
|
||||||
|
@ -100,6 +108,7 @@ class UserStatus {
|
||||||
|
|
||||||
Map toMap({bool shallow = false}) {
|
Map toMap({bool shallow = false}) {
|
||||||
return {
|
return {
|
||||||
|
"userId": userId,
|
||||||
"onlineStatus": onlineStatus.index,
|
"onlineStatus": onlineStatus.index,
|
||||||
"lastStatusChange": lastStatusChange.toIso8601String(),
|
"lastStatusChange": lastStatusChange.toIso8601String(),
|
||||||
"isPresent": isPresent,
|
"isPresent": isPresent,
|
||||||
|
@ -117,10 +126,12 @@ class UserStatus {
|
||||||
"outputDevice": outputDevice,
|
"outputDevice": outputDevice,
|
||||||
"isMobile": isMobile,
|
"isMobile": isMobile,
|
||||||
"compatibilityHash": compatibilityHash,
|
"compatibilityHash": compatibilityHash,
|
||||||
|
"sessionType": toBeginningOfSentenceCase(sessionType.name)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
UserStatus copyWith({
|
UserStatus copyWith({
|
||||||
|
String? userId,
|
||||||
OnlineStatus? onlineStatus,
|
OnlineStatus? onlineStatus,
|
||||||
DateTime? lastStatusChange,
|
DateTime? lastStatusChange,
|
||||||
DateTime? lastPresenceTimestamp,
|
DateTime? lastPresenceTimestamp,
|
||||||
|
@ -137,6 +148,7 @@ class UserStatus {
|
||||||
List<Session>? decodedSessions,
|
List<Session>? decodedSessions,
|
||||||
}) =>
|
}) =>
|
||||||
UserStatus(
|
UserStatus(
|
||||||
|
userId: userId ?? this.userId,
|
||||||
onlineStatus: onlineStatus ?? this.onlineStatus,
|
onlineStatus: onlineStatus ?? this.onlineStatus,
|
||||||
lastStatusChange: lastStatusChange ?? this.lastStatusChange,
|
lastStatusChange: lastStatusChange ?? this.lastStatusChange,
|
||||||
lastPresenceTimestamp: lastPresenceTimestamp ?? this.lastPresenceTimestamp,
|
lastPresenceTimestamp: lastPresenceTimestamp ?? this.lastPresenceTimestamp,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:recon/client_holder.dart';
|
import 'package:recon/client_holder.dart';
|
||||||
import 'package:recon/clients/messaging_client.dart';
|
import 'package:recon/clients/messaging_client.dart';
|
||||||
import 'package:recon/models/users/online_status.dart';
|
import 'package:recon/models/users/online_status.dart';
|
||||||
|
@ -52,7 +53,7 @@ class _FriendsListAppBarState extends State<FriendsListAppBar> with AutomaticKee
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
itemBuilder: (BuildContext context) => OnlineStatus.values
|
itemBuilder: (BuildContext context) => OnlineStatus.values
|
||||||
.where((element) => element == OnlineStatus.online || element == OnlineStatus.invisible)
|
.where((element) => element == OnlineStatus.online || element == OnlineStatus.offline).sorted((a, b) => b.index.compareTo(a.index),)
|
||||||
.map(
|
.map(
|
||||||
(item) => PopupMenuItem<OnlineStatus>(
|
(item) => PopupMenuItem<OnlineStatus>(
|
||||||
value: item,
|
value: item,
|
||||||
|
|
|
@ -5,7 +5,6 @@ import 'package:recon/auxiliary.dart';
|
||||||
import 'package:recon/clients/inventory_client.dart';
|
import 'package:recon/clients/inventory_client.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
|
@ -926,7 +926,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.7"
|
version: "3.0.7"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||||
|
|
|
@ -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
|
# 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
|
# 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.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 0.9.0+1
|
version: 0.9.1+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.0.1'
|
sdk: '>=3.0.1'
|
||||||
|
@ -63,7 +63,6 @@ dependencies:
|
||||||
permission_handler: ^10.2.0
|
permission_handler: ^10.2.0
|
||||||
flutter_downloader: ^1.10.4
|
flutter_downloader: ^1.10.4
|
||||||
flutter_cube: ^0.1.1
|
flutter_cube: ^0.1.1
|
||||||
vector_math: ^2.1.4
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in a new issue