mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 11:18:41 +00:00
some more bug fixes
This commit is contained in:
parent
d55572f8bc
commit
da39cdbb81
13 changed files with 171 additions and 157 deletions
8
.github/workflows/release_github.yml
vendored
8
.github/workflows/release_github.yml
vendored
|
|
@ -1,14 +1,12 @@
|
|||
name: Publish (Android)
|
||||
name: Publish on Github
|
||||
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
# paths:
|
||||
# - lib/**
|
||||
# - pubspec.lock
|
||||
# - pubspec.yaml
|
||||
paths:
|
||||
- pubspec.yaml
|
||||
|
||||
jobs:
|
||||
build_and_publish:
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ late ApiService apiService;
|
|||
late TwonlyDatabase twonlyDB;
|
||||
|
||||
List<CameraDescription> gCameras = <CameraDescription>[];
|
||||
bool gIsDemoUser = false;
|
||||
|
||||
// The following global function can be called from anywhere to update
|
||||
// the UI when something changed. The callbacks will be set by
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ Future<ErrorCode?> isAllowedToSend() async {
|
|||
var todaysImageCounter = user.todaysImageCounter;
|
||||
if (user.lastImageSend != null && user.todaysImageCounter != null) {
|
||||
if (isToday(user.lastImageSend!)) {
|
||||
if (user.todaysImageCounter == 3) {
|
||||
if (user.todaysImageCounter == 10) {
|
||||
return ErrorCode.PlanLimitReached;
|
||||
}
|
||||
todaysImageCounter = user.todaysImageCounter! + 1;
|
||||
|
|
|
|||
|
|
@ -157,10 +157,6 @@ Future<void> encryptAndSendMessageAsync(
|
|||
MessageJson msg, {
|
||||
PushNotification? pushNotification,
|
||||
}) async {
|
||||
if (gIsDemoUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
Uint8List? pushData;
|
||||
if (pushNotification != null) {
|
||||
pushData = await getPushData(userId, pushNotification);
|
||||
|
|
|
|||
|
|
@ -246,13 +246,17 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
}
|
||||
|
||||
await widget.cameraController?.pausePreview();
|
||||
if (!mounted) return;
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
await widget.cameraController?.setFlashMode(
|
||||
widget.selectedCameraDetails.isFlashOn
|
||||
? FlashMode.always
|
||||
: FlashMode.off);
|
||||
if (!mounted) return;
|
||||
if (Platform.isIOS) {
|
||||
// android has a problem with this. Flash is turned off in the pausePreview function.
|
||||
await widget.cameraController?.setFlashMode(FlashMode.off);
|
||||
}
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
imageBytes = widget.screenshotController
|
||||
.capture(pixelRatio: MediaQuery.of(context).devicePixelRatio);
|
||||
|
|
@ -260,6 +264,9 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
if (await pushMediaEditor(imageBytes, null)) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
sharePreviewIsShown = false;
|
||||
});
|
||||
}
|
||||
|
||||
Future<bool> pushMediaEditor(
|
||||
|
|
@ -404,17 +411,22 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
videoRecordingTimer?.cancel();
|
||||
videoRecordingTimer = null;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
videoRecordingStarted = null;
|
||||
isVideoRecording = false;
|
||||
});
|
||||
|
||||
if (widget.cameraController == null ||
|
||||
!widget.cameraController!.value.isRecordingVideo) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setState(() {
|
||||
videoRecordingStarted = null;
|
||||
isVideoRecording = false;
|
||||
sharePreviewIsShown = true;
|
||||
});
|
||||
|
||||
try {
|
||||
File? videoPathFile;
|
||||
final videoPath = await widget.cameraController?.stopVideoRecording();
|
||||
if (videoPath != null) {
|
||||
|
|
@ -553,22 +565,6 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
setState(() {});
|
||||
},
|
||||
),
|
||||
// if (!isFront)
|
||||
// ActionButton(
|
||||
// Icons.hd_rounded,
|
||||
// tooltipText: context.lang.toggleHighQuality,
|
||||
// color: useHighQuality
|
||||
// ? Colors.white
|
||||
// : Colors.white.withAlpha(160),
|
||||
// onPressed: () async {
|
||||
// useHighQuality = !useHighQuality;
|
||||
// setState(() {});
|
||||
// await updateUserdata((user) {
|
||||
// user.useHighQuality = useHighQuality;
|
||||
// return user;
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
if (!hasAudioPermission)
|
||||
ActionButton(
|
||||
Icons.mic_off_rounded,
|
||||
|
|
|
|||
|
|
@ -78,6 +78,9 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
|||
initAsync();
|
||||
initMediaFileUpload();
|
||||
layers.add(FilterLayerData());
|
||||
if (widget.sendTo != null) {
|
||||
selectedUserIds.add(widget.sendTo!.userId);
|
||||
}
|
||||
if (widget.imageBytes != null) {
|
||||
loadImage(widget.imageBytes!);
|
||||
} else if (widget.videoFilePath != null) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import 'package:twonly/src/views/camera/camera_send_to_view.dart';
|
|||
import 'package:twonly/src/views/chats/add_new_user.view.dart';
|
||||
import 'package:twonly/src/views/chats/chat_list_components/backup_notice.card.dart';
|
||||
import 'package:twonly/src/views/chats/chat_list_components/connection_info.comp.dart';
|
||||
import 'package:twonly/src/views/chats/chat_list_components/demo_user.card.dart';
|
||||
import 'package:twonly/src/views/chats/chat_list_components/feedback_btn.dart';
|
||||
import 'package:twonly/src/views/chats/chat_list_components/last_message_time.dart';
|
||||
import 'package:twonly/src/views/chats/chat_messages.view.dart';
|
||||
import 'package:twonly/src/views/chats/media_viewer.view.dart';
|
||||
|
|
@ -29,7 +29,6 @@ import 'package:twonly/src/views/components/message_send_state_icon.dart';
|
|||
import 'package:twonly/src/views/components/notification_badge.dart';
|
||||
import 'package:twonly/src/views/components/user_context_menu.dart';
|
||||
import 'package:twonly/src/views/settings/help/changelog.view.dart';
|
||||
import 'package:twonly/src/views/settings/help/contact_us.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/tutorial/tutorials.dart';
|
||||
|
|
@ -77,10 +76,6 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
|
||||
final user = await getUser();
|
||||
if (user == null) return;
|
||||
setState(() {
|
||||
showFeedbackShortcut = user.showFeedbackShortcut;
|
||||
});
|
||||
|
||||
final changeLog = await rootBundle.loadString('CHANGELOG.md');
|
||||
final changeLogHash =
|
||||
(await compute(Sha256().hash, changeLog.codeUnits)).bytes;
|
||||
|
|
@ -91,6 +86,9 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
return u;
|
||||
});
|
||||
if (!mounted) return;
|
||||
// only show changelog to people who already have contacts
|
||||
// this prevents that this is shown directly after the user registered
|
||||
if (_contacts.isNotEmpty) {
|
||||
await Navigator.push(context, MaterialPageRoute(builder: (context) {
|
||||
return ChangeLogView(
|
||||
changeLog: changeLog,
|
||||
|
|
@ -98,6 +96,7 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
|
|
@ -139,20 +138,7 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
),
|
||||
]),
|
||||
actions: [
|
||||
if (showFeedbackShortcut)
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const ContactUsView(),
|
||||
),
|
||||
);
|
||||
},
|
||||
color: Colors.grey,
|
||||
tooltip: context.lang.feedbackTooltip,
|
||||
icon: const FaIcon(FontAwesomeIcons.commentDots, size: 19),
|
||||
),
|
||||
const FeedbackIconButton(),
|
||||
StreamBuilder(
|
||||
stream: twonlyDB.contactsDao.watchContactsRequested(),
|
||||
builder: (context, snapshot) {
|
||||
|
|
@ -226,7 +212,6 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
child: ListView.builder(
|
||||
itemCount: _pinnedContacts.length +
|
||||
(_pinnedContacts.isNotEmpty ? 1 : 0) +
|
||||
(gIsDemoUser ? 1 : 0) +
|
||||
_contacts.length +
|
||||
1,
|
||||
itemBuilder: (context, index) {
|
||||
|
|
@ -234,20 +219,13 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
return const BackupNoticeCard();
|
||||
}
|
||||
index -= 1;
|
||||
if (gIsDemoUser) {
|
||||
if (index == 0) {
|
||||
return const DemoUserCard();
|
||||
}
|
||||
index -= 1;
|
||||
}
|
||||
// Check if the index is for the pinned users
|
||||
if (index < _pinnedContacts.length) {
|
||||
final contact = _pinnedContacts[index];
|
||||
return UserListItem(
|
||||
key: ValueKey(contact.userId),
|
||||
user: contact,
|
||||
firstUserListItemKey: (index == 0 && !gIsDemoUser ||
|
||||
index == 1 && gIsDemoUser)
|
||||
firstUserListItemKey: (index == 0 || index == 1)
|
||||
? firstUserListItemKey
|
||||
: null,
|
||||
);
|
||||
|
|
@ -381,6 +359,45 @@ class _UserListItem extends State<UserListItem> {
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> onTap() async {
|
||||
if (currentMessage == null) {
|
||||
await Navigator.push(context, MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return CameraSendToView(widget.user);
|
||||
},
|
||||
));
|
||||
return;
|
||||
}
|
||||
final msgs =
|
||||
previewMessages.where((x) => x.kind == MessageKind.media).toList();
|
||||
if (msgs.isNotEmpty &&
|
||||
msgs.first.kind == MessageKind.media &&
|
||||
msgs.first.messageOtherId != null &&
|
||||
msgs.first.openedAt == null) {
|
||||
switch (msgs.first.downloadState) {
|
||||
case DownloadState.pending:
|
||||
await startDownloadMedia(msgs.first, true);
|
||||
return;
|
||||
case DownloadState.downloaded:
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) {
|
||||
return MediaViewerView(widget.user);
|
||||
}),
|
||||
);
|
||||
return;
|
||||
case DownloadState.downloading:
|
||||
return;
|
||||
}
|
||||
}
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) {
|
||||
return ChatMessagesView(widget.user);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final flameCounter = getFlameCounterFromContact(widget.user);
|
||||
|
|
@ -433,48 +450,12 @@ class _UserListItem extends State<UserListItem> {
|
|||
},
|
||||
));
|
||||
},
|
||||
icon: FaIcon(FontAwesomeIcons.camera,
|
||||
color: context.color.outline.withAlpha(150)),
|
||||
icon: FaIcon(
|
||||
FontAwesomeIcons.camera,
|
||||
color: context.color.outline.withAlpha(150),
|
||||
),
|
||||
onTap: () {
|
||||
if (currentMessage == null) {
|
||||
Navigator.push(context, MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return CameraSendToView(widget.user);
|
||||
},
|
||||
));
|
||||
return;
|
||||
}
|
||||
final msgs = previewMessages
|
||||
.where((x) => x.kind == MessageKind.media)
|
||||
.toList();
|
||||
if (msgs.isNotEmpty &&
|
||||
msgs.first.kind == MessageKind.media &&
|
||||
msgs.first.messageOtherId != null &&
|
||||
msgs.first.openedAt == null) {
|
||||
switch (msgs.first.downloadState) {
|
||||
case DownloadState.pending:
|
||||
startDownloadMedia(msgs.first, true);
|
||||
return;
|
||||
case DownloadState.downloaded:
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) {
|
||||
return MediaViewerView(widget.user);
|
||||
}),
|
||||
);
|
||||
return;
|
||||
case DownloadState.downloading:
|
||||
return;
|
||||
}
|
||||
}
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) {
|
||||
return ChatMessagesView(widget.user);
|
||||
}),
|
||||
);
|
||||
},
|
||||
),
|
||||
onTap: onTap,
|
||||
),
|
||||
)
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/utils/storage.dart';
|
||||
import 'package:twonly/src/views/settings/backup/backup.view.dart';
|
||||
|
|
@ -26,12 +25,14 @@ class _BackupNoticeCardState extends State<BackupNoticeCard> {
|
|||
if (user != null &&
|
||||
(user.nextTimeToShowBackupNotice == null ||
|
||||
DateTime.now().isAfter(user.nextTimeToShowBackupNotice!))) {
|
||||
if (!gIsDemoUser && (user.twonlySafeBackup == null)) {
|
||||
if (user.twonlySafeBackup == null) {
|
||||
showBackupNotice = true;
|
||||
}
|
||||
}
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
|
||||
class ConnectionInfo extends StatefulWidget {
|
||||
|
|
@ -61,7 +60,7 @@ class _ConnectionInfoWidgetState extends State<ConnectionInfo>
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!showAnimation || gIsDemoUser) return Container();
|
||||
if (!showAnimation) return Container();
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
|
||||
return SizedBox(
|
||||
|
|
|
|||
51
lib/src/views/chats/chat_list_components/feedback_btn.dart
Normal file
51
lib/src/views/chats/chat_list_components/feedback_btn.dart
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/utils/storage.dart';
|
||||
import 'package:twonly/src/views/settings/help/contact_us.view.dart';
|
||||
|
||||
class FeedbackIconButton extends StatefulWidget {
|
||||
const FeedbackIconButton({super.key});
|
||||
|
||||
@override
|
||||
State<FeedbackIconButton> createState() => _FeedbackIconButtonState();
|
||||
}
|
||||
|
||||
class _FeedbackIconButtonState extends State<FeedbackIconButton> {
|
||||
bool showFeedbackShortcut = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
initAsync();
|
||||
}
|
||||
|
||||
Future<void> initAsync() async {
|
||||
final user = await getUser();
|
||||
if (user == null || !mounted) return;
|
||||
setState(() {
|
||||
showFeedbackShortcut = user.showFeedbackShortcut;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!showFeedbackShortcut) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const ContactUsView(),
|
||||
),
|
||||
);
|
||||
},
|
||||
color: Colors.grey,
|
||||
tooltip: context.lang.feedbackTooltip,
|
||||
icon: const FaIcon(FontAwesomeIcons.commentDots, size: 19),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -51,6 +51,7 @@ class HomeViewState extends State<HomeView> {
|
|||
double buttonDiameter = 100;
|
||||
double offsetRatio = 0;
|
||||
double offsetFromOne = 0;
|
||||
double lastChange = 0;
|
||||
|
||||
Timer? disableCameraTimer;
|
||||
bool initCameraStarted = true;
|
||||
|
|
@ -62,6 +63,8 @@ class HomeViewState extends State<HomeView> {
|
|||
bool onPageView(ScrollNotification notification) {
|
||||
disableCameraTimer?.cancel();
|
||||
if (notification.depth == 0 && notification is ScrollUpdateNotification) {
|
||||
final page = homeViewPageController.page ?? 0;
|
||||
lastChange = page;
|
||||
setState(() {
|
||||
offsetFromOne = 1.0 - (homeViewPageController.page ?? 0);
|
||||
offsetRatio = offsetFromOne.abs();
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@ class _RegisterViewState extends State<RegisterView> {
|
|||
bool _isValidUserName = false;
|
||||
bool _showUserNameError = false;
|
||||
|
||||
Future<void> createNewUser({bool isDemoAccount = false}) async {
|
||||
Future<void> createNewUser() async {
|
||||
if (!_isValidUserName) {
|
||||
setState(() {
|
||||
_showUserNameError = true;
|
||||
});
|
||||
return;
|
||||
}
|
||||
final username = isDemoAccount ? '<demo>' : usernameController.text;
|
||||
final username = usernameController.text;
|
||||
final inviteCode = inviteCodeController.text;
|
||||
|
||||
setState(() {
|
||||
|
|
@ -52,7 +52,6 @@ class _RegisterViewState extends State<RegisterView> {
|
|||
|
||||
var userId = 0;
|
||||
|
||||
if (!isDemoAccount) {
|
||||
final res = await apiService.register(username, inviteCode);
|
||||
if (res.isSuccess) {
|
||||
Log.info('Got user_id ${res.value} from server');
|
||||
|
|
@ -75,7 +74,6 @@ class _RegisterViewState extends State<RegisterView> {
|
|||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_isTryingToRegister = false;
|
||||
|
|
@ -86,18 +84,13 @@ class _RegisterViewState extends State<RegisterView> {
|
|||
username: username,
|
||||
displayName: username,
|
||||
subscriptionPlan: 'Preview',
|
||||
isDemoUser: isDemoAccount,
|
||||
isDemoUser: false,
|
||||
);
|
||||
|
||||
await const FlutterSecureStorage()
|
||||
.write(key: SecureStorageKeys.userData, value: jsonEncode(userData));
|
||||
|
||||
if (!isDemoAccount) {
|
||||
await apiService.authenticate();
|
||||
} else {
|
||||
gIsDemoUser = true;
|
||||
await createFakeDemoData();
|
||||
}
|
||||
widget.callbackOnSuccess();
|
||||
}
|
||||
|
||||
|
|
@ -228,12 +221,6 @@ class _RegisterViewState extends State<RegisterView> {
|
|||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
// OutlinedButton.icon(
|
||||
// onPressed: () {
|
||||
// createNewUser(isDemoAccount: true);
|
||||
// },
|
||||
// label: const Text('Demo'),
|
||||
// ),
|
||||
OutlinedButton.icon(
|
||||
onPressed: () {
|
||||
Navigator.push(context, MaterialPageRoute(
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ class NotificationView extends StatelessWidget {
|
|||
subtitle: Text(context.lang.settingsNotifyTroubleshootingDesc),
|
||||
onTap: () async {
|
||||
await initFCMAfterAuthenticated();
|
||||
final storedToken = const FlutterSecureStorage()
|
||||
.read(key: SecureStorageKeys.googleFcm) as String?;
|
||||
final storedToken = await (const FlutterSecureStorage()
|
||||
.read(key: SecureStorageKeys.googleFcm));
|
||||
await setupNotificationWithUsers(force: true);
|
||||
if (!context.mounted) return;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue