mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 11:18:41 +00:00
bug fixes
This commit is contained in:
parent
1b1da8c481
commit
606d377617
15 changed files with 84 additions and 94 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -5,9 +5,11 @@
|
||||||
*.swp
|
*.swp
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.atom/
|
.atom/
|
||||||
|
.build/
|
||||||
.buildlog/
|
.buildlog/
|
||||||
.history
|
.history
|
||||||
.svn/
|
.svn/
|
||||||
|
.swiftpm/
|
||||||
migrate_working_dir/
|
migrate_working_dir/
|
||||||
|
|
||||||
# IntelliJ related
|
# IntelliJ related
|
||||||
|
|
|
||||||
|
|
@ -120,57 +120,6 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initService() {
|
|
||||||
FlutterForegroundTask.init(
|
|
||||||
androidNotificationOptions: AndroidNotificationOptions(
|
|
||||||
channelId: 'foreground_service',
|
|
||||||
channelName: 'Foreground Service Notification',
|
|
||||||
channelDescription:
|
|
||||||
'This notification appears when the foreground service is running.',
|
|
||||||
onlyAlertOnce: true,
|
|
||||||
),
|
|
||||||
iosNotificationOptions: const IOSNotificationOptions(
|
|
||||||
showNotification: false,
|
|
||||||
playSound: false,
|
|
||||||
),
|
|
||||||
foregroundTaskOptions: ForegroundTaskOptions(
|
|
||||||
eventAction: ForegroundTaskEventAction.repeat(5000),
|
|
||||||
autoRunOnBoot: true,
|
|
||||||
autoRunOnMyPackageReplaced: true,
|
|
||||||
allowWakeLock: true,
|
|
||||||
allowWifiLock: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<ServiceRequestResult> _startService() async {
|
|
||||||
if (await FlutterForegroundTask.isRunningService) {
|
|
||||||
return FlutterForegroundTask.restartService();
|
|
||||||
} else {
|
|
||||||
return FlutterForegroundTask.startService(
|
|
||||||
serviceId: 256,
|
|
||||||
notificationTitle: 'Staying connected to the server.',
|
|
||||||
notificationText: 'Tap to return to the app',
|
|
||||||
notificationIcon:
|
|
||||||
NotificationIcon(metaDataName: "eu.twonly.service.TWONLY_LOGO"),
|
|
||||||
notificationInitialRoute: '/chats',
|
|
||||||
callback: startCallback,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future _stopService() async {
|
|
||||||
if (context.mounted) {
|
|
||||||
context.read<MessagesChangeProvider>().init(afterPaused: true);
|
|
||||||
context.read<ContactChangeProvider>().update();
|
|
||||||
}
|
|
||||||
FlutterForegroundTask.sendDataToTask("");
|
|
||||||
await FlutterForegroundTask.stopService();
|
|
||||||
if (!apiProvider.isAuthenticated) {
|
|
||||||
apiProvider.connect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
super.didChangeAppLifecycleState(state);
|
super.didChangeAppLifecycleState(state);
|
||||||
|
|
@ -178,15 +127,18 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||||
if (wasPaused) {
|
if (wasPaused) {
|
||||||
globalIsAppInBackground = false;
|
globalIsAppInBackground = false;
|
||||||
apiProvider.connect();
|
apiProvider.connect();
|
||||||
|
context.read<ContactChangeProvider>().update();
|
||||||
|
context.read<MessagesChangeProvider>().init();
|
||||||
// _stopService();
|
// _stopService();
|
||||||
}
|
}
|
||||||
} else if (state == AppLifecycleState.paused) {
|
} else if (state == AppLifecycleState.paused) {
|
||||||
wasPaused = true;
|
wasPaused = true;
|
||||||
globalIsAppInBackground = true;
|
globalIsAppInBackground = true;
|
||||||
apiProvider.close(() {
|
|
||||||
|
// apiProvider.close(() {
|
||||||
// use this only when uploading an image
|
// use this only when uploading an image
|
||||||
// _startService();
|
// _startService();
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
"searchUsernameInput": "Benutzername",
|
"searchUsernameInput": "Benutzername",
|
||||||
"searchUsernameTitle": "Benutzernamen suchen",
|
"searchUsernameTitle": "Benutzernamen suchen",
|
||||||
"searchUsernameNotFound": "Benutzername nicht gefunden",
|
"searchUsernameNotFound": "Benutzername nicht gefunden",
|
||||||
|
"searchUsernameNotFoundBody": "Es wurde kein Benutzer mit dem Benutzernamen \"{username}\" gefunden.",
|
||||||
"searchUsernameNewFollowerTitle": "Folgeanfragen",
|
"searchUsernameNewFollowerTitle": "Folgeanfragen",
|
||||||
"searchUsernameQrCodeBtn": "QR-Code scannen",
|
"searchUsernameQrCodeBtn": "QR-Code scannen",
|
||||||
"chatListViewSearchUserNameBtn": "Füge deinen ersten twonly-Kontakt hinzu!",
|
"chatListViewSearchUserNameBtn": "Füge deinen ersten twonly-Kontakt hinzu!",
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
"searchUsernameInput": "Username",
|
"searchUsernameInput": "Username",
|
||||||
"searchUsernameTitle": "Search username",
|
"searchUsernameTitle": "Search username",
|
||||||
"searchUsernameNotFound": "Username not found",
|
"searchUsernameNotFound": "Username not found",
|
||||||
|
"searchUsernameNotFoundBody": "There is no user with the username \"{username}\" registered.",
|
||||||
"searchUsernameNewFollowerTitle": "Follow requests",
|
"searchUsernameNewFollowerTitle": "Follow requests",
|
||||||
"searchUsernameQrCodeBtn": "Scan QR code",
|
"searchUsernameQrCodeBtn": "Scan QR code",
|
||||||
"chatListViewSearchUserNameBtn": "Add your first twonly contact!",
|
"chatListViewSearchUserNameBtn": "Add your first twonly contact!",
|
||||||
|
|
|
||||||
|
|
@ -325,7 +325,7 @@ class DbMessages extends CvModelBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future userOpenedOtherMessage(
|
static Future userOpenedOtherMessage(
|
||||||
int otherMessageId, int fromUserId) async {
|
int fromUserId, int otherMessageId) async {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
columnMessageOpenedAt: DateTime.now().toIso8601String(),
|
columnMessageOpenedAt: DateTime.now().toIso8601String(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,13 @@ import 'package:twonly/src/utils/signal.dart' as SignalHelper;
|
||||||
Future tryTransmitMessages() async {
|
Future tryTransmitMessages() async {
|
||||||
List<DbMessage> retransmit =
|
List<DbMessage> retransmit =
|
||||||
await DbMessages.getAllMessagesForRetransmitting();
|
await DbMessages.getAllMessagesForRetransmitting();
|
||||||
|
if (retransmit.isEmpty) return;
|
||||||
|
|
||||||
debugPrint("tryTransmitMessages: ${retransmit.length}");
|
Logger("api.dart").info("try sending messages: ${retransmit.length}");
|
||||||
|
|
||||||
Box box = await getMediaStorage();
|
Box box = await getMediaStorage();
|
||||||
for (int i = 0; i < retransmit.length; i++) {
|
for (int i = 0; i < retransmit.length; i++) {
|
||||||
int msgId = retransmit[i].messageId;
|
int msgId = retransmit[i].messageId;
|
||||||
debugPrint("msgId=$msgId");
|
|
||||||
|
|
||||||
Uint8List? bytes = box.get("retransmit-$msgId-textmessage");
|
Uint8List? bytes = box.get("retransmit-$msgId-textmessage");
|
||||||
if (bytes != null) {
|
if (bytes != null) {
|
||||||
|
|
@ -46,13 +46,8 @@ Future tryTransmitMessages() async {
|
||||||
if (encryptedMedia != null) {
|
if (encryptedMedia != null) {
|
||||||
final content = retransmit[i].messageContent;
|
final content = retransmit[i].messageContent;
|
||||||
if (content is MediaMessageContent) {
|
if (content is MediaMessageContent) {
|
||||||
await uploadMediaFile(
|
uploadMediaFile(msgId, Int64(retransmit[i].otherUserId), encryptedMedia,
|
||||||
msgId,
|
content.isRealTwonly, content.maxShowTime, retransmit[i].sendAt);
|
||||||
Int64(retransmit[i].otherUserId),
|
|
||||||
encryptedMedia,
|
|
||||||
content.isRealTwonly,
|
|
||||||
content.maxShowTime,
|
|
||||||
retransmit[i].sendAt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +64,6 @@ Future<Result> encryptAndSendMessage(Int64 userId, Message msg) async {
|
||||||
|
|
||||||
Box box = await getMediaStorage();
|
Box box = await getMediaStorage();
|
||||||
if (msg.messageId != null) {
|
if (msg.messageId != null) {
|
||||||
debugPrint("putting=${msg.messageId}");
|
|
||||||
box.put("retransmit-${msg.messageId}-textmessage", bytes);
|
box.put("retransmit-${msg.messageId}-textmessage", bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,6 +112,7 @@ Future uploadMediaFile(
|
||||||
DateTime messageSendAt,
|
DateTime messageSendAt,
|
||||||
) async {
|
) async {
|
||||||
Box box = await getMediaStorage();
|
Box box = await getMediaStorage();
|
||||||
|
Logger("api.dart").info("Uploading image $messageId");
|
||||||
|
|
||||||
List<int>? uploadToken = box.get("retransmit-$messageId-uploadtoken");
|
List<int>? uploadToken = box.get("retransmit-$messageId-uploadtoken");
|
||||||
if (uploadToken == null) {
|
if (uploadToken == null) {
|
||||||
|
|
@ -135,10 +130,10 @@ Future uploadMediaFile(
|
||||||
|
|
||||||
int offset = box.get("retransmit-$messageId-offset") ?? 0;
|
int offset = box.get("retransmit-$messageId-offset") ?? 0;
|
||||||
|
|
||||||
int fragmentedTransportSize = 100000;
|
int fragmentedTransportSize = 50000;
|
||||||
|
|
||||||
while (offset < encryptedMedia.length) {
|
while (offset < encryptedMedia.length) {
|
||||||
debugPrint("offset: $offset");
|
Logger("api.dart").info("Uploading image $messageId with offset: $offset");
|
||||||
int end = encryptedMedia.length;
|
int end = encryptedMedia.length;
|
||||||
if (offset + fragmentedTransportSize < encryptedMedia.length) {
|
if (offset + fragmentedTransportSize < encryptedMedia.length) {
|
||||||
end = offset + fragmentedTransportSize;
|
end = offset + fragmentedTransportSize;
|
||||||
|
|
@ -162,8 +157,6 @@ Future uploadMediaFile(
|
||||||
offset = end;
|
offset = end;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger("api.dart").shout("DOING UPDATE");
|
|
||||||
|
|
||||||
box.delete("retransmit-$messageId-media");
|
box.delete("retransmit-$messageId-media");
|
||||||
box.delete("retransmit-$messageId-uploadtoken");
|
box.delete("retransmit-$messageId-uploadtoken");
|
||||||
|
|
||||||
|
|
@ -302,7 +295,7 @@ Future tryDownloadMedia(int messageId, int fromUserId, List<int> mediaToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
Future userOpenedOtherMessage(int fromUserId, int messageOtherId) async {
|
Future userOpenedOtherMessage(int fromUserId, int messageOtherId) async {
|
||||||
await DbMessages.userOpenedOtherMessage(messageOtherId, fromUserId);
|
await DbMessages.userOpenedOtherMessage(fromUserId, messageOtherId);
|
||||||
|
|
||||||
encryptAndSendMessage(
|
encryptAndSendMessage(
|
||||||
Int64(fromUserId),
|
Int64(fromUserId),
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,8 @@ Future<client.Response> handleDownloadData(DownloadData data) async {
|
||||||
// download should only be done when the app is open
|
// download should only be done when the app is open
|
||||||
return client.Response()..error = ErrorCode.InternalError;
|
return client.Response()..error = ErrorCode.InternalError;
|
||||||
}
|
}
|
||||||
debugPrint("Downloading: ${data.uploadToken} ${data.fin}");
|
Logger("server_messages")
|
||||||
|
.info("downloading: ${data.uploadToken} ${data.fin}");
|
||||||
final box = await getMediaStorage();
|
final box = await getMediaStorage();
|
||||||
|
|
||||||
String boxId = data.uploadToken.toString();
|
String boxId = data.uploadToken.toString();
|
||||||
|
|
@ -83,6 +84,8 @@ Future<client.Response> handleDownloadData(DownloadData data) async {
|
||||||
Uint8List downloadedBytes;
|
Uint8List downloadedBytes;
|
||||||
if (buffered != null) {
|
if (buffered != null) {
|
||||||
if (data.offset != buffered.length) {
|
if (data.offset != buffered.length) {
|
||||||
|
Logger("server_messages")
|
||||||
|
.info("server send wrong offset: ${data.offset} ${buffered.length}");
|
||||||
// Logger("handleDownloadData").error(object)
|
// Logger("handleDownloadData").error(object)
|
||||||
return client.Response()..error = ErrorCode.InvalidOffset;
|
return client.Response()..error = ErrorCode.InvalidOffset;
|
||||||
}
|
}
|
||||||
|
|
@ -104,6 +107,9 @@ Future<client.Response> handleDownloadData(DownloadData data) async {
|
||||||
|
|
||||||
if (rawBytes != null) {
|
if (rawBytes != null) {
|
||||||
box.put("${data.uploadToken}_downloaded", rawBytes);
|
box.put("${data.uploadToken}_downloaded", rawBytes);
|
||||||
|
} else {
|
||||||
|
Logger("server_messages")
|
||||||
|
.shout("error decrypting the message: ${data.uploadToken}");
|
||||||
}
|
}
|
||||||
|
|
||||||
box.delete(boxId);
|
box.delete(boxId);
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,11 @@ import 'package:web_socket_channel/web_socket_channel.dart';
|
||||||
/// It handles errors and does automatically tries to reconnect on
|
/// It handles errors and does automatically tries to reconnect on
|
||||||
/// errors or network changes.
|
/// errors or network changes.
|
||||||
class ApiProvider {
|
class ApiProvider {
|
||||||
final String apiUrl = kDebugMode
|
final String apiUrl = (kDebugMode && false)
|
||||||
? "ws://10.99.0.6:3030/api/client"
|
? "ws://10.99.0.6:3030/api/client"
|
||||||
: "wss://api.twonly.eu/api/client";
|
: "wss://api.twonly.eu/api/client";
|
||||||
// ws://api.twonly.eu/api/client
|
// ws://api.twonly.eu/api/client
|
||||||
final String? backupApiUrl = kDebugMode
|
final String? backupApiUrl = (kDebugMode && false)
|
||||||
? "ws://10.99.0.6:3030/api/client"
|
? "ws://10.99.0.6:3030/api/client"
|
||||||
: "wss://api2.twonly.eu/api/client";
|
: "wss://api2.twonly.eu/api/client";
|
||||||
bool isAuthenticated = false;
|
bool isAuthenticated = false;
|
||||||
|
|
@ -70,10 +70,13 @@ class ApiProvider {
|
||||||
globalCallbackConnectionState(true);
|
globalCallbackConnectionState(true);
|
||||||
_reconnectionDelay = 5;
|
_reconnectionDelay = 5;
|
||||||
|
|
||||||
|
if (!globalIsAppInBackground) {
|
||||||
tryTransmitMessages();
|
tryTransmitMessages();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future close(Function callback) async {
|
Future close(Function callback) async {
|
||||||
|
log.info("Closing the websocket connection!");
|
||||||
if (_channel != null) {
|
if (_channel != null) {
|
||||||
await _channel!.sink.close();
|
await _channel!.sink.close();
|
||||||
callback();
|
callback();
|
||||||
|
|
@ -83,7 +86,7 @@ class ApiProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> connect() async {
|
Future<bool> connect() async {
|
||||||
if (_channel != null && _channel!.closeCode != null) {
|
if (_channel != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// ensure that the connect function is not called again by the timer.
|
// ensure that the connect function is not called again by the timer.
|
||||||
|
|
@ -93,13 +96,13 @@ class ApiProvider {
|
||||||
|
|
||||||
isAuthenticated = false;
|
isAuthenticated = false;
|
||||||
|
|
||||||
log.info("Trying to connect to the backend $apiUrl!");
|
log.fine("Trying to connect to the backend $apiUrl!");
|
||||||
if (await _connectTo(apiUrl)) {
|
if (await _connectTo(apiUrl)) {
|
||||||
await onConnected();
|
await onConnected();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (backupApiUrl != null) {
|
if (backupApiUrl != null) {
|
||||||
log.info("Trying to connect to the backup backend $backupApiUrl!");
|
log.fine("Trying to connect to the backup backend $backupApiUrl!");
|
||||||
if (await _connectTo(backupApiUrl!)) {
|
if (await _connectTo(backupApiUrl!)) {
|
||||||
await onConnected();
|
await onConnected();
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -111,6 +114,7 @@ class ApiProvider {
|
||||||
bool get isConnected => _channel != null && _channel!.closeCode != null;
|
bool get isConnected => _channel != null && _channel!.closeCode != null;
|
||||||
|
|
||||||
void _onDone() {
|
void _onDone() {
|
||||||
|
log.info("WebSocket Closed");
|
||||||
globalCallbackConnectionState(false);
|
globalCallbackConnectionState(false);
|
||||||
_channel = null;
|
_channel = null;
|
||||||
isAuthenticated = false;
|
isAuthenticated = false;
|
||||||
|
|
@ -118,7 +122,7 @@ class ApiProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onError(dynamic e) {
|
void _onError(dynamic e) {
|
||||||
log.shout("WebSocket Error: $e");
|
log.info("WebSocket Error: $e");
|
||||||
globalCallbackConnectionState(false);
|
globalCallbackConnectionState(false);
|
||||||
_channel = null;
|
_channel = null;
|
||||||
isAuthenticated = false;
|
isAuthenticated = false;
|
||||||
|
|
@ -126,6 +130,8 @@ class ApiProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
void tryToReconnect() {
|
void tryToReconnect() {
|
||||||
|
return;
|
||||||
|
if (globalIsAppInBackground) return;
|
||||||
if (reconnectionTimer != null) {
|
if (reconnectionTimer != null) {
|
||||||
reconnectionTimer!.cancel();
|
reconnectionTimer!.cancel();
|
||||||
}
|
}
|
||||||
|
|
@ -186,6 +192,7 @@ class ApiProvider {
|
||||||
Future<Result> _sendRequestV0(ClientToServer request,
|
Future<Result> _sendRequestV0(ClientToServer request,
|
||||||
{bool authenticated = true}) async {
|
{bool authenticated = true}) async {
|
||||||
if (_channel == null) {
|
if (_channel == null) {
|
||||||
|
log.shout("sending request, but api is not connected.");
|
||||||
if (!await connect()) {
|
if (!await connect()) {
|
||||||
return Result.error(ErrorCode.InternalError);
|
return Result.error(ErrorCode.InternalError);
|
||||||
}
|
}
|
||||||
|
|
@ -209,8 +216,13 @@ class ApiProvider {
|
||||||
isAuthenticated = false;
|
isAuthenticated = false;
|
||||||
if (authenticated) {
|
if (authenticated) {
|
||||||
await authenticate();
|
await authenticate();
|
||||||
|
if (isAuthenticated) {
|
||||||
// this will send the request one more time.
|
// this will send the request one more time.
|
||||||
return _sendRequestV0(request, authenticated: false);
|
return _sendRequestV0(request, authenticated: false);
|
||||||
|
} else {
|
||||||
|
log.shout("Session is not authenticated.");
|
||||||
|
return Result.error(ErrorCode.InternalError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,6 @@ Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||||
|
|
||||||
final stopwatch = Stopwatch()..start();
|
final stopwatch = Stopwatch()..start();
|
||||||
while (!gotMessage) {
|
while (!gotMessage) {
|
||||||
print("gotMessage: $gotMessage");
|
|
||||||
if (stopwatch.elapsed >= Duration(seconds: 20)) {
|
if (stopwatch.elapsed >= Duration(seconds: 20)) {
|
||||||
Logger("firebase-background").shout('Timeout reached. Exiting the loop.');
|
Logger("firebase-background").shout('Timeout reached. Exiting the loop.');
|
||||||
break; // Exit the loop if the timeout is reached.
|
break; // Exit the loop if the timeout is reached.
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ Future<UserData?> getUser() async {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final userMap = jsonDecode(userJson) as Map<String, dynamic>;
|
final userMap = jsonDecode(userJson) as Map<String, dynamic>;
|
||||||
Logger("get_user").info("Found user: $userMap");
|
|
||||||
final user = UserData.fromJson(userMap);
|
final user = UserData.fromJson(userMap);
|
||||||
return user;
|
return user;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,13 @@ class _ChatItemDetailsViewState extends State<ChatItemDetailsView> {
|
||||||
context
|
context
|
||||||
.read<MessagesChangeProvider>()
|
.read<MessagesChangeProvider>()
|
||||||
.loadMessagesForUser(user.userId.toInt());
|
.loadMessagesForUser(user.userId.toInt());
|
||||||
|
initAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future initAsync() async {
|
||||||
|
context
|
||||||
|
.read<MessagesChangeProvider>()
|
||||||
|
.loadMessagesForUser(user.userId.toInt(), force: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _sendMessage() async {
|
Future _sendMessage() async {
|
||||||
|
|
|
||||||
|
|
@ -162,17 +162,31 @@ class _UserListItem extends State<UserListItem> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
initAsync();
|
||||||
lastUpdateTime();
|
lastUpdateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future initAsync() async {
|
||||||
|
if (widget.lastMessage != null) {
|
||||||
|
if (!widget.lastMessage!.isDownloaded) {
|
||||||
|
final content = widget.lastMessage!.messageContent;
|
||||||
|
if (content is MediaMessageContent) {
|
||||||
|
tryDownloadMedia(widget.lastMessage!.messageId,
|
||||||
|
widget.lastMessage!.otherUserId, content.downloadToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void lastUpdateTime() {
|
void lastUpdateTime() {
|
||||||
// Change the color every 200 milliseconds
|
// Change the color every 200 milliseconds
|
||||||
updateTime = Timer.periodic(Duration(milliseconds: 200), (timer) {
|
updateTime = Timer.periodic(Duration(milliseconds: 200), (timer) {
|
||||||
setState(() {
|
setState(() {
|
||||||
lastMessageInSeconds =
|
if (widget.lastMessage != null) {
|
||||||
calculateTimeDifference(DateTime.now(), widget.lastMessage!.sendAt)
|
lastMessageInSeconds = calculateTimeDifference(
|
||||||
|
DateTime.now(), widget.lastMessage!.sendAt)
|
||||||
.inSeconds;
|
.inSeconds;
|
||||||
setState(() {});
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,8 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
child: CircularProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
value: progress,
|
value: progress,
|
||||||
strokeWidth: 2.0,
|
strokeWidth: 2.0,
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,9 @@ class _SearchUsernameView extends State<SearchUsernameView> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (context.mounted) {
|
||||||
|
showAlertDialog(context, context.lang.searchUsernameNotFound,
|
||||||
|
context.lang.searchUsernameNotFoundBody(searchUserName.text));
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ description: "Send pictures to friends in real time and be sure you are the only
|
||||||
# Prevent accidental publishing to pub.dev.
|
# Prevent accidental publishing to pub.dev.
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 0.0.1+1
|
version: 0.0.3+3
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue