mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-05-25 02:32:11 +00:00
bump version and smaller bug fixes
This commit is contained in:
parent
6e95b977ac
commit
8f7346dfba
11 changed files with 228 additions and 212 deletions
|
|
@ -140,6 +140,9 @@ class UserData {
|
||||||
// So update data can be assigned. If set the user choose to participate.
|
// So update data can be assigned. If set the user choose to participate.
|
||||||
String? userStudyParticipantsToken;
|
String? userStudyParticipantsToken;
|
||||||
|
|
||||||
|
@JsonKey(defaultValue: 0)
|
||||||
|
int userStudyCountNewFriendsViaSuggestion = 0;
|
||||||
|
|
||||||
// Once a day the anonymous data is collected and send to the server
|
// Once a day the anonymous data is collected and send to the server
|
||||||
DateTime? lastUserStudyDataUpload;
|
DateTime? lastUserStudyDataUpload;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,8 @@ UserData _$UserDataFromJson(Map<String, dynamic> json) =>
|
||||||
json['askedForUserStudyPermission'] as bool? ?? false
|
json['askedForUserStudyPermission'] as bool? ?? false
|
||||||
..userStudyParticipantsToken =
|
..userStudyParticipantsToken =
|
||||||
json['userStudyParticipantsToken'] as String?
|
json['userStudyParticipantsToken'] as String?
|
||||||
|
..userStudyCountNewFriendsViaSuggestion =
|
||||||
|
(json['userStudyCountNewFriendsViaSuggestion'] as num?)?.toInt() ?? 0
|
||||||
..lastUserStudyDataUpload = json['lastUserStudyDataUpload'] == null
|
..lastUserStudyDataUpload = json['lastUserStudyDataUpload'] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json['lastUserStudyDataUpload'] as String)
|
: DateTime.parse(json['lastUserStudyDataUpload'] as String)
|
||||||
|
|
@ -151,6 +153,8 @@ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
|
||||||
'twonlySafeBackup': instance.twonlySafeBackup,
|
'twonlySafeBackup': instance.twonlySafeBackup,
|
||||||
'askedForUserStudyPermission': instance.askedForUserStudyPermission,
|
'askedForUserStudyPermission': instance.askedForUserStudyPermission,
|
||||||
'userStudyParticipantsToken': instance.userStudyParticipantsToken,
|
'userStudyParticipantsToken': instance.userStudyParticipantsToken,
|
||||||
|
'userStudyCountNewFriendsViaSuggestion':
|
||||||
|
instance.userStudyCountNewFriendsViaSuggestion,
|
||||||
'lastUserStudyDataUpload': instance.lastUserStudyDataUpload
|
'lastUserStudyDataUpload': instance.lastUserStudyDataUpload
|
||||||
?.toIso8601String(),
|
?.toIso8601String(),
|
||||||
'currentSetupPage': instance.currentSetupPage,
|
'currentSetupPage': instance.currentSetupPage,
|
||||||
|
|
|
||||||
|
|
@ -318,13 +318,6 @@ Future<void> handleEncryptedFile(String mediaId) async {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await twonlyDB.mediaFilesDao.updateMedia(
|
|
||||||
mediaId,
|
|
||||||
const MediaFilesCompanion(
|
|
||||||
downloadState: Value(DownloadState.downloaded),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final chacha20 = FlutterChacha20.poly1305Aead();
|
final chacha20 = FlutterChacha20.poly1305Aead();
|
||||||
final secretKeyData = SecretKeyData(
|
final secretKeyData = SecretKeyData(
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,9 @@ Future<void> handleUserStudyUpload() async {
|
||||||
'user_discovery_count_announced_users': udAllAnnouncedUsers.length,
|
'user_discovery_count_announced_users': udAllAnnouncedUsers.length,
|
||||||
'user_discovery_count_unknown_announced_users': udUnknownAnnouncedUsers,
|
'user_discovery_count_unknown_announced_users': udUnknownAnnouncedUsers,
|
||||||
|
|
||||||
|
'user_study_count_new_friends_via_suggestion':
|
||||||
|
userService.currentUser.userStudyCountNewFriendsViaSuggestion,
|
||||||
|
|
||||||
'accepted_contacts': contacts.where((c) => c.accepted).length,
|
'accepted_contacts': contacts.where((c) => c.accepted).length,
|
||||||
'verified_contacts': verifications.length,
|
'verified_contacts': verifications.length,
|
||||||
'verified_contacts_via_migrated_from_old_version': verifications.values
|
'verified_contacts_via_migrated_from_old_version': verifications.values
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,6 @@ class _FlameCounterWidgetState extends State<FlameCounterWidget> {
|
||||||
flameEmoji = '🎂';
|
flameEmoji = '🎂';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override with hourglass when the flame is about to expire
|
|
||||||
if (isExpiring) flameEmoji = '⌛';
|
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
if (widget.prefix) const SizedBox(width: 5),
|
if (widget.prefix) const SizedBox(width: 5),
|
||||||
|
|
@ -96,6 +93,13 @@ class _FlameCounterWidgetState extends State<FlameCounterWidget> {
|
||||||
emoji: flameEmoji,
|
emoji: flameEmoji,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (isExpiring)
|
||||||
|
const SizedBox(
|
||||||
|
height: 11,
|
||||||
|
child: EmojiAnimationComp(
|
||||||
|
emoji: '⌛',
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -203,8 +203,7 @@ class _UserListItem extends State<GroupListItemComp> {
|
||||||
await startDownloadMedia(mediaFile, true);
|
await startDownloadMedia(mediaFile, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mediaFile.downloadState! == DownloadState.ready ||
|
if (mediaFile.downloadState! == DownloadState.ready) {
|
||||||
mediaFile.downloadState! == DownloadState.downloaded) {
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
await context.push(
|
await context.push(
|
||||||
Routes.chatsMediaViewer,
|
Routes.chatsMediaViewer,
|
||||||
|
|
|
||||||
|
|
@ -88,9 +88,7 @@ class _ChatMediaEntryState extends State<ChatMediaEntry> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onTap() async {
|
Future<void> onTap() async {
|
||||||
if ((widget.mediaService.mediaFile.downloadState == DownloadState.ready ||
|
if ((widget.mediaService.mediaFile.downloadState == DownloadState.ready) &&
|
||||||
widget.mediaService.mediaFile.downloadState ==
|
|
||||||
DownloadState.downloaded) &&
|
|
||||||
widget.message.openedAt == null) {
|
widget.message.openedAt == null) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
await Navigator.push(
|
await Navigator.push(
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,7 @@ class MediaViewerView extends StatefulWidget {
|
||||||
State<MediaViewerView> createState() => _MediaViewerViewState();
|
State<MediaViewerView> createState() => _MediaViewerViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MediaViewerViewState extends State<MediaViewerView>
|
class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
with WidgetsBindingObserver {
|
|
||||||
Timer? nextMediaTimer;
|
Timer? nextMediaTimer;
|
||||||
Timer? progressTimer;
|
Timer? progressTimer;
|
||||||
|
|
||||||
|
|
@ -90,7 +89,6 @@ class _MediaViewerViewState extends State<MediaViewerView>
|
||||||
if (widget.initialMessage != null) {
|
if (widget.initialMessage != null) {
|
||||||
allMediaFiles = [widget.initialMessage!];
|
allMediaFiles = [widget.initialMessage!];
|
||||||
}
|
}
|
||||||
WidgetsBinding.instance.addObserver(this);
|
|
||||||
|
|
||||||
asyncLoadNextMedia(true);
|
asyncLoadNextMedia(true);
|
||||||
}
|
}
|
||||||
|
|
@ -105,23 +103,11 @@ class _MediaViewerViewState extends State<MediaViewerView>
|
||||||
final tmp = videoController;
|
final tmp = videoController;
|
||||||
videoController = null;
|
videoController = null;
|
||||||
tmp?.dispose();
|
tmp?.dispose();
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
final Mutex _messageUpdateLock = Mutex();
|
final Mutex _messageUpdateLock = Mutex();
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
|
||||||
if (state == AppLifecycleState.resumed) {
|
|
||||||
_messageUpdateLock.protect(() async {
|
|
||||||
if (currentMedia == null && allMediaFiles.isNotEmpty) {
|
|
||||||
await loadCurrentMediaFile();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _isViewActive() {
|
bool _isViewActive() {
|
||||||
return !AppState.isAppInBackground &&
|
return !AppState.isAppInBackground &&
|
||||||
(ModalRoute.of(context)?.isCurrent ?? false);
|
(ModalRoute.of(context)?.isCurrent ?? false);
|
||||||
|
|
@ -158,7 +144,7 @@ class _MediaViewerViewState extends State<MediaViewerView>
|
||||||
allMediaFiles.add(msg);
|
allMediaFiles.add(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setState(() {});
|
if (mounted) setState(() {});
|
||||||
if (firstRun) {
|
if (firstRun) {
|
||||||
firstRun = false;
|
firstRun = false;
|
||||||
await loadCurrentMediaFile();
|
await loadCurrentMediaFile();
|
||||||
|
|
@ -228,7 +214,13 @@ class _MediaViewerViewState extends State<MediaViewerView>
|
||||||
|
|
||||||
await downloadStateListener?.cancel();
|
await downloadStateListener?.cancel();
|
||||||
downloadStateListener = stream.listen((updated) async {
|
downloadStateListener = stream.listen((updated) async {
|
||||||
if (updated == null) return;
|
if (updated == null) {
|
||||||
|
// Media file record no longer exists — skip to next or exit rather
|
||||||
|
// than leaving the screen permanently black with no content/loader.
|
||||||
|
await downloadStateListener?.cancel();
|
||||||
|
await nextMediaOrExit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (updated.downloadState != DownloadState.ready) {
|
if (updated.downloadState != DownloadState.ready) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_showDownloadingLoader = true;
|
_showDownloadingLoader = true;
|
||||||
|
|
@ -238,7 +230,12 @@ class _MediaViewerViewState extends State<MediaViewerView>
|
||||||
final mediaFile = await twonlyDB.mediaFilesDao.getMediaFileById(
|
final mediaFile = await twonlyDB.mediaFilesDao.getMediaFileById(
|
||||||
allMediaFiles.first.mediaId!,
|
allMediaFiles.first.mediaId!,
|
||||||
);
|
);
|
||||||
if (mediaFile == null) return;
|
if (mediaFile == null) {
|
||||||
|
// DB record gone — skip to next or exit.
|
||||||
|
await downloadStateListener?.cancel();
|
||||||
|
await nextMediaOrExit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
await startDownloadMedia(mediaFile, true);
|
await startDownloadMedia(mediaFile, true);
|
||||||
unawaited(tryDownloadAllMediaFiles(force: true));
|
unawaited(tryDownloadAllMediaFiles(force: true));
|
||||||
}
|
}
|
||||||
|
|
@ -246,7 +243,12 @@ class _MediaViewerViewState extends State<MediaViewerView>
|
||||||
}
|
}
|
||||||
|
|
||||||
await downloadStateListener?.cancel();
|
await downloadStateListener?.cancel();
|
||||||
await handleNextDownloadedMedia(showTwonly);
|
try {
|
||||||
|
await handleNextDownloadedMedia(showTwonly);
|
||||||
|
} catch (e, st) {
|
||||||
|
Log.error('handleNextDownloadedMedia failed: $e\n$st');
|
||||||
|
await nextMediaOrExit();
|
||||||
|
}
|
||||||
// start downloading all the other possible missing media files.
|
// start downloading all the other possible missing media files.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -580,210 +582,213 @@ class _MediaViewerViewState extends State<MediaViewerView>
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Stack(
|
body: SafeArea(
|
||||||
fit: StackFit.expand,
|
child: Stack(
|
||||||
children: [
|
fit: StackFit.expand,
|
||||||
if (_showDownloadingLoader) _loader(),
|
children: [
|
||||||
if ((currentMedia != null || videoController != null) &&
|
if (_showDownloadingLoader) _loader(),
|
||||||
(canBeSeenUntil == null || progress >= 0))
|
if ((currentMedia != null || videoController != null) &&
|
||||||
GestureDetector(
|
(canBeSeenUntil == null || progress >= 0))
|
||||||
onTap: onTap,
|
GestureDetector(
|
||||||
onDoubleTap: (videoController == null) ? null : onTap,
|
onTap: onTap,
|
||||||
child: MediaViewSizingHelper(
|
onDoubleTap: (videoController == null) ? null : onTap,
|
||||||
bottomNavigation: bottomNavigation(),
|
child: MediaViewSizingHelper(
|
||||||
requiredHeight: 55,
|
bottomNavigation: bottomNavigation(),
|
||||||
child: Stack(
|
requiredHeight: 55,
|
||||||
children: [
|
child: Stack(
|
||||||
if (videoController != null)
|
children: [
|
||||||
Positioned.fill(
|
if (videoController != null)
|
||||||
child: PhotoView.customChild(
|
Positioned.fill(
|
||||||
initialScale: PhotoViewComputedScale.contained,
|
child: PhotoView.customChild(
|
||||||
minScale: PhotoViewComputedScale.contained,
|
initialScale: PhotoViewComputedScale.contained,
|
||||||
child: VideoPlayerHelper(
|
minScale: PhotoViewComputedScale.contained,
|
||||||
controller: videoController!,
|
child: VideoPlayerHelper(
|
||||||
onDoubleTap: onTap,
|
controller: videoController!,
|
||||||
|
onDoubleTap: onTap,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else if (currentMedia != null &&
|
||||||
|
(currentMedia!.mediaFile.type == MediaType.image ||
|
||||||
|
currentMedia!.mediaFile.type == MediaType.gif))
|
||||||
|
Positioned.fill(
|
||||||
|
child: PhotoView(
|
||||||
|
imageProvider: FileImage(
|
||||||
|
currentMedia!.tempPath,
|
||||||
|
),
|
||||||
|
initialScale: PhotoViewComputedScale.contained,
|
||||||
|
minScale: PhotoViewComputedScale.contained,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
],
|
||||||
else if (currentMedia != null &&
|
),
|
||||||
currentMedia!.mediaFile.type == MediaType.image ||
|
),
|
||||||
currentMedia!.mediaFile.type == MediaType.gif)
|
),
|
||||||
Positioned.fill(
|
if (displayTwonlyPresent)
|
||||||
child: PhotoView(
|
Positioned.fill(
|
||||||
imageProvider: FileImage(
|
child: GestureDetector(
|
||||||
currentMedia!.tempPath,
|
onTap: () => loadCurrentMediaFile(showTwonly: true),
|
||||||
),
|
child: Column(
|
||||||
initialScale: PhotoViewComputedScale.contained,
|
children: [
|
||||||
minScale: PhotoViewComputedScale.contained,
|
Expanded(
|
||||||
|
child: Lottie.asset(
|
||||||
|
'assets/animations/present.lottie.lottie',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
Container(
|
||||||
),
|
padding: const EdgeInsets.only(bottom: 200),
|
||||||
),
|
child: Text(context.lang.mediaViewerTwonlyTapToOpen),
|
||||||
),
|
|
||||||
if (displayTwonlyPresent)
|
|
||||||
Positioned.fill(
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () => loadCurrentMediaFile(showTwonly: true),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Lottie.asset(
|
|
||||||
'assets/animations/present.lottie.lottie',
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
Container(
|
),
|
||||||
padding: const EdgeInsets.only(bottom: 200),
|
|
||||||
child: Text(context.lang.mediaViewerTwonlyTapToOpen),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
left: 10,
|
|
||||||
top: 10,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.close, size: 30),
|
|
||||||
color: Colors.white,
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (currentMedia != null &&
|
|
||||||
currentMedia?.mediaFile.downloadState != DownloadState.ready)
|
|
||||||
Positioned.fill(child: _loader()),
|
|
||||||
if (canBeSeenUntil != null || progress >= 0)
|
|
||||||
Positioned(
|
Positioned(
|
||||||
right: 20,
|
left: 10,
|
||||||
top: 27,
|
top: 10,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
IconButton(
|
||||||
width: 20,
|
icon: const Icon(Icons.close, size: 30),
|
||||||
height: 20,
|
color: Colors.white,
|
||||||
child: CircularProgressIndicator(
|
onPressed: () => Navigator.pop(context),
|
||||||
value: progress,
|
|
||||||
strokeWidth: 2,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
if (currentMedia != null &&
|
||||||
top: 10,
|
currentMedia?.mediaFile.downloadState != DownloadState.ready)
|
||||||
left: showSendTextMessageInput ? 0 : null,
|
Positioned.fill(child: _loader()),
|
||||||
right: showSendTextMessageInput ? 0 : 15,
|
if (canBeSeenUntil != null || progress >= 0)
|
||||||
child: Text(
|
Positioned(
|
||||||
_currentMediaSender,
|
right: 20,
|
||||||
textAlign: TextAlign.center,
|
top: 27,
|
||||||
style: TextStyle(
|
|
||||||
fontSize: showSendTextMessageInput ? 24 : 14,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: showSendTextMessageInput
|
|
||||||
? null
|
|
||||||
: const Color.fromARGB(255, 126, 126, 126),
|
|
||||||
shadows: const [
|
|
||||||
Shadow(
|
|
||||||
color: Color.fromARGB(122, 0, 0, 0),
|
|
||||||
blurRadius: 5,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (showSendTextMessageInput)
|
|
||||||
Positioned(
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
child: Container(
|
|
||||||
color: context.color.surface,
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
bottom: 10,
|
|
||||||
left: 20,
|
|
||||||
right: 20,
|
|
||||||
top: 10,
|
|
||||||
),
|
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
SizedBox(
|
||||||
icon: const FaIcon(FontAwesomeIcons.xmark),
|
width: 20,
|
||||||
onPressed: () {
|
height: 20,
|
||||||
setState(() {
|
child: CircularProgressIndicator(
|
||||||
showShortReactions = false;
|
value: progress,
|
||||||
showSendTextMessageInput = false;
|
strokeWidth: 2,
|
||||||
});
|
),
|
||||||
},
|
|
||||||
),
|
),
|
||||||
Expanded(
|
],
|
||||||
child: TextField(
|
),
|
||||||
autofocus: true,
|
),
|
||||||
controller: textMessageController,
|
Positioned(
|
||||||
onChanged: (value) async {
|
top: 10,
|
||||||
await twonlyDB.groupsDao.updateGroup(
|
left: showSendTextMessageInput ? 0 : null,
|
||||||
widget.group.groupId,
|
right: showSendTextMessageInput ? 0 : 15,
|
||||||
GroupsCompanion(
|
child: Text(
|
||||||
draftMessage: Value(textMessageController.text),
|
_currentMediaSender,
|
||||||
),
|
textAlign: TextAlign.center,
|
||||||
);
|
style: TextStyle(
|
||||||
|
fontSize: showSendTextMessageInput ? 24 : 14,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: showSendTextMessageInput
|
||||||
|
? null
|
||||||
|
: const Color.fromARGB(255, 126, 126, 126),
|
||||||
|
shadows: const [
|
||||||
|
Shadow(
|
||||||
|
color: Color.fromARGB(122, 0, 0, 0),
|
||||||
|
blurRadius: 5,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (showSendTextMessageInput)
|
||||||
|
Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Container(
|
||||||
|
color: context.color.surface,
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
bottom: 10,
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
top: 10,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: const FaIcon(FontAwesomeIcons.xmark),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
showShortReactions = false;
|
||||||
|
showSendTextMessageInput = false;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onEditingComplete: () {
|
),
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
autofocus: true,
|
||||||
|
controller: textMessageController,
|
||||||
|
onChanged: (value) async {
|
||||||
|
await twonlyDB.groupsDao.updateGroup(
|
||||||
|
widget.group.groupId,
|
||||||
|
GroupsCompanion(
|
||||||
|
draftMessage: Value(textMessageController.text),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onEditingComplete: () {
|
||||||
|
setState(() {
|
||||||
|
showSendTextMessageInput = false;
|
||||||
|
showShortReactions = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
decoration: inputTextMessageDeco(
|
||||||
|
context,
|
||||||
|
context.lang.chatListDetailInput,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: const FaIcon(FontAwesomeIcons.solidPaperPlane),
|
||||||
|
onPressed: () async {
|
||||||
|
if (textMessageController.text.isNotEmpty) {
|
||||||
|
await insertAndSendTextMessage(
|
||||||
|
widget.group.groupId,
|
||||||
|
textMessageController.text,
|
||||||
|
currentMessage!.messageId,
|
||||||
|
);
|
||||||
|
textMessageController.clear();
|
||||||
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
showSendTextMessageInput = false;
|
showSendTextMessageInput = false;
|
||||||
showShortReactions = false;
|
showShortReactions = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
decoration: inputTextMessageDeco(
|
|
||||||
context,
|
|
||||||
context.lang.chatListDetailInput,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
IconButton(
|
),
|
||||||
icon: const FaIcon(FontAwesomeIcons.solidPaperPlane),
|
|
||||||
onPressed: () async {
|
|
||||||
if (textMessageController.text.isNotEmpty) {
|
|
||||||
await insertAndSendTextMessage(
|
|
||||||
widget.group.groupId,
|
|
||||||
textMessageController.text,
|
|
||||||
currentMessage!.messageId,
|
|
||||||
);
|
|
||||||
textMessageController.clear();
|
|
||||||
}
|
|
||||||
setState(() {
|
|
||||||
showSendTextMessageInput = false;
|
|
||||||
showShortReactions = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (currentMessage != null)
|
||||||
|
AdditionalMessageContent(currentMessage!),
|
||||||
|
if (currentMedia != null)
|
||||||
|
ReactionButtons(
|
||||||
|
show: showShortReactions,
|
||||||
|
textInputFocused: showSendTextMessageInput,
|
||||||
|
mediaViewerDistanceFromBottom: mediaViewerDistanceFromBottom,
|
||||||
|
groupId: widget.group.groupId,
|
||||||
|
messageId: currentMessage!.messageId,
|
||||||
|
emojiKey: emojiKey,
|
||||||
|
hide: () {
|
||||||
|
setState(() {
|
||||||
|
showShortReactions = false;
|
||||||
|
showSendTextMessageInput = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Positioned.fill(
|
||||||
|
child: EmojiFloatWidget(key: emojiKey),
|
||||||
),
|
),
|
||||||
if (currentMessage != null) AdditionalMessageContent(currentMessage!),
|
],
|
||||||
if (currentMedia != null)
|
),
|
||||||
ReactionButtons(
|
|
||||||
show: showShortReactions,
|
|
||||||
textInputFocused: showSendTextMessageInput,
|
|
||||||
mediaViewerDistanceFromBottom: mediaViewerDistanceFromBottom,
|
|
||||||
groupId: widget.group.groupId,
|
|
||||||
messageId: currentMessage!.messageId,
|
|
||||||
emojiKey: emojiKey,
|
|
||||||
hide: () {
|
|
||||||
setState(() {
|
|
||||||
showShortReactions = false;
|
|
||||||
showSendTextMessageInput = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Positioned.fill(
|
|
||||||
child: EmojiFloatWidget(key: emojiKey),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/database/daos/user_discovery.dao.dart';
|
import 'package:twonly/src/database/daos/user_discovery.dao.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/services/api/utils.api.dart';
|
import 'package:twonly/src/services/api/utils.api.dart';
|
||||||
|
import 'package:twonly/src/services/user.service.dart';
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/visual/components/avatar_icon.comp.dart';
|
import 'package:twonly/src/visual/components/avatar_icon.comp.dart';
|
||||||
|
|
@ -66,6 +67,10 @@ class FriendSuggestionsComp extends StatelessWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (added > 0) await importSignalContactAndCreateRequest(userdata);
|
if (added > 0) await importSignalContactAndCreateRequest(userdata);
|
||||||
|
|
||||||
|
await UserService.update(
|
||||||
|
(u) => u.userStudyCountNewFriendsViaSuggestion += 1,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _hideAnnouncedUser(int userId) async {
|
Future<void> _hideAnnouncedUser(int userId) async {
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ class UserDiscoverySetupComp extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
context.lang.onboardingUserDiscoveryShareFriends,
|
context.lang.onboardingUserDiscoveryShareFriends,
|
||||||
style: Theme.of(context).textTheme.headlineSmall,
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
|
|
||||||
|
|
@ -255,6 +256,7 @@ class UserDiscoverySetupComp extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
context.lang.onboardingUserDiscoveryLetFriendsFindYou,
|
context.lang.onboardingUserDiscoveryLetFriendsFindYou,
|
||||||
style: Theme.of(context).textTheme.headlineSmall,
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ description: "twonly, a privacy-friendly way to connect with friends through sec
|
||||||
|
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 0.2.0+109
|
version: 0.2.1+110
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.11.0
|
sdk: ^3.11.0
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue