mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-05-25 03:42:13 +00:00
new add contact view for scanned qr via link
This commit is contained in:
parent
3c91f99008
commit
646b9c22d3
11 changed files with 174 additions and 11 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
|
@ -115,7 +116,7 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
|||
bool _isUserCreated = false;
|
||||
bool _showOnboarding = true;
|
||||
bool _isLoaded = false;
|
||||
bool _skipBackup = false;
|
||||
bool _skipBackup = kDebugMode;
|
||||
bool _isTwonlyLocked = true;
|
||||
|
||||
(Future<int>?, bool) _proofOfWork = (null, false);
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import 'package:twonly/src/constants/routes.keys.dart';
|
|||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
import 'package:twonly/src/visual/views/camera/camera_qr_scanner.view.dart';
|
||||
import 'package:twonly/src/visual/views/camera/camera_send_to.view.dart';
|
||||
import 'package:twonly/src/visual/views/chats/add_new_user.view.dart';
|
||||
import 'package:twonly/src/visual/views/chats/archived_chats.view.dart';
|
||||
import 'package:twonly/src/visual/views/chats/chat_messages.view.dart';
|
||||
import 'package:twonly/src/visual/views/chats/media_viewer.view.dart';
|
||||
import 'package:twonly/src/visual/views/chats/start_new_chat.view.dart';
|
||||
import 'package:twonly/src/visual/views/contact/add_new_contact.view.dart';
|
||||
import 'package:twonly/src/visual/views/contact/contact.view.dart';
|
||||
import 'package:twonly/src/visual/views/groups/group.view.dart';
|
||||
import 'package:twonly/src/visual/views/groups/group_create_select_members.view.dart';
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ import 'package:twonly/src/utils/misc.dart';
|
|||
import 'package:twonly/src/utils/qr.utils.dart';
|
||||
import 'package:twonly/src/visual/components/alert.dialog.dart';
|
||||
import 'package:twonly/src/visual/views/camera/share_image_editor.view.dart';
|
||||
import 'package:twonly/src/visual/views/chats/add_new_user.view.dart';
|
||||
import 'package:twonly/src/visual/views/contact/add_contact_via_qr_link.view.dart';
|
||||
import 'package:twonly/src/visual/views/contact/add_new_contact.view.dart';
|
||||
|
||||
Future<bool> handleIntentUrl(BuildContext context, Uri uri) async {
|
||||
if (!uri.scheme.startsWith('http')) return false;
|
||||
|
|
@ -50,9 +51,9 @@ Future<bool> handleIntentUrl(BuildContext context, Uri uri) async {
|
|||
}
|
||||
} else {
|
||||
await context.navPush(
|
||||
AddNewUserView(
|
||||
username: profile.username,
|
||||
publicKey: Uint8List.fromList(profile.publicIdentityKey),
|
||||
AddContactViaQrLinkView(
|
||||
profile: profile,
|
||||
qrCodeLink: uri.toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class QrCodeUtils {
|
|||
profile.userId.toInt(),
|
||||
);
|
||||
|
||||
if (contact == null || !contact.accepted) {
|
||||
if (contact == null) {
|
||||
if (profile.username == userService.currentUser.username) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
154
lib/src/visual/views/contact/add_contact_via_qr_link.view.dart
Normal file
154
lib/src/visual/views/contact/add_contact_via_qr_link.view.dart
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:drift/drift.dart' hide Column;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:twonly/locator.dart';
|
||||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart'
|
||||
as server;
|
||||
import 'package:twonly/src/model/protobuf/client/generated/qr.pb.dart';
|
||||
import 'package:twonly/src/services/api/utils.api.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/utils/qr.utils.dart';
|
||||
|
||||
class AddContactViaQrLinkView extends StatefulWidget {
|
||||
const AddContactViaQrLinkView({
|
||||
required this.profile,
|
||||
this.qrCodeLink,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final PublicProfile profile;
|
||||
final String? qrCodeLink;
|
||||
|
||||
@override
|
||||
State<AddContactViaQrLinkView> createState() =>
|
||||
_AddContactViaQrLinkViewState();
|
||||
}
|
||||
|
||||
class _AddContactViaQrLinkViewState extends State<AddContactViaQrLinkView> {
|
||||
bool _isLoading = false;
|
||||
|
||||
Future<void> _sendFollowRequest() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
|
||||
try {
|
||||
final userData = server.Response_UserData(
|
||||
userId: widget.profile.userId,
|
||||
publicIdentityKey: widget.profile.publicIdentityKey,
|
||||
signedPrekey: widget.profile.signedPrekey,
|
||||
signedPrekeySignature: widget.profile.signedPrekeySignature,
|
||||
signedPrekeyId: widget.profile.signedPrekeyId,
|
||||
username: utf8.encode(widget.profile.username),
|
||||
registrationId: widget.profile.registrationId,
|
||||
);
|
||||
|
||||
final added = await twonlyDB.contactsDao.insertOnConflictUpdate(
|
||||
ContactsCompanion(
|
||||
username: Value(widget.profile.username),
|
||||
userId: Value(widget.profile.userId.toInt()),
|
||||
requested: const Value(false),
|
||||
blocked: const Value(false),
|
||||
deletedByUser: const Value(false),
|
||||
),
|
||||
);
|
||||
|
||||
if (added > 0) {
|
||||
await importSignalContactAndCreateRequest(userData);
|
||||
if (widget.qrCodeLink != null) {
|
||||
// As the user does now exist he can now be marked as verified
|
||||
await QrCodeUtils.handleQrCodeLink(widget.qrCodeLink!);
|
||||
}
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
context.pop();
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Error: $e')),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(context.lang.addFriendTitle),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Spacer(),
|
||||
CircleAvatar(
|
||||
radius: 50,
|
||||
backgroundColor: context.color.primaryContainer,
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.user,
|
||||
size: 40,
|
||||
color: context.color.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
widget.profile.username,
|
||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: context.color.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
context.lang.userFoundBody,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
color: context.color.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
const SizedBox(width: 16),
|
||||
Center(
|
||||
child: FilledButton(
|
||||
onPressed: _isLoading ? null : _sendFollowRequest,
|
||||
child: _isLoading
|
||||
? const SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
)
|
||||
: Text(context.lang.createContactRequest),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Center(
|
||||
child: OutlinedButton(
|
||||
onPressed: _isLoading ? null : () => context.pop(),
|
||||
child: Text(context.lang.cancel),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -14,8 +14,8 @@ import 'package:twonly/src/database/twonly.db.dart';
|
|||
import 'package:twonly/src/services/api/utils.api.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/visual/components/alert.dialog.dart';
|
||||
import 'package:twonly/src/visual/views/chats/add_new_user_components/friend_suggestions.comp.dart';
|
||||
import 'package:twonly/src/visual/views/chats/add_new_user_components/open_requests_list.comp.dart';
|
||||
import 'package:twonly/src/visual/views/contact/add_new_contact_components/friend_suggestions.comp.dart';
|
||||
import 'package:twonly/src/visual/views/contact/add_new_contact_components/open_requests_list.comp.dart';
|
||||
|
||||
class AddNewUserView extends StatefulWidget {
|
||||
const AddNewUserView({
|
||||
|
|
@ -11,7 +11,7 @@ import 'package:twonly/src/utils/misc.dart';
|
|||
import 'package:twonly/src/visual/components/avatar_icon.comp.dart';
|
||||
import 'package:twonly/src/visual/elements/headline.element.dart';
|
||||
import 'package:twonly/src/visual/themes/light.dart';
|
||||
import 'package:twonly/src/visual/views/chats/add_new_user_components/friend_suggestions.comp.dart';
|
||||
import 'package:twonly/src/visual/views/contact/add_new_contact_components/friend_suggestions.comp.dart';
|
||||
|
||||
class OpenRequestsListComp extends StatelessWidget {
|
||||
const OpenRequestsListComp({
|
||||
|
|
@ -18,7 +18,7 @@ import 'package:twonly/src/visual/components/flame_counter.comp.dart';
|
|||
import 'package:twonly/src/visual/components/select_chat_deletion_time.comp.dart';
|
||||
import 'package:twonly/src/visual/components/verification_badge.comp.dart';
|
||||
import 'package:twonly/src/visual/elements/better_list_title.element.dart';
|
||||
import 'package:twonly/src/visual/views/contact/components/restore_flame.comp.dart';
|
||||
import 'package:twonly/src/visual/views/contact/contact_components/restore_flame.comp.dart';
|
||||
import 'package:twonly/src/visual/views/groups/group.view.dart';
|
||||
|
||||
class ContactView extends StatefulWidget {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,13 @@ class HomeViewState extends State<HomeView> {
|
|||
unawaited(_mainCameraController.selectCamera(0, true));
|
||||
unawaited(_initAsync());
|
||||
|
||||
handleIntentUrl(
|
||||
context,
|
||||
Uri.parse(
|
||||
'https://me.twonly.eu/qr/#EAAauAEIgLDN0Nm7oKh0EghoYWhoaGhoaBohBRZQ8w_zpm1v7SRTdc8GEOMAxuf1caGDlBa-v0ZiTw9qIiEF05juEs1c3yw0STiSwQR7lowDX5hBaxN4YFR0HhkopGIoudTO5wIyQFQRtU1aO7P7O5s2ekB1ppAost3iQQizwhFObjOLgHQnpwcnwEONXZzSADYqCeEoNcvyE45w0v21z1Imhozk3Q44oI0GQhA9U_chIJwwZ7J9fpeXODZF',
|
||||
),
|
||||
);
|
||||
|
||||
// Subscribe to all events (initial link and further)
|
||||
_deepLinkSub = AppLinks().uriLinkStream.listen((uri) async {
|
||||
if (!mounted) return;
|
||||
|
|
|
|||
Loading…
Reference in a new issue