mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-05-24 22:32:12 +00:00
improved layout and fixed add logging
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
This commit is contained in:
parent
0a972d023f
commit
3acd207de6
17 changed files with 577 additions and 296 deletions
|
|
@ -1,5 +1,9 @@
|
|||
# Changelog
|
||||
|
||||
## 0.2.9
|
||||
|
||||
- Fix: Messages occasionally not received until app restart
|
||||
|
||||
## 0.2.8
|
||||
|
||||
- Fix: App did not launch sometimes on Android
|
||||
|
|
|
|||
|
|
@ -16,8 +16,12 @@ class UserDiscoveryCallbacks {
|
|||
static Future<Uint8List?> signData(
|
||||
Uint8List inputData,
|
||||
) async {
|
||||
Log.info('UserDiscoveryCallbacks: signData started');
|
||||
var privKey = (await getSignalIdentityKeyPair())?.getPrivateKey();
|
||||
if (privKey == null) return null;
|
||||
if (privKey == null) {
|
||||
Log.error('UserDiscoveryCallbacks: signData failed, privKey is null');
|
||||
return null;
|
||||
}
|
||||
final random = getRandomUint8List(32);
|
||||
final signature = sign(
|
||||
privKey.serialize(),
|
||||
|
|
@ -25,6 +29,7 @@ class UserDiscoveryCallbacks {
|
|||
random,
|
||||
);
|
||||
privKey = null;
|
||||
Log.info('UserDiscoveryCallbacks: signData finished');
|
||||
return signature;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2965,6 +2965,90 @@ abstract class AppLocalizations {
|
|||
/// In en, this message translates to:
|
||||
/// **'Approve'**
|
||||
String get contactUserDiscoveryManualApprovalApprove;
|
||||
|
||||
/// No description provided for @exampleUserName1.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'james'**
|
||||
String get exampleUserName1;
|
||||
|
||||
/// No description provided for @exampleUserName2.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'mary'**
|
||||
String get exampleUserName2;
|
||||
|
||||
/// No description provided for @exampleUserName3.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'john'**
|
||||
String get exampleUserName3;
|
||||
|
||||
/// No description provided for @exampleUserName4.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'patricia'**
|
||||
String get exampleUserName4;
|
||||
|
||||
/// No description provided for @exampleUserName5.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'robert'**
|
||||
String get exampleUserName5;
|
||||
|
||||
/// No description provided for @exampleUserName6.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'jennifer'**
|
||||
String get exampleUserName6;
|
||||
|
||||
/// No description provided for @exampleUserName7.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'michael'**
|
||||
String get exampleUserName7;
|
||||
|
||||
/// No description provided for @exampleUserName8.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'linda'**
|
||||
String get exampleUserName8;
|
||||
|
||||
/// No description provided for @exampleUserName9.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'william'**
|
||||
String get exampleUserName9;
|
||||
|
||||
/// No description provided for @exampleUserName10.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'lena'**
|
||||
String get exampleUserName10;
|
||||
|
||||
/// No description provided for @exampleUserName11.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'david'**
|
||||
String get exampleUserName11;
|
||||
|
||||
/// No description provided for @exampleJane.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'jane'**
|
||||
String get exampleJane;
|
||||
|
||||
/// No description provided for @back.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Back'**
|
||||
String get back;
|
||||
|
||||
/// No description provided for @onboardingExampleLabel.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Example'**
|
||||
String get onboardingExampleLabel;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
|
|
|||
|
|
@ -1669,4 +1669,46 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get contactUserDiscoveryManualApprovalApprove => 'Freigeben';
|
||||
|
||||
@override
|
||||
String get exampleUserName1 => 'max_mustermann';
|
||||
|
||||
@override
|
||||
String get exampleUserName2 => 'erika_musterfrau';
|
||||
|
||||
@override
|
||||
String get exampleUserName3 => 'hans';
|
||||
|
||||
@override
|
||||
String get exampleUserName4 => 'petra';
|
||||
|
||||
@override
|
||||
String get exampleUserName5 => 'klaus';
|
||||
|
||||
@override
|
||||
String get exampleUserName6 => 'sabine';
|
||||
|
||||
@override
|
||||
String get exampleUserName7 => 'stefan';
|
||||
|
||||
@override
|
||||
String get exampleUserName8 => 'monika';
|
||||
|
||||
@override
|
||||
String get exampleUserName9 => 'christian';
|
||||
|
||||
@override
|
||||
String get exampleUserName10 => 'lena';
|
||||
|
||||
@override
|
||||
String get exampleUserName11 => 'david';
|
||||
|
||||
@override
|
||||
String get exampleJane => 'erika';
|
||||
|
||||
@override
|
||||
String get back => 'Zurück';
|
||||
|
||||
@override
|
||||
String get onboardingExampleLabel => 'Beispiel';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1654,4 +1654,46 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get contactUserDiscoveryManualApprovalApprove => 'Approve';
|
||||
|
||||
@override
|
||||
String get exampleUserName1 => 'james';
|
||||
|
||||
@override
|
||||
String get exampleUserName2 => 'mary';
|
||||
|
||||
@override
|
||||
String get exampleUserName3 => 'john';
|
||||
|
||||
@override
|
||||
String get exampleUserName4 => 'patricia';
|
||||
|
||||
@override
|
||||
String get exampleUserName5 => 'robert';
|
||||
|
||||
@override
|
||||
String get exampleUserName6 => 'jennifer';
|
||||
|
||||
@override
|
||||
String get exampleUserName7 => 'michael';
|
||||
|
||||
@override
|
||||
String get exampleUserName8 => 'linda';
|
||||
|
||||
@override
|
||||
String get exampleUserName9 => 'william';
|
||||
|
||||
@override
|
||||
String get exampleUserName10 => 'lena';
|
||||
|
||||
@override
|
||||
String get exampleUserName11 => 'david';
|
||||
|
||||
@override
|
||||
String get exampleJane => 'jane';
|
||||
|
||||
@override
|
||||
String get back => 'Back';
|
||||
|
||||
@override
|
||||
String get onboardingExampleLabel => 'Example';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 03bf220400bf35002c77e153768bd0f963a97d89
|
||||
Subproject commit 73d1af8ca42b10abf6204acf3720d40f9ab6d4a8
|
||||
|
|
@ -76,20 +76,28 @@ class UserDiscoveryService {
|
|||
required bool sharePromotion,
|
||||
}) async {
|
||||
try {
|
||||
Log.info('UserDiscoveryService: initializeOrUpdate started');
|
||||
final userId = userService.currentUser.userId;
|
||||
final publicKey = await getUserPublicKey();
|
||||
Log.info('UserDiscoveryService: initializing Rust bridge');
|
||||
await FlutterUserDiscovery.initializeOrUpdate(
|
||||
threshold: threshold,
|
||||
userId: userService.currentUser.userId,
|
||||
publicKey: await getUserPublicKey(),
|
||||
userId: userId,
|
||||
publicKey: publicKey,
|
||||
sharePromotion: sharePromotion,
|
||||
);
|
||||
Log.info(
|
||||
'UserDiscoveryService: Rust bridge initialized, updating UserService',
|
||||
);
|
||||
await UserService.update(
|
||||
(u) => u
|
||||
..isUserDiscoveryEnabled = true
|
||||
..userDiscoverySharePromotion = sharePromotion
|
||||
..userDiscoveryThreshold = threshold,
|
||||
);
|
||||
Log.info('UserDiscoveryService: initializeOrUpdate finished');
|
||||
} catch (e) {
|
||||
Log.error(e);
|
||||
Log.error('UserDiscoveryService: initializeOrUpdate error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ final ThemeData darkTheme = ThemeData.dark().copyWith(
|
|||
brightness: Brightness.dark,
|
||||
seedColor: const Color(0xFF57CC99),
|
||||
surface: const Color.fromARGB(255, 20, 18, 23),
|
||||
surfaceContainer: const Color.fromARGB(255, 33, 30, 39),
|
||||
surfaceContainer: const Color.fromARGB(255, 45, 41, 54),
|
||||
surfaceContainerLow: const Color.fromARGB(255, 38, 34, 45),
|
||||
surfaceContainerHigh: const Color.fromARGB(255, 52, 48, 62),
|
||||
),
|
||||
inputDecorationTheme: const InputDecorationTheme(
|
||||
border: OutlineInputBorder(),
|
||||
|
|
|
|||
|
|
@ -43,6 +43,14 @@ extension SetupPagesExtension on SetupPages {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
SetupPages? previous() {
|
||||
final prevIndex = index - 1;
|
||||
if (prevIndex >= 0) {
|
||||
return SetupPages.values[prevIndex];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class SetupView extends StatefulWidget {
|
||||
|
|
@ -119,31 +127,51 @@ class _SetupViewState extends State<SetupView> {
|
|||
),
|
||||
body: ListView(
|
||||
key: ValueKey(currentPage.name),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
|
||||
children: [
|
||||
_buildPage(currentPage, state),
|
||||
if (!currentPage.isLast)
|
||||
SizedBox(
|
||||
height: 50,
|
||||
child: Center(
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
await UserService.update(
|
||||
(u) => u.skipSetupPages = true,
|
||||
);
|
||||
widget.onUpdate?.call();
|
||||
},
|
||||
child: Text(
|
||||
context.lang.onboardingFinishLater,
|
||||
style: TextStyle(
|
||||
color: context.color.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
if (currentPage.index > 0 || !currentPage.isLast)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (currentPage.index > 0)
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await UserService.update((u) {
|
||||
u.currentSetupPage = currentPage.previous()?.name;
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
context.lang.back,
|
||||
style: TextStyle(
|
||||
color: context.color.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (currentPage.index > 0 && !currentPage.isLast)
|
||||
const SizedBox(width: 24),
|
||||
if (!currentPage.isLast)
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await UserService.update(
|
||||
(u) => u.skipSetupPages = true,
|
||||
);
|
||||
widget.onUpdate?.call();
|
||||
},
|
||||
child: Text(
|
||||
context.lang.onboardingFinishLater,
|
||||
style: TextStyle(
|
||||
color: context.color.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 60),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class AddNewContactsPage extends StatelessWidget {
|
|||
const SizedBox(height: 20),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 40),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 35),
|
||||
|
||||
child: Column(
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -8,53 +8,101 @@ class MockContactRequestActionsComp extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
// width: 125,
|
||||
return IgnorePointer(
|
||||
child: SizedBox(
|
||||
// width: 125,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(width: 4),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
// width: 45,
|
||||
child: FilledButton(
|
||||
style: FilledButton.styleFrom(
|
||||
padding: const EdgeInsets.only(right: 2, left: 4),
|
||||
backgroundColor: context.color.surfaceContainerHigh,
|
||||
foregroundColor: context.color.onSurface,
|
||||
),
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.person_off_rounded,
|
||||
color: Color.fromARGB(164, 244, 67, 54),
|
||||
size: 12,
|
||||
),
|
||||
Text(
|
||||
context.lang.contactActionBlock,
|
||||
style: const TextStyle(fontSize: 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
// width: 50,
|
||||
child: FilledButton(
|
||||
style: FilledButton.styleFrom(
|
||||
padding: const EdgeInsets.only(right: 2, left: 4),
|
||||
backgroundColor: context.color.surfaceContainerHigh,
|
||||
foregroundColor: context.color.onSurface,
|
||||
),
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.check, color: Colors.green, size: 12),
|
||||
Text(
|
||||
context.lang.contactActionAccept,
|
||||
style: const TextStyle(fontSize: 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
style: IconButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
constraints: const BoxConstraints(),
|
||||
icon: const Icon(Icons.close, size: 12),
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MockContactSuggestedActionsComp extends StatelessWidget {
|
||||
const MockContactSuggestedActionsComp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IgnorePointer(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(width: 4),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
// width: 45,
|
||||
child: FilledButton(
|
||||
style: FilledButton.styleFrom(
|
||||
padding: const EdgeInsets.only(right: 2, left: 4),
|
||||
backgroundColor: context.color.surfaceContainerHigh,
|
||||
foregroundColor: context.color.onSurface,
|
||||
),
|
||||
padding: const EdgeInsets.only(right: 8, left: 4),
|
||||
).merge(secondaryGreyButtonStyle(context)),
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.person_off_rounded,
|
||||
color: Color.fromARGB(164, 244, 67, 54),
|
||||
size: 12,
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 6),
|
||||
child: FaIcon(FontAwesomeIcons.userPlus, size: 10),
|
||||
),
|
||||
Text(
|
||||
context.lang.contactActionBlock,
|
||||
style: const TextStyle(fontSize: 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
// width: 50,
|
||||
child: FilledButton(
|
||||
style: FilledButton.styleFrom(
|
||||
padding: const EdgeInsets.only(right: 2, left: 4),
|
||||
backgroundColor: context.color.surfaceContainerHigh,
|
||||
foregroundColor: context.color.onSurface,
|
||||
),
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.check, color: Colors.green, size: 12),
|
||||
Text(
|
||||
context.lang.contactActionAccept,
|
||||
context.lang.friendSuggestionsRequest,
|
||||
style: const TextStyle(fontSize: 8),
|
||||
),
|
||||
],
|
||||
|
|
@ -75,47 +123,3 @@ class MockContactRequestActionsComp extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MockContactSuggestedActionsComp extends StatelessWidget {
|
||||
const MockContactSuggestedActionsComp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(width: 4),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
child: FilledButton(
|
||||
style: FilledButton.styleFrom(
|
||||
padding: const EdgeInsets.only(right: 8, left: 4),
|
||||
).merge(secondaryGreyButtonStyle(context)),
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 6),
|
||||
child: FaIcon(FontAwesomeIcons.userPlus, size: 10),
|
||||
),
|
||||
Text(
|
||||
context.lang.friendSuggestionsRequest,
|
||||
style: const TextStyle(fontSize: 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
style: IconButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
constraints: const BoxConstraints(),
|
||||
icon: const Icon(Icons.close, size: 12),
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class NextButtonComp extends StatelessWidget {
|
|||
userService.currentUser.currentSetupPage,
|
||||
);
|
||||
return ElevatedButton(
|
||||
onPressed: canSubmit
|
||||
onPressed: (canSubmit && !isLoading)
|
||||
? () async {
|
||||
if (onPressed != null) {
|
||||
final error = await onPressed?.call();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ class LetYourFriendsFindYou extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _LetYourFriendsFindYouState extends State<LetYourFriendsFindYou> {
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
|
@ -77,8 +79,19 @@ class _LetYourFriendsFindYouState extends State<LetYourFriendsFindYou> {
|
|||
),
|
||||
const SizedBox(height: 50),
|
||||
NextButtonComp(
|
||||
isLoading: _isLoading,
|
||||
onPressed: () async {
|
||||
return !(await widget.state.initializeOrUpdate());
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
try {
|
||||
final result = await widget.state.initializeOrUpdate();
|
||||
return !result;
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:twonly/locator.dart';
|
||||
import 'package:twonly/src/services/user.service.dart';
|
||||
import 'package:twonly/src/services/user_discovery.service.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/visual/components/avatar_icon.comp.dart';
|
||||
import 'package:twonly/src/visual/components/verification_badge.comp.dart';
|
||||
|
|
@ -9,18 +10,18 @@ import 'package:twonly/src/visual/views/contact/add_new_contact_components/frien
|
|||
import 'package:twonly/src/visual/views/onboarding/setup/components/mock_contact_request_actions.comp.dart';
|
||||
import 'package:twonly/src/visual/views/onboarding/setup/components/setup_switch_card.comp.dart';
|
||||
|
||||
const exampleUsers = [
|
||||
'james',
|
||||
'mary',
|
||||
'john',
|
||||
'patricia',
|
||||
'robert',
|
||||
'jennifer',
|
||||
'michael',
|
||||
'linda',
|
||||
'william',
|
||||
'lena',
|
||||
'david',
|
||||
List<String> getExampleUsers(BuildContext context) => [
|
||||
context.lang.exampleUserName1,
|
||||
context.lang.exampleUserName2,
|
||||
context.lang.exampleUserName3,
|
||||
context.lang.exampleUserName4,
|
||||
context.lang.exampleUserName5,
|
||||
context.lang.exampleUserName6,
|
||||
context.lang.exampleUserName7,
|
||||
context.lang.exampleUserName8,
|
||||
context.lang.exampleUserName9,
|
||||
context.lang.exampleUserName10,
|
||||
context.lang.exampleUserName11,
|
||||
];
|
||||
|
||||
class UserDiscoverySetupState {
|
||||
|
|
@ -52,21 +53,30 @@ class UserDiscoverySetupState {
|
|||
}
|
||||
|
||||
Future<bool> initializeOrUpdate() async {
|
||||
if (isUserDiscoveryEnabled) {
|
||||
await UserDiscoveryService.initializeOrUpdate(
|
||||
threshold: threshold,
|
||||
sharePromotion: sharePromotion,
|
||||
);
|
||||
try {
|
||||
Log.info('UserDiscoverySetupState: initializeOrUpdate started');
|
||||
if (isUserDiscoveryEnabled) {
|
||||
Log.info('UserDiscoverySetupState: initializing UserDiscoveryService');
|
||||
await UserDiscoveryService.initializeOrUpdate(
|
||||
threshold: threshold,
|
||||
sharePromotion: sharePromotion,
|
||||
);
|
||||
}
|
||||
|
||||
Log.info('UserDiscoverySetupState: updating UserService');
|
||||
await UserService.update((u) {
|
||||
u
|
||||
..isUserDiscoveryEnabled = isUserDiscoveryEnabled
|
||||
..requiredSendImages = requiredSendImages
|
||||
..userDiscoveryRequiresManualApproval = isManualApprovalEnabled;
|
||||
});
|
||||
|
||||
Log.info('UserDiscoverySetupState: initializeOrUpdate finished');
|
||||
return true;
|
||||
} catch (e) {
|
||||
Log.error('UserDiscoverySetupState: initializeOrUpdate failed: $e');
|
||||
return false;
|
||||
}
|
||||
|
||||
await UserService.update((u) {
|
||||
u
|
||||
..isUserDiscoveryEnabled = isUserDiscoveryEnabled
|
||||
..requiredSendImages = requiredSendImages
|
||||
..userDiscoveryRequiresManualApproval = isManualApprovalEnabled;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,15 +117,12 @@ class UserDiscoverySetupComp extends StatelessWidget {
|
|||
textAlign: TextAlign.center,
|
||||
),
|
||||
|
||||
const SizedBox(height: 32),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
SetupSwitchCard(
|
||||
value: state.isUserDiscoveryEnabled,
|
||||
onChanged: (val) => state.update(() {
|
||||
state.isUserDiscoveryEnabled = val;
|
||||
if (!val) {
|
||||
state.sharePromotion = false;
|
||||
}
|
||||
}),
|
||||
title: context.lang.onboardingUserDiscoveryShareFriends,
|
||||
expandedChild: Column(
|
||||
|
|
@ -143,48 +150,10 @@ class UserDiscoverySetupComp extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
padding: EdgeInsets.only(bottom: 8),
|
||||
child: Divider(),
|
||||
),
|
||||
Text(
|
||||
context.lang.onboardingUserDiscoveryContactsVerifiedBadge,
|
||||
style: TextStyle(
|
||||
color: context.color.onSurfaceVariant,
|
||||
fontSize: 12,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Center(
|
||||
child: Container(
|
||||
width: 100,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey, width: 0.5),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
AvatarIcon(fontSize: 12),
|
||||
SizedBox(width: 5),
|
||||
Text(
|
||||
'jane',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
VerificationBadgeComp(
|
||||
isVerifiedByTransferredTrust: true,
|
||||
size: 14,
|
||||
clickable: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const _ExampleLabel(),
|
||||
Text(
|
||||
context.lang.onboardingUserDiscoveryWhoIsRequesting,
|
||||
style: TextStyle(
|
||||
|
|
@ -214,9 +183,9 @@ class UserDiscoverySetupComp extends StatelessWidget {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'jane',
|
||||
style: TextStyle(
|
||||
Text(
|
||||
context.lang.exampleJane,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 13,
|
||||
),
|
||||
|
|
@ -226,8 +195,8 @@ class UserDiscoverySetupComp extends StatelessWidget {
|
|||
children: buildFriendsListTextString(
|
||||
context,
|
||||
[
|
||||
'mary',
|
||||
'james',
|
||||
context.lang.exampleUserName2,
|
||||
context.lang.exampleUserName1,
|
||||
],
|
||||
),
|
||||
style: const TextStyle(fontSize: 10),
|
||||
|
|
@ -241,6 +210,47 @@ class UserDiscoverySetupComp extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
context.lang.onboardingUserDiscoveryContactsVerifiedBadge,
|
||||
style: TextStyle(
|
||||
color: context.color.onSurfaceVariant,
|
||||
fontSize: 12,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Center(
|
||||
child: Container(
|
||||
width: 100,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey, width: 0.5),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const AvatarIcon(fontSize: 12),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
context.lang.exampleJane,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
const VerificationBadgeComp(
|
||||
isVerifiedByTransferredTrust: true,
|
||||
size: 14,
|
||||
clickable: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
|
|
@ -275,18 +285,15 @@ class UserDiscoverySetupComp extends StatelessWidget {
|
|||
SetupSwitchCard(
|
||||
value: state.sharePromotion,
|
||||
onChanged: (val) => state.update(() {
|
||||
if (val) {
|
||||
state.isUserDiscoveryEnabled = true;
|
||||
}
|
||||
state.sharePromotion = val;
|
||||
}),
|
||||
title: context.lang.onboardingUserDiscoveryBeRecommended,
|
||||
expandedChild: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
expandedChild: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
|
|
@ -319,121 +326,128 @@ class UserDiscoverySetupComp extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
context.lang.onboardingUserDiscoveryWhatOthersSee,
|
||||
style: TextStyle(
|
||||
color: context.color.onSurfaceVariant,
|
||||
fontSize: 12,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(bottom: 8, top: 8),
|
||||
child: Divider(),
|
||||
),
|
||||
const _ExampleLabel(),
|
||||
Text(
|
||||
context.lang.onboardingUserDiscoveryWhatOthersSee,
|
||||
style: TextStyle(
|
||||
color: context.color.onSurfaceVariant,
|
||||
fontSize: 12,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 3,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey, width: 0.5),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const AvatarIcon(fontSize: 14),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
userService.currentUser.username,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 3,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey, width: 0.5),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const AvatarIcon(fontSize: 14),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
userService.currentUser.username,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: buildFriendsListTextString(
|
||||
context,
|
||||
exampleUsers.sublist(
|
||||
0,
|
||||
state.threshold,
|
||||
),
|
||||
),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: buildFriendsListTextString(
|
||||
context,
|
||||
getExampleUsers(context).sublist(
|
||||
0,
|
||||
state.threshold,
|
||||
),
|
||||
style: const TextStyle(fontSize: 11),
|
||||
),
|
||||
style: const TextStyle(fontSize: 11),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const MockContactSuggestedActionsComp(),
|
||||
],
|
||||
),
|
||||
),
|
||||
const MockContactSuggestedActionsComp(),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
context.lang.onboardingUserDiscoveryWhatYouSee,
|
||||
style: TextStyle(
|
||||
color: context.color.onSurfaceVariant,
|
||||
fontSize: 12,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
context.lang.onboardingUserDiscoveryWhatYouSee,
|
||||
style: TextStyle(
|
||||
color: context.color.onSurfaceVariant,
|
||||
fontSize: 12,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 3,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey, width: 0.5),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const AvatarIcon(fontSize: 14),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'jane',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 13,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 3,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey, width: 0.5),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const AvatarIcon(fontSize: 14),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
context.lang.exampleJane,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 13,
|
||||
),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: buildFriendsListTextString(
|
||||
context,
|
||||
exampleUsers.sublist(
|
||||
0,
|
||||
state.threshold,
|
||||
),
|
||||
),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: buildFriendsListTextString(
|
||||
context,
|
||||
getExampleUsers(context).sublist(
|
||||
0,
|
||||
state.threshold,
|
||||
),
|
||||
style: const TextStyle(fontSize: 10),
|
||||
),
|
||||
style: const TextStyle(fontSize: 10),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const MockContactRequestActionsComp(),
|
||||
],
|
||||
),
|
||||
),
|
||||
const MockContactRequestActionsComp(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -442,3 +456,28 @@ class UserDiscoverySetupComp extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ExampleLabel extends StatelessWidget {
|
||||
const _ExampleLabel();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 12, bottom: 0),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey, width: 0.5),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
context.lang.onboardingExampleLabel,
|
||||
style: const TextStyle(fontSize: 10, color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ description: "twonly, a privacy-friendly way to connect with friends through sec
|
|||
|
||||
publish_to: 'none'
|
||||
|
||||
version: 0.2.8+117
|
||||
version: 0.2.9+118
|
||||
|
||||
environment:
|
||||
sdk: ^3.11.0
|
||||
|
|
|
|||
|
|
@ -10,12 +10,16 @@ impl FlutterUserDiscovery {
|
|||
public_key: Vec<u8>,
|
||||
share_promotion: bool,
|
||||
) -> Result<()> {
|
||||
Ok(get_twonly_flutter()?
|
||||
.user_discovery
|
||||
.get()
|
||||
.await
|
||||
tracing::info!("Rust bridge: initialize_or_update started");
|
||||
let twonly = get_twonly_flutter()?;
|
||||
tracing::info!("Rust bridge: getting user_discovery lock");
|
||||
let user_discovery = twonly.user_discovery.get().await;
|
||||
tracing::info!("Rust bridge: calling initialize_or_update on protocols");
|
||||
let res = user_discovery
|
||||
.initialize_or_update(threshold, user_id, public_key, share_promotion)
|
||||
.await?)
|
||||
.await;
|
||||
tracing::info!("Rust bridge: initialize_or_update on protocols finished");
|
||||
Ok(res?)
|
||||
}
|
||||
|
||||
pub async fn get_current_version() -> Result<Vec<u8>> {
|
||||
|
|
|
|||
|
|
@ -91,7 +91,9 @@ impl<Store: UserDiscoveryStore, Utils: UserDiscoveryUtils> UserDiscovery<Store,
|
|||
public_key: Vec<u8>,
|
||||
share_promotion: bool,
|
||||
) -> Result<()> {
|
||||
tracing::info!("Protocols: initialize_or_update started, getting config_lock");
|
||||
let config_lock = self.config_lock.lock().await;
|
||||
tracing::info!("Protocols: got config_lock, getting config from store");
|
||||
let mut config = match self.store.get_config().await {
|
||||
Ok(config) => {
|
||||
let mut config: UserDiscoveryConfig = serde_json::from_str(&config)?;
|
||||
|
|
@ -113,10 +115,12 @@ impl<Store: UserDiscoveryStore, Utils: UserDiscoveryUtils> UserDiscovery<Store,
|
|||
public_key,
|
||||
};
|
||||
|
||||
tracing::info!("Protocols: signing data");
|
||||
let signature = self.utils.sign_data(&signed_data.encode_to_vec()).await?;
|
||||
|
||||
debug_assert_eq!(threshold, config.threshold);
|
||||
|
||||
tracing::info!("Protocols: setting up announcements");
|
||||
let verification_shares = self
|
||||
.setup_announcements(&config, signed_data, signature)
|
||||
.await?;
|
||||
|
|
@ -128,8 +132,10 @@ impl<Store: UserDiscoveryStore, Utils: UserDiscoveryUtils> UserDiscovery<Store,
|
|||
config.verification_shares = verification_shares;
|
||||
config.share_promotion = share_promotion;
|
||||
|
||||
tracing::info!("Protocols: updating config in store");
|
||||
self.update_config(config, config_lock).await?;
|
||||
|
||||
tracing::info!("Protocols: initialize_or_update finished");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue