mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-16 06:38:40 +00:00
bug fixes
This commit is contained in:
parent
5f2a9890ba
commit
84448f79ca
12 changed files with 155 additions and 47 deletions
68
lib/src/components/connection_state.dart
Normal file
68
lib/src/components/connection_state.dart
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ConnectionInfo extends StatefulWidget {
|
||||||
|
const ConnectionInfo({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ConnectionInfo> createState() => _ConnectionInfoWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ConnectionInfoWidgetState extends State<ConnectionInfo> {
|
||||||
|
int redColorOpacity = 100; // Initial opacity value
|
||||||
|
bool redColorGoUp = true; // Direction of the opacity change
|
||||||
|
double screenWidth = 0; // To hold the screen width
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_startColorAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startColorAnimation() {
|
||||||
|
// Change the color every 200 milliseconds
|
||||||
|
Future.delayed(Duration(milliseconds: 200), () {
|
||||||
|
setState(() {
|
||||||
|
if (redColorOpacity <= 100) {
|
||||||
|
redColorGoUp = true;
|
||||||
|
}
|
||||||
|
if (redColorOpacity >= 150) {
|
||||||
|
redColorGoUp = false;
|
||||||
|
}
|
||||||
|
if (redColorGoUp) {
|
||||||
|
redColorOpacity += 10;
|
||||||
|
} else {
|
||||||
|
redColorOpacity -= 10;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_startColorAnimation(); // Repeat the animation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
screenWidth = MediaQuery.of(context).size.width; // Get the screen width
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
top: 3, // Position it at the top
|
||||||
|
left: (screenWidth * 0.5) / 2, // Center it horizontally
|
||||||
|
child: AnimatedContainer(
|
||||||
|
duration: Duration(milliseconds: 100),
|
||||||
|
width: screenWidth * 0.5, // 50% of the screen width
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.red[600]!
|
||||||
|
.withAlpha(redColorOpacity), // Use the animated opacity
|
||||||
|
width: 2.0, // Red border width
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10.0),
|
||||||
|
), // Rounded corners
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -68,6 +68,10 @@
|
||||||
"contactVerifyNumberMarkAsVerified": "Als verifiziert markieren",
|
"contactVerifyNumberMarkAsVerified": "Als verifiziert markieren",
|
||||||
"contactVerifyNumberClearVerification": "Verifizierung aufheben",
|
"contactVerifyNumberClearVerification": "Verifizierung aufheben",
|
||||||
"contactVerifyNumberLongDesc": "Um die Ende-zu-Ende-Verschlüsselung mit {username} zu verifizieren, vergleiche die Zahlen mit ihrem Gerät. Die Person kann auch deinen Code mit ihrem Gerät scannen.",
|
"contactVerifyNumberLongDesc": "Um die Ende-zu-Ende-Verschlüsselung mit {username} zu verifizieren, vergleiche die Zahlen mit ihrem Gerät. Die Person kann auch deinen Code mit ihrem Gerät scannen.",
|
||||||
|
"contactNickame": "Spitzname",
|
||||||
|
"contactBlock": "Blockieren",
|
||||||
|
"contactBlockTitle": "Blockiere {username}",
|
||||||
|
"contactBlockBody": "Ein blockierter Benutzer kann dir keine Nachrichten mehr senden, und sein Profil ist nicht mehr sichtbar. Um die Blockierung eines Benutzers aufzuheben, navigiere einfach zu Einstellungen > Datenschutz > Blockierte Benutzer.",
|
||||||
"undo": "Rückgängig",
|
"undo": "Rückgängig",
|
||||||
"redo": "Wiederholen",
|
"redo": "Wiederholen",
|
||||||
"next": "Weiter",
|
"next": "Weiter",
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,10 @@
|
||||||
"contactVerifyNumberMarkAsVerified": "Mark as verified",
|
"contactVerifyNumberMarkAsVerified": "Mark as verified",
|
||||||
"contactVerifyNumberClearVerification": "Clear verification",
|
"contactVerifyNumberClearVerification": "Clear verification",
|
||||||
"contactVerifyNumberLongDesc": "To verify the end-to-end encryption with {username}, compare the numbers with their device. The person can also scan your code with their device.",
|
"contactVerifyNumberLongDesc": "To verify the end-to-end encryption with {username}, compare the numbers with their device. The person can also scan your code with their device.",
|
||||||
|
"contactNickame": "Nickname",
|
||||||
|
"contactBlock": "Block",
|
||||||
|
"contactBlockTitle": "Block {username}",
|
||||||
|
"contactBlockBody": "A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users.",
|
||||||
"undo": "Undo",
|
"undo": "Undo",
|
||||||
"redo": "Redo",
|
"redo": "Redo",
|
||||||
"next": "Next",
|
"next": "Next",
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ class DbMessages extends CvModelBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future deleteMessageById(int messageId) async {
|
static Future<int?> deleteMessageById(int messageId) async {
|
||||||
await dbProvider.db!.delete(
|
await dbProvider.db!.delete(
|
||||||
tableName,
|
tableName,
|
||||||
where: '$columnMessageId = ?',
|
where: '$columnMessageId = ?',
|
||||||
|
|
@ -153,6 +153,7 @@ class DbMessages extends CvModelBase {
|
||||||
if (fromUserId != null) {
|
if (fromUserId != null) {
|
||||||
globalCallBackOnMessageChange(fromUserId);
|
globalCallBackOnMessageChange(fromUserId);
|
||||||
}
|
}
|
||||||
|
return fromUserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<int?> getFromUserIdByMessageId(int messageId) async {
|
static Future<int?> getFromUserIdByMessageId(int messageId) async {
|
||||||
|
|
|
||||||
|
|
@ -216,7 +216,9 @@ Future sendImage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future tryDownloadMedia(List<int> mediaToken, {bool force = false}) async {
|
Future tryDownloadMedia(int messageId, List<int> mediaToken,
|
||||||
|
{bool force = false}) async {
|
||||||
|
if (globalIsAppInBackground) return;
|
||||||
if (!force) {
|
if (!force) {
|
||||||
// TODO: create option to enable download via mobile data
|
// TODO: create option to enable download via mobile data
|
||||||
final List<ConnectivityResult> connectivityResult =
|
final List<ConnectivityResult> connectivityResult =
|
||||||
|
|
@ -234,6 +236,7 @@ Future tryDownloadMedia(List<int> mediaToken, {bool force = false}) async {
|
||||||
offset = media.length;
|
offset = media.length;
|
||||||
}
|
}
|
||||||
globalCallBackOnDownloadChange(mediaToken, true);
|
globalCallBackOnDownloadChange(mediaToken, true);
|
||||||
|
box.put("${mediaToken}_messageId", messageId);
|
||||||
apiProvider.triggerDownload(mediaToken, offset);
|
apiProvider.triggerDownload(mediaToken, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -254,7 +257,13 @@ Future userOpenedOtherMessage(int fromUserId, int messageOtherId) async {
|
||||||
Future<Uint8List?> getDownloadedMedia(
|
Future<Uint8List?> getDownloadedMedia(
|
||||||
List<int> mediaToken, int messageOtherId) async {
|
List<int> mediaToken, int messageOtherId) async {
|
||||||
final box = await getMediaStorage();
|
final box = await getMediaStorage();
|
||||||
Uint8List? media = box.get("${mediaToken}_downloaded");
|
Uint8List? media;
|
||||||
|
try {
|
||||||
|
media = box.get("${mediaToken}_downloaded");
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (media == null) return null;
|
||||||
|
|
||||||
int fromUserId = box.get("${mediaToken}_fromUserId");
|
int fromUserId = box.get("${mediaToken}_fromUserId");
|
||||||
await userOpenedOtherMessage(fromUserId, messageOtherId);
|
await userOpenedOtherMessage(fromUserId, messageOtherId);
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,9 @@ Future<client.Response> handleDownloadData(DownloadData data) async {
|
||||||
|
|
||||||
int? messageId = box.get("${data.uploadToken}_messageId");
|
int? messageId = box.get("${data.uploadToken}_messageId");
|
||||||
if (messageId != null) {
|
if (messageId != null) {
|
||||||
await DbMessages.deleteMessageById(messageId);
|
int? fromUserId = await DbMessages.deleteMessageById(messageId);
|
||||||
box.delete(boxId);
|
box.delete(boxId);
|
||||||
int? fromUserId = box.get("${data.uploadToken}_fromUserId");
|
// int? fromUserId = box.get("${data.uploadToken}_fromUserId");
|
||||||
if (fromUserId != null) {
|
if (fromUserId != null) {
|
||||||
globalCallBackOnMessageChange(fromUserId);
|
globalCallBackOnMessageChange(fromUserId);
|
||||||
}
|
}
|
||||||
|
|
@ -70,6 +70,10 @@ Future<client.Response> handleDownloadData(DownloadData data) async {
|
||||||
globalCallBackOnDownloadChange(data.uploadToken, false);
|
globalCallBackOnDownloadChange(data.uploadToken, false);
|
||||||
var ok = client.Response_Ok()..none = true;
|
var ok = client.Response_Ok()..none = true;
|
||||||
return client.Response()..ok = ok;
|
return client.Response()..ok = ok;
|
||||||
|
} else {
|
||||||
|
globalCallBackOnDownloadChange(data.uploadToken, false);
|
||||||
|
var ok = client.Response_Ok()..none = true;
|
||||||
|
return client.Response()..ok = ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,8 +187,7 @@ Future<client.Response> handleNewMessage(
|
||||||
List<int> downloadToken = content.downloadToken;
|
List<int> downloadToken = content.downloadToken;
|
||||||
Box box = await getMediaStorage();
|
Box box = await getMediaStorage();
|
||||||
box.put("${downloadToken}_fromUserId", fromUserId.toInt());
|
box.put("${downloadToken}_fromUserId", fromUserId.toInt());
|
||||||
box.put("${downloadToken}_messageId", messageId);
|
tryDownloadMedia(messageId, downloadToken);
|
||||||
tryDownloadMedia(downloadToken);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
localPushNotificationNewMessage(
|
localPushNotificationNewMessage(
|
||||||
|
|
|
||||||
|
|
@ -179,20 +179,31 @@ class ApiProvider {
|
||||||
return Result.error(ErrorCode.InternalError);
|
return Result.error(ErrorCode.InternalError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (authenticated) {
|
if (_channel == null) {
|
||||||
await authenticate();
|
return Result.error(ErrorCode.InternalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
var seq = Int64(Random().nextInt(4294967296));
|
var seq = Int64(Random().nextInt(4294967296));
|
||||||
while (messagesV0.containsKey(seq)) {
|
while (messagesV0.containsKey(seq)) {
|
||||||
seq = Int64(Random().nextInt(4294967296));
|
seq = Int64(Random().nextInt(4294967296));
|
||||||
}
|
}
|
||||||
|
|
||||||
request.v0.seq = seq;
|
request.v0.seq = seq;
|
||||||
|
|
||||||
final requestBytes = request.writeToBuffer();
|
final requestBytes = request.writeToBuffer();
|
||||||
|
|
||||||
_channel!.sink.add(requestBytes);
|
_channel!.sink.add(requestBytes);
|
||||||
|
|
||||||
return asResult(await _waitForResponse(seq));
|
Result res = asResult(await _waitForResponse(seq));
|
||||||
|
if (res.isError) {
|
||||||
|
if (res.error == ErrorCode.SessionNotAuthenticated) {
|
||||||
|
isAuthenticated = false;
|
||||||
|
if (authenticated) {
|
||||||
|
await authenticate();
|
||||||
|
// this will send the request one more time.
|
||||||
|
return _sendRequestV0(request, authenticated: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future authenticate() async {
|
Future authenticate() async {
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ class WebsocketForegroundTask extends TaskHandler {
|
||||||
// Called when data is sent using `FlutterForegroundTask.sendDataToTask`.
|
// Called when data is sent using `FlutterForegroundTask.sendDataToTask`.
|
||||||
@override
|
@override
|
||||||
void onReceiveData(Object data) {
|
void onReceiveData(Object data) {
|
||||||
|
apiProvider.close(() {});
|
||||||
print('onReceiveData: $data');
|
print('onReceiveData: $data');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,7 +54,7 @@ class WebsocketForegroundTask extends TaskHandler {
|
||||||
// Called when the notification itself is pressed.
|
// Called when the notification itself is pressed.
|
||||||
@override
|
@override
|
||||||
void onNotificationPressed() {
|
void onNotificationPressed() {
|
||||||
print('onNotificationPressed');
|
apiProvider.close(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the notification itself is dismissed.
|
// Called when the notification itself is dismissed.
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ class ChatListEntry extends StatelessWidget {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
tryDownloadMedia(token, force: true);
|
tryDownloadMedia(message.messageId, token, force: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,7 @@ class _UserListItem extends State<UserListItem> {
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (isDownloading) return;
|
if (isDownloading) return;
|
||||||
if (!widget.lastMessage.isDownloaded) {
|
if (!widget.lastMessage.isDownloaded) {
|
||||||
tryDownloadMedia(token, force: true);
|
tryDownloadMedia(widget.lastMessage.messageId, token, force: true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (state == MessageSendState.received &&
|
if (state == MessageSendState.received &&
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
||||||
import 'package:local_auth/local_auth.dart';
|
import 'package:local_auth/local_auth.dart';
|
||||||
import 'package:lottie/lottie.dart';
|
import 'package:lottie/lottie.dart';
|
||||||
import 'package:no_screenshot/no_screenshot.dart';
|
import 'package:no_screenshot/no_screenshot.dart';
|
||||||
|
|
@ -74,6 +73,12 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
List<int> token = content.downloadToken;
|
List<int> token = content.downloadToken;
|
||||||
_imageByte =
|
_imageByte =
|
||||||
await getDownloadedMedia(token, widget.message.messageOtherId!);
|
await getDownloadedMedia(token, widget.message.messageOtherId!);
|
||||||
|
if (_imageByte == null) {
|
||||||
|
// image already deleted
|
||||||
|
if (context.mounted) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
@ -204,31 +209,31 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (_imageByte != null && false)
|
// if (_imageByte != null)
|
||||||
Positioned(
|
// Positioned(
|
||||||
bottom: 30,
|
// bottom: 30,
|
||||||
left: 0,
|
// left: 0,
|
||||||
right: 0,
|
// right: 0,
|
||||||
child: Row(
|
// child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
// children: [
|
||||||
// const SizedBox(width: 20),
|
// // const SizedBox(width: 20),
|
||||||
FilledButton.icon(
|
// FilledButton.icon(
|
||||||
icon: FaIcon(FontAwesomeIcons.solidPaperPlane),
|
// icon: FaIcon(FontAwesomeIcons.solidPaperPlane),
|
||||||
onPressed: () async {},
|
// onPressed: () async {},
|
||||||
style: ButtonStyle(
|
// style: ButtonStyle(
|
||||||
padding: WidgetStateProperty.all<EdgeInsets>(
|
// padding: WidgetStateProperty.all<EdgeInsets>(
|
||||||
EdgeInsets.symmetric(vertical: 10, horizontal: 30),
|
// EdgeInsets.symmetric(vertical: 10, horizontal: 30),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
label: Text(
|
// label: Text(
|
||||||
"Respond",
|
// "Respond",
|
||||||
style: TextStyle(fontSize: 17),
|
// style: TextStyle(fontSize: 17),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import 'package:twonly/src/components/verified_shield.dart';
|
||||||
import 'package:twonly/src/model/contacts_model.dart';
|
import 'package:twonly/src/model/contacts_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:twonly/src/providers/messages_change_provider.dart';
|
import 'package:twonly/src/providers/messages_change_provider.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/views/contact/contact_verify_view.dart';
|
import 'package:twonly/src/views/contact/contact_verify_view.dart';
|
||||||
|
|
||||||
class ContactView extends StatefulWidget {
|
class ContactView extends StatefulWidget {
|
||||||
|
|
@ -67,7 +68,7 @@ class _ContactViewState extends State<ContactView> {
|
||||||
SizedBox(height: 50),
|
SizedBox(height: 50),
|
||||||
BetterListTile(
|
BetterListTile(
|
||||||
icon: FontAwesomeIcons.pencil,
|
icon: FontAwesomeIcons.pencil,
|
||||||
text: "Nickname",
|
text: context.lang.contactNickame,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
String? newUsername =
|
String? newUsername =
|
||||||
await showNicknameChangeDialog(context, widget.contact);
|
await showNicknameChangeDialog(context, widget.contact);
|
||||||
|
|
@ -80,7 +81,7 @@ class _ContactViewState extends State<ContactView> {
|
||||||
const Divider(),
|
const Divider(),
|
||||||
BetterListTile(
|
BetterListTile(
|
||||||
icon: FontAwesomeIcons.shieldHeart,
|
icon: FontAwesomeIcons.shieldHeart,
|
||||||
text: "Verify safety number",
|
text: context.lang.contactVerifyNumberTitle,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(context, MaterialPageRoute(
|
Navigator.push(context, MaterialPageRoute(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
|
|
@ -92,12 +93,13 @@ class _ContactViewState extends State<ContactView> {
|
||||||
BetterListTile(
|
BetterListTile(
|
||||||
icon: FontAwesomeIcons.ban,
|
icon: FontAwesomeIcons.ban,
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
text: "Block",
|
text: context.lang.contactBlock,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
bool block = await showAlertDialog(
|
bool block = await showAlertDialog(
|
||||||
context,
|
context,
|
||||||
"Block ${widget.contact.displayName}",
|
context.lang.contactBlockTitle(widget.contact.displayName),
|
||||||
"A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users..");
|
context.lang.contactBlockBody,
|
||||||
|
);
|
||||||
if (block) {
|
if (block) {
|
||||||
await DbContacts.blockUser(widget.contact.userId.toInt());
|
await DbContacts.blockUser(widget.contact.userId.toInt());
|
||||||
// go back to the first
|
// go back to the first
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue