mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 18:08:40 +00:00
fix multiple issues
This commit is contained in:
parent
95c9db86d6
commit
da4917ad46
33 changed files with 125 additions and 290 deletions
|
|
@ -55,6 +55,9 @@ android {
|
||||||
debug {
|
debug {
|
||||||
applicationIdSuffix ".testing"
|
applicationIdSuffix ".testing"
|
||||||
}
|
}
|
||||||
|
// profile {
|
||||||
|
// applicationIdSuffix ".STOP"
|
||||||
|
// }
|
||||||
release {
|
release {
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,6 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||||
<uses-permission android:name="android.permission.CAMERA"/>
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
|
<application android:usesCleartextTraffic="true" >
|
||||||
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
|
||||||
import 'package:twonly/src/services/fcm.service.dart';
|
import 'package:twonly/src/services/fcm.service.dart';
|
||||||
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
||||||
import 'package:twonly/src/services/notifications/setup.notifications.dart';
|
import 'package:twonly/src/services/notifications/setup.notifications.dart';
|
||||||
|
import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart';
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/storage.dart';
|
import 'package:twonly/src/utils/storage.dart';
|
||||||
|
|
||||||
|
|
@ -63,13 +64,7 @@ void main() async {
|
||||||
unawaited(createPushAvatars());
|
unawaited(createPushAvatars());
|
||||||
await twonlyDB.messagesDao.purgeMessageTable();
|
await twonlyDB.messagesDao.purgeMessageTable();
|
||||||
|
|
||||||
// await twonlyDB.messagesDao.resetPendingDownloadState();
|
unawaited(performTwonlySafeBackup());
|
||||||
// await twonlyDB.messageRetransmissionDao.purgeOldRetransmissions();
|
|
||||||
// await twonlyDB.signalDao.purgeOutDatedPreKeys();
|
|
||||||
|
|
||||||
// unawaited(purgeSendMediaFiles());
|
|
||||||
|
|
||||||
// unawaited(performTwonlySafeBackup());
|
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
|
||||||
..where(
|
..where(
|
||||||
contacts.requested.equals(true) &
|
contacts.requested.equals(true) &
|
||||||
contacts.accepted.equals(false) &
|
contacts.accepted.equals(false) &
|
||||||
|
contacts.deletedByUser.equals(false) &
|
||||||
contacts.blocked.equals(false),
|
contacts.blocked.equals(false),
|
||||||
)
|
)
|
||||||
..addColumns([count]);
|
..addColumns([count]);
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
|
||||||
..where((t) => t.groupId.equals(groupId)))
|
..where((t) => t.groupId.equals(groupId)))
|
||||||
.getSingle();
|
.getSingle();
|
||||||
|
|
||||||
final totalMediaCounter = group.totalMediaCounter + 1;
|
final totalMediaCounter = group.totalMediaCounter + (received ? 0 : 1);
|
||||||
var flameCounter = group.flameCounter;
|
var flameCounter = group.flameCounter;
|
||||||
var maxFlameCounter = group.maxFlameCounter;
|
var maxFlameCounter = group.maxFlameCounter;
|
||||||
var maxFlameCounterFrom = group.maxFlameCounterFrom;
|
var maxFlameCounterFrom = group.maxFlameCounterFrom;
|
||||||
|
|
@ -321,7 +321,11 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
|
||||||
if (updateFlame) {
|
if (updateFlame) {
|
||||||
flameCounter += 1;
|
flameCounter += 1;
|
||||||
lastFlameCounterChange = Value(timestamp);
|
lastFlameCounterChange = Value(timestamp);
|
||||||
if ((flameCounter + 1) >= maxFlameCounter) {
|
// Overwrite max flame counter either the current is bigger or the th max flame counter is older then 4 days
|
||||||
|
if ((flameCounter + 1) >= maxFlameCounter ||
|
||||||
|
maxFlameCounterFrom == null ||
|
||||||
|
maxFlameCounterFrom
|
||||||
|
.isBefore(DateTime.now().subtract(const Duration(days: 5)))) {
|
||||||
maxFlameCounter = flameCounter + 1;
|
maxFlameCounter = flameCounter + 1;
|
||||||
maxFlameCounterFrom = DateTime.now();
|
maxFlameCounterFrom = DateTime.now();
|
||||||
}
|
}
|
||||||
|
|
@ -351,6 +355,15 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stream<int> watchSumTotalMediaCounter() {
|
||||||
|
final query = selectOnly(groups)
|
||||||
|
..addColumns([groups.totalMediaCounter.sum()]);
|
||||||
|
return query.watch().map((rows) {
|
||||||
|
final expr = rows.first.read(groups.totalMediaCounter.sum());
|
||||||
|
return expr ?? 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> increaseLastMessageExchange(
|
Future<void> increaseLastMessageExchange(
|
||||||
String groupId,
|
String groupId,
|
||||||
DateTime newLastMessage,
|
DateTime newLastMessage,
|
||||||
|
|
|
||||||
|
|
@ -816,5 +816,6 @@
|
||||||
"deleteChatAfterADay": "einem Tag.",
|
"deleteChatAfterADay": "einem Tag.",
|
||||||
"deleteChatAfterAWeek": "einer Woche.",
|
"deleteChatAfterAWeek": "einer Woche.",
|
||||||
"deleteChatAfterAMonth": "einem Monat.",
|
"deleteChatAfterAMonth": "einem Monat.",
|
||||||
"deleteChatAfterAYear": "einem Jahr."
|
"deleteChatAfterAYear": "einem Jahr.",
|
||||||
|
"yourTwonlyScore": "Dein twonly-Score"
|
||||||
}
|
}
|
||||||
|
|
@ -594,5 +594,6 @@
|
||||||
"deleteChatAfterADay": "one day.",
|
"deleteChatAfterADay": "one day.",
|
||||||
"deleteChatAfterAWeek": "one week.",
|
"deleteChatAfterAWeek": "one week.",
|
||||||
"deleteChatAfterAMonth": "one month.",
|
"deleteChatAfterAMonth": "one month.",
|
||||||
"deleteChatAfterAYear": "one year."
|
"deleteChatAfterAYear": "one year.",
|
||||||
|
"yourTwonlyScore": "Your twonly-Score"
|
||||||
}
|
}
|
||||||
|
|
@ -2671,6 +2671,12 @@ abstract class AppLocalizations {
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'one year.'**
|
/// **'one year.'**
|
||||||
String get deleteChatAfterAYear;
|
String get deleteChatAfterAYear;
|
||||||
|
|
||||||
|
/// No description provided for @yourTwonlyScore.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Your twonly-Score'**
|
||||||
|
String get yourTwonlyScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppLocalizationsDelegate
|
class _AppLocalizationsDelegate
|
||||||
|
|
|
||||||
|
|
@ -1474,4 +1474,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get deleteChatAfterAYear => 'einem Jahr.';
|
String get deleteChatAfterAYear => 'einem Jahr.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get yourTwonlyScore => 'Dein twonly-Score';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1464,4 +1464,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get deleteChatAfterAYear => 'one year.';
|
String get deleteChatAfterAYear => 'one year.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get yourTwonlyScore => 'Your twonly-Score';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@ final lockRetransStore = Mutex();
|
||||||
/// errors or network changes.
|
/// errors or network changes.
|
||||||
class ApiService {
|
class ApiService {
|
||||||
ApiService();
|
ApiService();
|
||||||
final String apiHost = kDebugMode ? '10.99.0.140:3030' : 'api.twonly.eu';
|
final String apiHost = kReleaseMode ? 'api.twonly.eu' : '10.99.0.140:3030';
|
||||||
final String apiSecure = kDebugMode ? '' : 's';
|
final String apiSecure = kReleaseMode ? 's' : '';
|
||||||
|
|
||||||
bool appIsOutdated = false;
|
bool appIsOutdated = false;
|
||||||
bool isAuthenticated = false;
|
bool isAuthenticated = false;
|
||||||
|
|
|
||||||
|
|
@ -35,15 +35,15 @@ Future<void> initFileDownloader() async {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var androidConfig = [];
|
var androidConfig = [];
|
||||||
if (kDebugMode) {
|
if (!kReleaseMode) {
|
||||||
androidConfig = [(Config.bypassTLSCertificateValidation, kDebugMode)];
|
androidConfig = [(Config.bypassTLSCertificateValidation, true)];
|
||||||
}
|
}
|
||||||
await FileDownloader().configure(androidConfig: androidConfig);
|
await FileDownloader().configure(androidConfig: androidConfig);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
Log.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kDebugMode) {
|
if (!kReleaseMode) {
|
||||||
FileDownloader().configureNotification(
|
FileDownloader().configureNotification(
|
||||||
running: const TaskNotification(
|
running: const TaskNotification(
|
||||||
'Uploading/Downloading',
|
'Uploading/Downloading',
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,10 @@ Future<void> customLocalPushNotification(String title, String msg) async {
|
||||||
'1',
|
'1',
|
||||||
'System',
|
'System',
|
||||||
channelDescription: 'System messages.',
|
channelDescription: 'System messages.',
|
||||||
importance: Importance.max,
|
importance: Importance.high,
|
||||||
priority: Priority.max,
|
priority: Priority.high,
|
||||||
styleInformation: BigTextStyleInformation(msg),
|
styleInformation: BigTextStyleInformation(msg),
|
||||||
|
icon: 'ic_launcher_foreground',
|
||||||
);
|
);
|
||||||
|
|
||||||
const darwinNotificationDetails = DarwinNotificationDetails();
|
const darwinNotificationDetails = DarwinNotificationDetails();
|
||||||
|
|
@ -34,8 +35,10 @@ Future<void> customLocalPushNotification(String title, String msg) async {
|
||||||
iOS: darwinNotificationDetails,
|
iOS: darwinNotificationDetails,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final id = Random.secure().nextInt(9999);
|
||||||
|
|
||||||
await flutterLocalNotificationsPlugin.show(
|
await flutterLocalNotificationsPlugin.show(
|
||||||
Random.secure().nextInt(9999),
|
id,
|
||||||
title,
|
title,
|
||||||
msg,
|
msg,
|
||||||
notificationDetails,
|
notificationDetails,
|
||||||
|
|
@ -95,11 +98,11 @@ Future<void> handlePushData(String pushDataB64) async {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
Log.error(e);
|
||||||
await customLocalPushNotification(
|
await customLocalPushNotification(
|
||||||
'Du hast eine neue Nachricht.',
|
'Du hast eine neue Nachricht.',
|
||||||
'Öffne twonly um mehr zu erfahren.',
|
'Öffne twonly um mehr zu erfahren.',
|
||||||
);
|
);
|
||||||
Log.error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,6 +164,7 @@ Future<void> showLocalPushNotification(
|
||||||
priority: Priority.max,
|
priority: Priority.max,
|
||||||
ticker: 'You got a new message.',
|
ticker: 'You got a new message.',
|
||||||
largeIcon: styleInformation,
|
largeIcon: styleInformation,
|
||||||
|
icon: 'ic_launcher_foreground',
|
||||||
);
|
);
|
||||||
|
|
||||||
const darwinNotificationDetails = DarwinNotificationDetails();
|
const darwinNotificationDetails = DarwinNotificationDetails();
|
||||||
|
|
@ -174,7 +178,7 @@ Future<void> showLocalPushNotification(
|
||||||
title,
|
title,
|
||||||
body,
|
body,
|
||||||
notificationDetails,
|
notificationDetails,
|
||||||
payload: pushNotification.kind.name,
|
// payload: pushNotification.kind.name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ Future<void> setupNotificationWithUsers({
|
||||||
final pushUser =
|
final pushUser =
|
||||||
pushUsers.firstWhereOrNull((x) => x.userId == contact.userId);
|
pushUsers.firstWhereOrNull((x) => x.userId == contact.userId);
|
||||||
|
|
||||||
if (pushUser != null) {
|
if (pushUser != null && pushUser.pushKeys.isNotEmpty) {
|
||||||
// make it harder to predict the change of the key
|
// make it harder to predict the change of the key
|
||||||
final timeBefore =
|
final timeBefore =
|
||||||
DateTime.now().subtract(Duration(days: 5 + random.nextInt(5)));
|
DateTime.now().subtract(Duration(days: 5 + random.nextInt(5)));
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ void initLogger() {
|
||||||
Logger.root.level = Level.ALL;
|
Logger.root.level = Level.ALL;
|
||||||
Logger.root.onRecord.listen((record) async {
|
Logger.root.onRecord.listen((record) async {
|
||||||
await _writeLogToFile(record);
|
await _writeLogToFile(record);
|
||||||
if (kDebugMode) {
|
if (!kReleaseMode) {
|
||||||
print(
|
print(
|
||||||
'${record.level.name} [twonly] ${record.loggerName} > ${record.message}',
|
'${record.level.name} [twonly] ${record.loggerName} > ${record.message}',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ bool isUUIDNewer(String uuid1, String uuid2) {
|
||||||
return timestamp1 > timestamp2;
|
return timestamp1 > timestamp2;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
Log.error(e);
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:camera/camera.dart';
|
import 'package:camera/camera.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
|
import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/views/camera/camera_preview_controller_view.dart';
|
import 'package:twonly/src/views/camera/camera_preview_controller_view.dart';
|
||||||
|
|
||||||
class CameraZoomButtons extends StatefulWidget {
|
class CameraZoomButtons extends StatefulWidget {
|
||||||
|
|
@ -50,6 +50,7 @@ class _CameraZoomButtonsState extends State<CameraZoomButtons> {
|
||||||
|
|
||||||
Future<void> initAsync() async {
|
Future<void> initAsync() async {
|
||||||
showWideAngleZoom = (await widget.controller.getMinZoomLevel()) < 1;
|
showWideAngleZoom = (await widget.controller.getMinZoomLevel()) < 1;
|
||||||
|
Log.info('Found ${gCameras.length} cameras for zoom.');
|
||||||
if (!showWideAngleZoom && Platform.isIOS && gCameras.length == 3) {
|
if (!showWideAngleZoom && Platform.isIOS && gCameras.length == 3) {
|
||||||
showWideAngleZoomIOS = true;
|
showWideAngleZoomIOS = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ Future<List<Sticker>> getStickerIndex() async {
|
||||||
final indexFile = File('${directory.path}/stickers.json');
|
final indexFile = File('${directory.path}/stickers.json');
|
||||||
var res = <Sticker>[];
|
var res = <Sticker>[];
|
||||||
|
|
||||||
if (indexFile.existsSync() && !kDebugMode) {
|
if (indexFile.existsSync() && kReleaseMode) {
|
||||||
final lastModified = indexFile.lastModifiedSync();
|
final lastModified = indexFile.lastModifiedSync();
|
||||||
final difference = DateTime.now().difference(lastModified);
|
final difference = DateTime.now().difference(lastModified);
|
||||||
final content = await indexFile.readAsString();
|
final content = await indexFile.readAsString();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
|
@ -45,10 +47,10 @@ class ReactionRow extends StatelessWidget {
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
reaction.emoji,
|
reaction.emoji,
|
||||||
style: const TextStyle(fontSize: 18),
|
style: TextStyle(fontSize: Platform.isIOS ? 18 : 15),
|
||||||
strutStyle: const StrutStyle(
|
strutStyle: StrutStyle(
|
||||||
forceStrutHeight: true,
|
forceStrutHeight: true,
|
||||||
height: 1.6,
|
height: Platform.isIOS ? 1.6 : 1.3,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -114,7 +116,7 @@ class ReactionRow extends StatelessWidget {
|
||||||
entry.$2.toString(),
|
entry.$2.toString(),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 13,
|
||||||
color:
|
color:
|
||||||
isDarkMode(context) ? Colors.white : Colors.black,
|
isDarkMode(context) ? Colors.white : Colors.black,
|
||||||
decoration: TextDecoration.none,
|
decoration: TextDecoration.none,
|
||||||
|
|
|
||||||
|
|
@ -67,9 +67,10 @@ class _ChatMediaEntryState extends State<ChatMediaEntry> {
|
||||||
if (widget.message.openedAt == null || widget.message.mediaStored) {
|
if (widget.message.openedAt == null || widget.message.mediaStored) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (widget.mediaService.tempPath.existsSync()) {
|
if (widget.mediaService.tempPath.existsSync() &&
|
||||||
await sendCipherTextToGroup(
|
widget.message.senderId != null) {
|
||||||
widget.message.groupId,
|
await sendCipherText(
|
||||||
|
widget.message.senderId!,
|
||||||
EncryptedContent(
|
EncryptedContent(
|
||||||
mediaUpdate: EncryptedContent_MediaUpdate(
|
mediaUpdate: EncryptedContent_MediaUpdate(
|
||||||
type: EncryptedContent_MediaUpdate_Type.REOPENED,
|
type: EncryptedContent_MediaUpdate_Type.REOPENED,
|
||||||
|
|
|
||||||
|
|
@ -77,10 +77,10 @@ class ChatTextEntry extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
if (info.expanded)
|
if (info.expanded)
|
||||||
Expanded(
|
Expanded(
|
||||||
child: BetterText(text: text, textColor: info.textColor),
|
child: BetterText(text: info.text, textColor: info.textColor),
|
||||||
)
|
)
|
||||||
else ...[
|
else ...[
|
||||||
BetterText(text: text, textColor: info.textColor),
|
BetterText(text: info.text, textColor: info.textColor),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: info.spacerWidth,
|
width: info.spacerWidth,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -242,10 +242,10 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.lastReaction!.emoji,
|
widget.lastReaction!.emoji,
|
||||||
style: const TextStyle(fontSize: 18),
|
style: const TextStyle(fontSize: 15),
|
||||||
strutStyle: const StrutStyle(
|
strutStyle: const StrutStyle(
|
||||||
forceStrutHeight: true,
|
forceStrutHeight: true,
|
||||||
height: 1.6,
|
height: 1.4,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,242 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:audio_waveforms/audio_waveforms.dart';
|
|
||||||
import 'package:audio_waveforms_example/chat_bubble.dart';
|
|
||||||
import 'package:file_picker/file_picker.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
|
|
||||||
void main() => runApp(const MyApp());
|
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
|
||||||
const MyApp({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const MaterialApp(
|
|
||||||
title: 'Audio Waveforms',
|
|
||||||
debugShowCheckedModeBanner: false,
|
|
||||||
home: Home(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Home extends StatefulWidget {
|
|
||||||
const Home({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<Home> createState() => _HomeState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _HomeState extends State<Home> {
|
|
||||||
late final RecorderController recorderController;
|
|
||||||
|
|
||||||
String? path;
|
|
||||||
String? musicFile;
|
|
||||||
bool isRecording = false;
|
|
||||||
bool isRecordingCompleted = false;
|
|
||||||
bool isLoading = true;
|
|
||||||
late Directory appDirectory;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_getDir();
|
|
||||||
_initialiseControllers();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _getDir() async {
|
|
||||||
appDirectory = await getApplicationDocumentsDirectory();
|
|
||||||
path = "${appDirectory.path}/recording.m4a";
|
|
||||||
isLoading = false;
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _initialiseControllers() {
|
|
||||||
recorderController = RecorderController()
|
|
||||||
..androidEncoder = AndroidEncoder.aac
|
|
||||||
..androidOutputFormat = AndroidOutputFormat.mpeg4
|
|
||||||
..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC
|
|
||||||
..sampleRate = 44100;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _pickFile() async {
|
|
||||||
FilePickerResult? result = await FilePicker.platform.pickFiles();
|
|
||||||
if (result != null) {
|
|
||||||
musicFile = result.files.single.path;
|
|
||||||
setState(() {});
|
|
||||||
} else {
|
|
||||||
debugPrint("File not picked");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
recorderController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: const Color(0xFF252331),
|
|
||||||
appBar: AppBar(
|
|
||||||
backgroundColor: const Color(0xFF252331),
|
|
||||||
elevation: 1,
|
|
||||||
centerTitle: true,
|
|
||||||
shadowColor: Colors.grey,
|
|
||||||
title: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Image.asset(
|
|
||||||
'assets/images/logo.png',
|
|
||||||
scale: 1.5,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
const Text(
|
|
||||||
'Simform',
|
|
||||||
style: TextStyle(color: Colors.white),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: isLoading
|
|
||||||
? const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
)
|
|
||||||
: SafeArea(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Expanded(
|
|
||||||
child: ListView.builder(
|
|
||||||
itemCount: 4,
|
|
||||||
itemBuilder: (_, index) {
|
|
||||||
return WaveBubble(
|
|
||||||
index: index + 1,
|
|
||||||
isSender: index.isOdd,
|
|
||||||
width: MediaQuery.of(context).size.width / 2,
|
|
||||||
appDirectory: appDirectory,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (isRecordingCompleted)
|
|
||||||
WaveBubble(
|
|
||||||
path: path,
|
|
||||||
isSender: true,
|
|
||||||
appDirectory: appDirectory,
|
|
||||||
),
|
|
||||||
if (musicFile != null)
|
|
||||||
WaveBubble(
|
|
||||||
path: musicFile,
|
|
||||||
isSender: true,
|
|
||||||
appDirectory: appDirectory,
|
|
||||||
),
|
|
||||||
SafeArea(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
AnimatedSwitcher(
|
|
||||||
duration: const Duration(milliseconds: 200),
|
|
||||||
child: isRecording
|
|
||||||
? AudioWaveforms(
|
|
||||||
enableGesture: true,
|
|
||||||
size: Size(
|
|
||||||
MediaQuery.of(context).size.width / 2,
|
|
||||||
50),
|
|
||||||
recorderController: recorderController,
|
|
||||||
waveStyle: const WaveStyle(
|
|
||||||
waveColor: Colors.white,
|
|
||||||
extendWaveform: true,
|
|
||||||
showMiddleLine: false,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(12.0),
|
|
||||||
color: const Color(0xFF1E1B26),
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.only(left: 18),
|
|
||||||
margin: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 15),
|
|
||||||
)
|
|
||||||
: Container(
|
|
||||||
width:
|
|
||||||
MediaQuery.of(context).size.width / 1.7,
|
|
||||||
height: 50,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: const Color(0xFF1E1B26),
|
|
||||||
borderRadius: BorderRadius.circular(12.0),
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.only(left: 18),
|
|
||||||
margin: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 15),
|
|
||||||
child: TextField(
|
|
||||||
readOnly: true,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: "Type Something...",
|
|
||||||
hintStyle: const TextStyle(
|
|
||||||
color: Colors.white54),
|
|
||||||
contentPadding:
|
|
||||||
const EdgeInsets.only(top: 16),
|
|
||||||
border: InputBorder.none,
|
|
||||||
suffixIcon: IconButton(
|
|
||||||
onPressed: _pickFile,
|
|
||||||
icon: Icon(Icons.adaptive.share),
|
|
||||||
color: Colors.white54,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
onPressed: _refreshWave,
|
|
||||||
icon: Icon(
|
|
||||||
isRecording ? Icons.refresh : Icons.send,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
IconButton(
|
|
||||||
onPressed: _startOrStopRecording,
|
|
||||||
icon: Icon(isRecording ? Icons.stop : Icons.mic),
|
|
||||||
color: Colors.white,
|
|
||||||
iconSize: 28,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startOrStopRecording() async {
|
|
||||||
try {
|
|
||||||
if (isRecording) {
|
|
||||||
recorderController.reset();
|
|
||||||
|
|
||||||
path = await recorderController.stop(false);
|
|
||||||
|
|
||||||
if (path != null) {
|
|
||||||
isRecordingCompleted = true;
|
|
||||||
debugPrint(path);
|
|
||||||
debugPrint("Recorded file size: ${File(path!).lengthSync()}");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await recorderController.record(path: path); // Path is optional
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint(e.toString());
|
|
||||||
} finally {
|
|
||||||
if (recorderController.hasPermission) {
|
|
||||||
setState(() {
|
|
||||||
isRecording = !isRecording;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _refreshWave() {
|
|
||||||
if (isRecording) recorderController.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -82,6 +82,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
_subscription.cancel();
|
_subscription.cancel();
|
||||||
downloadStateListener?.cancel();
|
downloadStateListener?.cancel();
|
||||||
videoController?.dispose();
|
videoController?.dispose();
|
||||||
|
videoController = null;
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,7 +142,9 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
|
|
||||||
Future<void> loadCurrentMediaFile({bool showTwonly = false}) async {
|
Future<void> loadCurrentMediaFile({bool showTwonly = false}) async {
|
||||||
if (!mounted || !context.mounted) return;
|
if (!mounted || !context.mounted) return;
|
||||||
if (allMediaFiles.isEmpty) return nextMediaOrExit();
|
if (allMediaFiles.isEmpty || allMediaFiles.first.mediaId == null) {
|
||||||
|
return nextMediaOrExit();
|
||||||
|
}
|
||||||
await _noScreenshot.screenshotOff();
|
await _noScreenshot.screenshotOff();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
@ -175,7 +178,8 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
downloadTriggered = true;
|
downloadTriggered = true;
|
||||||
final mediaFile = await twonlyDB.mediaFilesDao
|
final mediaFile = await twonlyDB.mediaFilesDao
|
||||||
.getMediaFileById(allMediaFiles.first.mediaId!);
|
.getMediaFileById(allMediaFiles.first.mediaId!);
|
||||||
await startDownloadMedia(mediaFile!, true);
|
if (mediaFile == null) return;
|
||||||
|
await startDownloadMedia(mediaFile, true);
|
||||||
unawaited(tryDownloadAllMediaFiles(force: true));
|
unawaited(tryDownloadAllMediaFiles(force: true));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
@ -269,6 +273,10 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
progressTimer = Timer.periodic(const Duration(milliseconds: 10), (timer) {
|
progressTimer = Timer.periodic(const Duration(milliseconds: 10), (timer) {
|
||||||
|
if (currentMedia!.mediaFile.displayLimitInMilliseconds == null ||
|
||||||
|
canBeSeenUntil == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final difference = canBeSeenUntil!.difference(DateTime.now());
|
final difference = canBeSeenUntil!.difference(DateTime.now());
|
||||||
// Calculate the progress as a value between 0.0 and 1.0
|
// Calculate the progress as a value between 0.0 and 1.0
|
||||||
progress = difference.inMilliseconds /
|
progress = difference.inMilliseconds /
|
||||||
|
|
@ -312,10 +320,12 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
|
|
||||||
void displayShortReactions() {
|
void displayShortReactions() {
|
||||||
final renderBox =
|
final renderBox =
|
||||||
mediaWidgetKey.currentContext!.findRenderObject()! as RenderBox;
|
mediaWidgetKey.currentContext!.findRenderObject() as RenderBox?;
|
||||||
setState(() {
|
setState(() {
|
||||||
showShortReactions = true;
|
showShortReactions = true;
|
||||||
|
if (renderBox != null) {
|
||||||
mediaViewerDistanceFromBottom = renderBox.size.height;
|
mediaViewerDistanceFromBottom = renderBox.size.height;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ class _MaxFlameListTitleState extends State<MaxFlameListTitle> {
|
||||||
if (_directChat == null ||
|
if (_directChat == null ||
|
||||||
_directChat!.maxFlameCounter == 0 ||
|
_directChat!.maxFlameCounter == 0 ||
|
||||||
_flameCounter >= (_directChat!.maxFlameCounter + 1) ||
|
_flameCounter >= (_directChat!.maxFlameCounter + 1) ||
|
||||||
_directChat!.lastFlameCounterChange!
|
_directChat!.maxFlameCounterFrom!
|
||||||
.isBefore(DateTime.now().subtract(const Duration(days: 4)))) {
|
.isBefore(DateTime.now().subtract(const Duration(days: 4)))) {
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ class _AccountViewState extends State<AccountView> {
|
||||||
.where(
|
.where(
|
||||||
(x) =>
|
(x) =>
|
||||||
x.transactionType != Response_TransactionTypes.ThanksForTesting ||
|
x.transactionType != Response_TransactionTypes.ThanksForTesting ||
|
||||||
kDebugMode,
|
!kReleaseMode,
|
||||||
)
|
)
|
||||||
.map((a) => a.depositCents.toInt())
|
.map((a) => a.depositCents.toInt())
|
||||||
.sum;
|
.sum;
|
||||||
|
|
@ -101,7 +101,7 @@ class _AccountViewState extends State<AccountView> {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Text(context.lang.settingsAccountDeleteAccountNoBallance),
|
: Text(context.lang.settingsAccountDeleteAccountNoBallance),
|
||||||
onLongPress: kDebugMode
|
onLongPress: !kReleaseMode
|
||||||
? () async {
|
? () async {
|
||||||
await deleteLocalUserData();
|
await deleteLocalUserData();
|
||||||
await Restart.restartApp(
|
await Restart.restartApp(
|
||||||
|
|
|
||||||
|
|
@ -204,7 +204,7 @@ class _TwonlyIdentityBackupViewState extends State<TwonlyIdentityBackupView> {
|
||||||
onPressed: (!isLoading &&
|
onPressed: (!isLoading &&
|
||||||
(passwordCtrl.text == repeatedPasswordCtrl.text &&
|
(passwordCtrl.text == repeatedPasswordCtrl.text &&
|
||||||
passwordCtrl.text.length >= 8 ||
|
passwordCtrl.text.length >= 8 ||
|
||||||
kDebugMode))
|
!kReleaseMode))
|
||||||
? onPressedEnableTwonlySafe
|
? onPressedEnableTwonlySafe
|
||||||
: null,
|
: null,
|
||||||
icon: isLoading
|
icon: isLoading
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ class _AutomatedTestingViewState extends State<AutomatedTestingView> {
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
children: [
|
children: [
|
||||||
if (kDebugMode)
|
if (!kReleaseMode)
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Sending a lot of messages.'),
|
title: const Text('Sending a lot of messages.'),
|
||||||
subtitle: Text(lotsOfMessagesStatus),
|
subtitle: Text(lotsOfMessagesStatus),
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ class _DeveloperSettingsViewState extends State<DeveloperSettingsView> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
// if (kDebugMode)
|
// if (!kReleaseMode)
|
||||||
// ListTile(
|
// ListTile(
|
||||||
// title: const Text('FlameSync Test'),
|
// title: const Text('FlameSync Test'),
|
||||||
// onTap: () async {
|
// onTap: () async {
|
||||||
|
|
@ -74,7 +74,7 @@ class _DeveloperSettingsViewState extends State<DeveloperSettingsView> {
|
||||||
// await syncFlameCounters();
|
// await syncFlameCounters();
|
||||||
// },
|
// },
|
||||||
// ),
|
// ),
|
||||||
if (kDebugMode)
|
if (!kReleaseMode)
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Automated Testing'),
|
title: const Text('Automated Testing'),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,26 @@ class _ProfileViewState extends State<ProfileView> {
|
||||||
final AvatarMakerController _avatarMakerController =
|
final AvatarMakerController _avatarMakerController =
|
||||||
PersistentAvatarMakerController(customizedPropertyCategories: []);
|
PersistentAvatarMakerController(customizedPropertyCategories: []);
|
||||||
|
|
||||||
|
int twonlyScore = 0;
|
||||||
|
late StreamSubscription<int> twonlyScoreSub;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
twonlyScoreSub =
|
||||||
|
twonlyDB.groupsDao.watchSumTotalMediaCounter().listen((update) {
|
||||||
|
setState(() {
|
||||||
|
twonlyScore = update;
|
||||||
|
});
|
||||||
|
});
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
twonlyScoreSub.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> updateUserDisplayName(String displayName) async {
|
Future<void> updateUserDisplayName(String displayName) async {
|
||||||
await updateUserdata((user) {
|
await updateUserdata((user) {
|
||||||
user
|
user
|
||||||
|
|
@ -156,6 +171,17 @@ class _ProfileViewState extends State<ProfileView> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
BetterListTile(
|
||||||
|
text: context.lang.yourTwonlyScore,
|
||||||
|
icon: FontAwesomeIcons.trophy,
|
||||||
|
trailing: Text(
|
||||||
|
twonlyScore.toString(),
|
||||||
|
style: TextStyle(
|
||||||
|
color: context.color.primary,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ class _CheckoutViewState extends State<CheckoutView> {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: Card(
|
child: Card(
|
||||||
|
color: context.color.surfaceContainer,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ class _SelectPaymentViewState extends State<SelectPaymentView> {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Card(
|
child: Card(
|
||||||
|
color: context.color.surfaceContainer,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
@ -193,6 +194,7 @@ class _SelectPaymentViewState extends State<SelectPaymentView> {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: Card(
|
child: Card(
|
||||||
|
color: context.color.surfaceContainer,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
@ -215,6 +217,7 @@ class _SelectPaymentViewState extends State<SelectPaymentView> {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: Card(
|
child: Card(
|
||||||
|
color: context.color.surfaceContainer,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
|
||||||
|
|
@ -444,6 +444,7 @@ class PlanCard extends StatelessWidget {
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
),
|
),
|
||||||
|
color: context.color.surfaceContainer,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue