mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 13:08:42 +00:00
add barcode scanner and remove tutorial
This commit is contained in:
parent
9667ea21b6
commit
76b617e63a
13 changed files with 73 additions and 277 deletions
0
.gitmodules
vendored
Normal file
0
.gitmodules
vendored
Normal file
|
|
@ -1,9 +1,15 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
the Flutter tool needs it to communicate with the running application
|
the Flutter tool needs it to communicate with the running application
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
-->
|
-->
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<application android:usesCleartextTraffic="true" >
|
<application android:usesCleartextTraffic="true" >
|
||||||
|
<!-- // https://github.com/juliansteenbakker/mobile_scanner/issues/553 -->
|
||||||
|
<meta-data android:name="firebase_performance_collection_deactivated" android:value="true" />
|
||||||
|
<!-- <service
|
||||||
|
android:name="com.google.android.datatransport.runtime.scheduling.jobscheduling.JobInfoSchedulerService"
|
||||||
|
tools:node="remove">
|
||||||
|
</service> -->
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
|
||||||
<application
|
<application
|
||||||
android:label="twonly"
|
android:label="twonly"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
|
@ -33,6 +33,12 @@
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
|
|
||||||
|
<!-- // https://github.com/juliansteenbakker/mobile_scanner/issues/553 -->
|
||||||
|
<meta-data android:name="firebase_performance_collection_deactivated" android:value="true" />
|
||||||
|
<service
|
||||||
|
android:name="com.google.android.datatransport.runtime.scheduling.jobscheduling.JobInfoSchedulerService"
|
||||||
|
tools:node="remove">
|
||||||
|
</service>
|
||||||
|
|
||||||
<!-- <service
|
<!-- <service
|
||||||
android:name="com.pravera.flutter_foreground_task.service.ForegroundService"
|
android:name="com.pravera.flutter_foreground_task.service.ForegroundService"
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,5 @@
|
||||||
<uses-permission android:name="android.permission.CAMERA"/>
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
<application android:usesCleartextTraffic="true" >
|
<application android:usesCleartextTraffic="true" >
|
||||||
</application>
|
</application>
|
||||||
|
<meta-data android:name="firebase_performance_collection_deactivated" android:value="true" />
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -85,5 +85,9 @@
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
|
<!--Disable Firebase Telemetry-->
|
||||||
|
<key>firebase_performance_collection_deactivated</key>
|
||||||
|
<true/>
|
||||||
|
<!--...-->
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
||||||
|
|
@ -23,24 +23,26 @@ class BarcodeDetectorPainter extends CustomPainter {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
final Paint paint = Paint()
|
final paint = Paint()
|
||||||
..style = PaintingStyle.stroke
|
..style = PaintingStyle.stroke
|
||||||
..strokeWidth = 3.0
|
..strokeWidth = 3.0
|
||||||
..color = Colors.lightGreenAccent;
|
..color = Colors.lightGreenAccent;
|
||||||
|
|
||||||
final Paint background = Paint()..color = Color(0x99000000);
|
final background = Paint()..color = const Color(0x99000000);
|
||||||
|
|
||||||
for (final Barcode barcode in barcodes) {
|
for (final barcode in barcodes) {
|
||||||
final ParagraphBuilder builder = ParagraphBuilder(
|
final builder = ParagraphBuilder(
|
||||||
ParagraphStyle(
|
ParagraphStyle(
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
textDirection: TextDirection.ltr),
|
textDirection: TextDirection.ltr,
|
||||||
);
|
),
|
||||||
builder.pushStyle(
|
)
|
||||||
ui.TextStyle(color: Colors.lightGreenAccent, background: background));
|
..pushStyle(
|
||||||
builder.addText('${barcode.displayValue}');
|
ui.TextStyle(color: Colors.lightGreenAccent, background: background),
|
||||||
builder.pop();
|
)
|
||||||
|
..addText('${barcode.displayValue}')
|
||||||
|
..pop();
|
||||||
|
|
||||||
final left = translateX(
|
final left = translateX(
|
||||||
barcode.boundingBox.left,
|
barcode.boundingBox.left,
|
||||||
|
|
@ -77,16 +79,16 @@ class BarcodeDetectorPainter extends CustomPainter {
|
||||||
// paint,
|
// paint,
|
||||||
// );
|
// );
|
||||||
|
|
||||||
final List<Offset> cornerPoints = <Offset>[];
|
final cornerPoints = <Offset>[];
|
||||||
for (final point in barcode.cornerPoints) {
|
for (final point in barcode.cornerPoints) {
|
||||||
final double x = translateX(
|
final x = translateX(
|
||||||
point.x.toDouble(),
|
point.x.toDouble(),
|
||||||
size,
|
size,
|
||||||
imageSize,
|
imageSize,
|
||||||
rotation,
|
rotation,
|
||||||
cameraLensDirection,
|
cameraLensDirection,
|
||||||
);
|
);
|
||||||
final double y = translateY(
|
final y = translateY(
|
||||||
point.y.toDouble(),
|
point.y.toDouble(),
|
||||||
size,
|
size,
|
||||||
imageSize,
|
imageSize,
|
||||||
|
|
@ -99,19 +101,22 @@ class BarcodeDetectorPainter extends CustomPainter {
|
||||||
|
|
||||||
// Add the first point to close the polygon
|
// Add the first point to close the polygon
|
||||||
cornerPoints.add(cornerPoints.first);
|
cornerPoints.add(cornerPoints.first);
|
||||||
canvas.drawPoints(PointMode.polygon, cornerPoints, paint);
|
canvas
|
||||||
|
..drawPoints(PointMode.polygon, cornerPoints, paint)
|
||||||
canvas.drawParagraph(
|
..drawParagraph(
|
||||||
builder.build()
|
builder.build()
|
||||||
..layout(ParagraphConstraints(
|
..layout(
|
||||||
|
ParagraphConstraints(
|
||||||
width: (right - left).abs(),
|
width: (right - left).abs(),
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
Offset(
|
Offset(
|
||||||
Platform.isAndroid &&
|
Platform.isAndroid &&
|
||||||
cameraLensDirection == CameraLensDirection.front
|
cameraLensDirection == CameraLensDirection.front
|
||||||
? right
|
? right
|
||||||
: left,
|
: left,
|
||||||
top),
|
top,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ double translateX(
|
||||||
switch (cameraLensDirection) {
|
switch (cameraLensDirection) {
|
||||||
case CameraLensDirection.back:
|
case CameraLensDirection.back:
|
||||||
return x * canvasSize.width / imageSize.width;
|
return x * canvasSize.width / imageSize.width;
|
||||||
|
// ignore: no_default_cases
|
||||||
default:
|
default:
|
||||||
return canvasSize.width - x * canvasSize.width / imageSize.width;
|
return canvasSize.width - x * canvasSize.width / imageSize.width;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import 'package:twonly/src/views/settings/help/changelog.view.dart';
|
||||||
import 'package:twonly/src/views/settings/profile/profile.view.dart';
|
import 'package:twonly/src/views/settings/profile/profile.view.dart';
|
||||||
import 'package:twonly/src/views/settings/settings_main.view.dart';
|
import 'package:twonly/src/views/settings/settings_main.view.dart';
|
||||||
import 'package:twonly/src/views/settings/subscription/subscription.view.dart';
|
import 'package:twonly/src/views/settings/subscription/subscription.view.dart';
|
||||||
import 'package:twonly/src/views/tutorial/tutorials.dart';
|
|
||||||
|
|
||||||
class ChatListView extends StatefulWidget {
|
class ChatListView extends StatefulWidget {
|
||||||
const ChatListView({super.key});
|
const ChatListView({super.key});
|
||||||
|
|
@ -38,7 +37,6 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
List<Group> _groupsArchived = [];
|
List<Group> _groupsArchived = [];
|
||||||
|
|
||||||
GlobalKey searchForOtherUsers = GlobalKey();
|
GlobalKey searchForOtherUsers = GlobalKey();
|
||||||
Timer? tutorial;
|
|
||||||
bool showFeedbackShortcut = false;
|
bool showFeedbackShortcut = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -58,16 +56,6 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
tutorial = Timer(const Duration(seconds: 1), () async {
|
|
||||||
tutorial = null;
|
|
||||||
if (!mounted) return;
|
|
||||||
await showChatListTutorialSearchOtherUsers(context, searchForOtherUsers);
|
|
||||||
if (!mounted) return;
|
|
||||||
// if (_groupsNotPinned.isNotEmpty) {
|
|
||||||
// await showChatListTutorialContextMenu(context, firstUserListItemKey);
|
|
||||||
// }
|
|
||||||
});
|
|
||||||
|
|
||||||
final changeLog = await rootBundle.loadString('CHANGELOG.md');
|
final changeLog = await rootBundle.loadString('CHANGELOG.md');
|
||||||
final changeLogHash =
|
final changeLogHash =
|
||||||
(await compute(Sha256().hash, changeLog.codeUnits)).bytes;
|
(await compute(Sha256().hash, changeLog.codeUnits)).bytes;
|
||||||
|
|
@ -97,7 +85,6 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
tutorial?.cancel();
|
|
||||||
_contactsSub.cancel();
|
_contactsSub.cancel();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import 'package:twonly/src/views/components/flame.dart';
|
||||||
import 'package:twonly/src/views/components/verified_shield.dart';
|
import 'package:twonly/src/views/components/verified_shield.dart';
|
||||||
import 'package:twonly/src/views/contact/contact.view.dart';
|
import 'package:twonly/src/views/contact/contact.view.dart';
|
||||||
import 'package:twonly/src/views/groups/group.view.dart';
|
import 'package:twonly/src/views/groups/group.view.dart';
|
||||||
import 'package:twonly/src/views/tutorial/tutorials.dart';
|
|
||||||
|
|
||||||
Color getMessageColor(Message message) {
|
Color getMessageColor(Message message) {
|
||||||
return (message.senderId == null)
|
return (message.senderId == null)
|
||||||
|
|
@ -89,7 +88,6 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
||||||
Message? quotesMessage;
|
Message? quotesMessage;
|
||||||
GlobalKey verifyShieldKey = GlobalKey();
|
GlobalKey verifyShieldKey = GlobalKey();
|
||||||
late FocusNode textFieldFocus;
|
late FocusNode textFieldFocus;
|
||||||
Timer? tutorial;
|
|
||||||
final ItemScrollController itemScrollController = ItemScrollController();
|
final ItemScrollController itemScrollController = ItemScrollController();
|
||||||
int? focusedScrollItem;
|
int? focusedScrollItem;
|
||||||
|
|
||||||
|
|
@ -99,12 +97,6 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
||||||
group = widget.group;
|
group = widget.group;
|
||||||
textFieldFocus = FocusNode();
|
textFieldFocus = FocusNode();
|
||||||
initStreams();
|
initStreams();
|
||||||
|
|
||||||
tutorial = Timer(const Duration(seconds: 1), () async {
|
|
||||||
tutorial = null;
|
|
||||||
if (!mounted) return;
|
|
||||||
await showVerifyShieldTutorial(context, verifyShieldKey);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -114,7 +106,6 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
||||||
contactSub?.cancel();
|
contactSub?.cancel();
|
||||||
groupActionsSub?.cancel();
|
groupActionsSub?.cancel();
|
||||||
lastOpenedMessageByContactSub?.cancel();
|
lastOpenedMessageByContactSub?.cancel();
|
||||||
tutorial?.cancel();
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ class HomeViewState extends State<HomeView> {
|
||||||
CustomPaint? _customPaint;
|
CustomPaint? _customPaint;
|
||||||
String? _text;
|
String? _text;
|
||||||
|
|
||||||
final _orientations = {
|
final Map<DeviceOrientation, int> _orientations = {
|
||||||
DeviceOrientation.portraitUp: 0,
|
DeviceOrientation.portraitUp: 0,
|
||||||
DeviceOrientation.landscapeLeft: 90,
|
DeviceOrientation.landscapeLeft: 90,
|
||||||
DeviceOrientation.portraitDown: 180,
|
DeviceOrientation.portraitDown: 180,
|
||||||
|
|
|
||||||
|
|
@ -62,26 +62,26 @@ class _HelpViewState extends State<HelpView> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
// ListTile(
|
||||||
title: Text(context.lang.settingsResetTutorials),
|
// title: Text(context.lang.settingsResetTutorials),
|
||||||
subtitle: Text(
|
// subtitle: Text(
|
||||||
context.lang.settingsResetTutorialsDesc,
|
// context.lang.settingsResetTutorialsDesc,
|
||||||
style: const TextStyle(fontSize: 12),
|
// style: const TextStyle(fontSize: 12),
|
||||||
),
|
// ),
|
||||||
onTap: () async {
|
// onTap: () async {
|
||||||
await updateUserdata((user) {
|
// await updateUserdata((user) {
|
||||||
user.tutorialDisplayed = [];
|
// user.tutorialDisplayed = [];
|
||||||
return user;
|
// return user;
|
||||||
});
|
// });
|
||||||
if (!context.mounted) return;
|
// if (!context.mounted) return;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
// ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
// SnackBar(
|
||||||
content: Text(context.lang.settingsResetTutorialsSuccess),
|
// content: Text(context.lang.settingsResetTutorialsSuccess),
|
||||||
duration: const Duration(seconds: 3),
|
// duration: const Duration(seconds: 3),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(context.lang.allowErrorTracking),
|
title: Text(context.lang.allowErrorTracking),
|
||||||
|
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
|
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
|
||||||
import 'package:twonly/src/utils/storage.dart';
|
|
||||||
|
|
||||||
Future<void> showTutorial(
|
|
||||||
BuildContext context,
|
|
||||||
List<TargetFocus> targets,
|
|
||||||
) async {
|
|
||||||
final completer = Completer<dynamic>();
|
|
||||||
TutorialCoachMark(
|
|
||||||
targets: targets,
|
|
||||||
colorShadow: context.color.primary,
|
|
||||||
textSkip: context.lang.ok,
|
|
||||||
alignSkip: Alignment.bottomCenter,
|
|
||||||
textStyleSkip: const TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 20,
|
|
||||||
),
|
|
||||||
onSkip: () {
|
|
||||||
completer.complete();
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
onFinish: () {
|
|
||||||
completer.complete();
|
|
||||||
},
|
|
||||||
).show(context: context);
|
|
||||||
|
|
||||||
await completer.future;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> checkIfTutorialAlreadyShown(String tutorialId) async {
|
|
||||||
final user = await getUser();
|
|
||||||
if (user == null) return true;
|
|
||||||
user.tutorialDisplayed ??= [];
|
|
||||||
if (user.tutorialDisplayed!.contains(tutorialId)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
user.tutorialDisplayed!.add(tutorialId);
|
|
||||||
|
|
||||||
await updateUserdata((u) {
|
|
||||||
u.tutorialDisplayed = user.tutorialDisplayed;
|
|
||||||
return u;
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
TargetFocus getTargetFocus(
|
|
||||||
BuildContext context,
|
|
||||||
GlobalKey key,
|
|
||||||
String title,
|
|
||||||
String body,
|
|
||||||
) {
|
|
||||||
final renderBox = key.currentContext!.findRenderObject()! as RenderBox;
|
|
||||||
final position = renderBox.localToGlobal(Offset.zero);
|
|
||||||
final screenHeight = MediaQuery.of(context).size.height;
|
|
||||||
final centerY = screenHeight / 2;
|
|
||||||
|
|
||||||
double top = 0;
|
|
||||||
double bottom = 0;
|
|
||||||
|
|
||||||
if (position.dy < centerY) {
|
|
||||||
bottom = 0;
|
|
||||||
top = position.dy;
|
|
||||||
} else {
|
|
||||||
bottom = centerY;
|
|
||||||
top = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TargetFocus(
|
|
||||||
identify: title,
|
|
||||||
keyTarget: key,
|
|
||||||
contents: [
|
|
||||||
TargetContent(
|
|
||||||
align: ContentAlign.custom,
|
|
||||||
customPosition: CustomTargetContentPosition(
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
top: top,
|
|
||||||
bottom: bottom,
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
title,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.black,
|
|
||||||
fontSize: 20,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 10),
|
|
||||||
child: Text(
|
|
||||||
body,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:mutex/mutex.dart';
|
|
||||||
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
|
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
|
||||||
import 'package:twonly/src/views/tutorial/show_tutorial.dart';
|
|
||||||
|
|
||||||
final lockDisplayTutorial = Mutex();
|
|
||||||
|
|
||||||
Future<void> showChatListTutorialSearchOtherUsers(
|
|
||||||
BuildContext context,
|
|
||||||
GlobalKey searchForOtherUsers,
|
|
||||||
) async {
|
|
||||||
await lockDisplayTutorial.protect(() async {
|
|
||||||
if (await checkIfTutorialAlreadyShown('chat_list:search_users')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!context.mounted) return;
|
|
||||||
final targets = <TargetFocus>[
|
|
||||||
getTargetFocus(
|
|
||||||
context,
|
|
||||||
searchForOtherUsers,
|
|
||||||
context.lang.tutorialChatListSearchUsersTitle,
|
|
||||||
context.lang.tutorialChatListSearchUsersDesc,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
await showTutorial(context, targets);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> showChatListTutorialContextMenu(
|
|
||||||
BuildContext context,
|
|
||||||
GlobalKey firstUserListItemKey,
|
|
||||||
) async {
|
|
||||||
await lockDisplayTutorial.protect(() async {
|
|
||||||
if (await checkIfTutorialAlreadyShown('chat_list:context_menu')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!context.mounted) return;
|
|
||||||
final targets = <TargetFocus>[
|
|
||||||
getTargetFocus(
|
|
||||||
context,
|
|
||||||
firstUserListItemKey,
|
|
||||||
context.lang.tutorialChatListContextMenuTitle,
|
|
||||||
context.lang.tutorialChatListContextMenuDesc,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
await showTutorial(context, targets);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> showVerifyShieldTutorial(
|
|
||||||
BuildContext context,
|
|
||||||
GlobalKey firstUserListItemKey,
|
|
||||||
) async {
|
|
||||||
await lockDisplayTutorial.protect(() async {
|
|
||||||
if (await checkIfTutorialAlreadyShown('chat_messages:verify_shield')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!context.mounted) return;
|
|
||||||
final targets = <TargetFocus>[
|
|
||||||
getTargetFocus(
|
|
||||||
context,
|
|
||||||
firstUserListItemKey,
|
|
||||||
context.lang.tutorialChatMessagesVerifyShieldTitle,
|
|
||||||
context.lang.tutorialChatMessagesVerifyShieldDesc,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
await showTutorial(context, targets);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> showReopenMediaFilesTutorial(
|
|
||||||
BuildContext context,
|
|
||||||
GlobalKey firstUserListItemKey,
|
|
||||||
) async {
|
|
||||||
await lockDisplayTutorial.protect(() async {
|
|
||||||
if (await checkIfTutorialAlreadyShown('chat_messages:reopen_message')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!context.mounted) return;
|
|
||||||
final targets = <TargetFocus>[
|
|
||||||
getTargetFocus(
|
|
||||||
context,
|
|
||||||
firstUserListItemKey,
|
|
||||||
context.lang.tutorialChatMessagesReopenMessageTitle,
|
|
||||||
context.lang.tutorialChatMessagesReopenMessageDesc,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
await showTutorial(context, targets);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue