mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 13:08:42 +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 {
|
||||
applicationIdSuffix ".testing"
|
||||
}
|
||||
// profile {
|
||||
// applicationIdSuffix ".STOP"
|
||||
// }
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,4 +6,6 @@
|
|||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<application android:usesCleartextTraffic="true" >
|
||||
</application>
|
||||
</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/mediafiles/mediafile.service.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/storage.dart';
|
||||
|
||||
|
|
@ -63,13 +64,7 @@ void main() async {
|
|||
unawaited(createPushAvatars());
|
||||
await twonlyDB.messagesDao.purgeMessageTable();
|
||||
|
||||
// await twonlyDB.messagesDao.resetPendingDownloadState();
|
||||
// await twonlyDB.messageRetransmissionDao.purgeOldRetransmissions();
|
||||
// await twonlyDB.signalDao.purgeOutDatedPreKeys();
|
||||
|
||||
// unawaited(purgeSendMediaFiles());
|
||||
|
||||
// unawaited(performTwonlySafeBackup());
|
||||
unawaited(performTwonlySafeBackup());
|
||||
|
||||
runApp(
|
||||
MultiProvider(
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
|
|||
..where(
|
||||
contacts.requested.equals(true) &
|
||||
contacts.accepted.equals(false) &
|
||||
contacts.deletedByUser.equals(false) &
|
||||
contacts.blocked.equals(false),
|
||||
)
|
||||
..addColumns([count]);
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
|
|||
..where((t) => t.groupId.equals(groupId)))
|
||||
.getSingle();
|
||||
|
||||
final totalMediaCounter = group.totalMediaCounter + 1;
|
||||
final totalMediaCounter = group.totalMediaCounter + (received ? 0 : 1);
|
||||
var flameCounter = group.flameCounter;
|
||||
var maxFlameCounter = group.maxFlameCounter;
|
||||
var maxFlameCounterFrom = group.maxFlameCounterFrom;
|
||||
|
|
@ -321,7 +321,11 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
|
|||
if (updateFlame) {
|
||||
flameCounter += 1;
|
||||
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;
|
||||
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(
|
||||
String groupId,
|
||||
DateTime newLastMessage,
|
||||
|
|
|
|||
|
|
@ -816,5 +816,6 @@
|
|||
"deleteChatAfterADay": "einem Tag.",
|
||||
"deleteChatAfterAWeek": "einer Woche.",
|
||||
"deleteChatAfterAMonth": "einem Monat.",
|
||||
"deleteChatAfterAYear": "einem Jahr."
|
||||
"deleteChatAfterAYear": "einem Jahr.",
|
||||
"yourTwonlyScore": "Dein twonly-Score"
|
||||
}
|
||||
|
|
@ -594,5 +594,6 @@
|
|||
"deleteChatAfterADay": "one day.",
|
||||
"deleteChatAfterAWeek": "one week.",
|
||||
"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:
|
||||
/// **'one year.'**
|
||||
String get deleteChatAfterAYear;
|
||||
|
||||
/// No description provided for @yourTwonlyScore.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Your twonly-Score'**
|
||||
String get yourTwonlyScore;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
|
|
|||
|
|
@ -1474,4 +1474,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get deleteChatAfterAYear => 'einem Jahr.';
|
||||
|
||||
@override
|
||||
String get yourTwonlyScore => 'Dein twonly-Score';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1464,4 +1464,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get deleteChatAfterAYear => 'one year.';
|
||||
|
||||
@override
|
||||
String get yourTwonlyScore => 'Your twonly-Score';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ final lockRetransStore = Mutex();
|
|||
/// errors or network changes.
|
||||
class ApiService {
|
||||
ApiService();
|
||||
final String apiHost = kDebugMode ? '10.99.0.140:3030' : 'api.twonly.eu';
|
||||
final String apiSecure = kDebugMode ? '' : 's';
|
||||
final String apiHost = kReleaseMode ? 'api.twonly.eu' : '10.99.0.140:3030';
|
||||
final String apiSecure = kReleaseMode ? 's' : '';
|
||||
|
||||
bool appIsOutdated = false;
|
||||
bool isAuthenticated = false;
|
||||
|
|
|
|||
|
|
@ -35,15 +35,15 @@ Future<void> initFileDownloader() async {
|
|||
|
||||
try {
|
||||
var androidConfig = [];
|
||||
if (kDebugMode) {
|
||||
androidConfig = [(Config.bypassTLSCertificateValidation, kDebugMode)];
|
||||
if (!kReleaseMode) {
|
||||
androidConfig = [(Config.bypassTLSCertificateValidation, true)];
|
||||
}
|
||||
await FileDownloader().configure(androidConfig: androidConfig);
|
||||
} catch (e) {
|
||||
Log.error(e);
|
||||
}
|
||||
|
||||
if (kDebugMode) {
|
||||
if (!kReleaseMode) {
|
||||
FileDownloader().configureNotification(
|
||||
running: const TaskNotification(
|
||||
'Uploading/Downloading',
|
||||
|
|
|
|||
|
|
@ -23,9 +23,10 @@ Future<void> customLocalPushNotification(String title, String msg) async {
|
|||
'1',
|
||||
'System',
|
||||
channelDescription: 'System messages.',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
importance: Importance.high,
|
||||
priority: Priority.high,
|
||||
styleInformation: BigTextStyleInformation(msg),
|
||||
icon: 'ic_launcher_foreground',
|
||||
);
|
||||
|
||||
const darwinNotificationDetails = DarwinNotificationDetails();
|
||||
|
|
@ -34,8 +35,10 @@ Future<void> customLocalPushNotification(String title, String msg) async {
|
|||
iOS: darwinNotificationDetails,
|
||||
);
|
||||
|
||||
final id = Random.secure().nextInt(9999);
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
Random.secure().nextInt(9999),
|
||||
id,
|
||||
title,
|
||||
msg,
|
||||
notificationDetails,
|
||||
|
|
@ -95,11 +98,11 @@ Future<void> handlePushData(String pushDataB64) async {
|
|||
}
|
||||
}
|
||||
} catch (e) {
|
||||
Log.error(e);
|
||||
await customLocalPushNotification(
|
||||
'Du hast eine neue Nachricht.',
|
||||
'Öffne twonly um mehr zu erfahren.',
|
||||
);
|
||||
Log.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,6 +164,7 @@ Future<void> showLocalPushNotification(
|
|||
priority: Priority.max,
|
||||
ticker: 'You got a new message.',
|
||||
largeIcon: styleInformation,
|
||||
icon: 'ic_launcher_foreground',
|
||||
);
|
||||
|
||||
const darwinNotificationDetails = DarwinNotificationDetails();
|
||||
|
|
@ -174,7 +178,7 @@ Future<void> showLocalPushNotification(
|
|||
title,
|
||||
body,
|
||||
notificationDetails,
|
||||
payload: pushNotification.kind.name,
|
||||
// payload: pushNotification.kind.name,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ Future<void> setupNotificationWithUsers({
|
|||
final pushUser =
|
||||
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
|
||||
final timeBefore =
|
||||
DateTime.now().subtract(Duration(days: 5 + random.nextInt(5)));
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ void initLogger() {
|
|||
Logger.root.level = Level.ALL;
|
||||
Logger.root.onRecord.listen((record) async {
|
||||
await _writeLogToFile(record);
|
||||
if (kDebugMode) {
|
||||
if (!kReleaseMode) {
|
||||
print(
|
||||
'${record.level.name} [twonly] ${record.loggerName} > ${record.message}',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ bool isUUIDNewer(String uuid1, String uuid2) {
|
|||
return timestamp1 > timestamp2;
|
||||
} catch (e) {
|
||||
Log.error(e);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
import 'package:twonly/src/views/camera/camera_preview_controller_view.dart';
|
||||
|
||||
class CameraZoomButtons extends StatefulWidget {
|
||||
|
|
@ -50,6 +50,7 @@ class _CameraZoomButtonsState extends State<CameraZoomButtons> {
|
|||
|
||||
Future<void> initAsync() async {
|
||||
showWideAngleZoom = (await widget.controller.getMinZoomLevel()) < 1;
|
||||
Log.info('Found ${gCameras.length} cameras for zoom.');
|
||||
if (!showWideAngleZoom && Platform.isIOS && gCameras.length == 3) {
|
||||
showWideAngleZoomIOS = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ Future<List<Sticker>> getStickerIndex() async {
|
|||
final indexFile = File('${directory.path}/stickers.json');
|
||||
var res = <Sticker>[];
|
||||
|
||||
if (indexFile.existsSync() && !kDebugMode) {
|
||||
if (indexFile.existsSync() && kReleaseMode) {
|
||||
final lastModified = indexFile.lastModifiedSync();
|
||||
final difference = DateTime.now().difference(lastModified);
|
||||
final content = await indexFile.readAsString();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
|
|
@ -45,10 +47,10 @@ class ReactionRow extends StatelessWidget {
|
|||
child: Center(
|
||||
child: Text(
|
||||
reaction.emoji,
|
||||
style: const TextStyle(fontSize: 18),
|
||||
strutStyle: const StrutStyle(
|
||||
style: TextStyle(fontSize: Platform.isIOS ? 18 : 15),
|
||||
strutStyle: StrutStyle(
|
||||
forceStrutHeight: true,
|
||||
height: 1.6,
|
||||
height: Platform.isIOS ? 1.6 : 1.3,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -114,7 +116,7 @@ class ReactionRow extends StatelessWidget {
|
|||
entry.$2.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontSize: 13,
|
||||
color:
|
||||
isDarkMode(context) ? Colors.white : Colors.black,
|
||||
decoration: TextDecoration.none,
|
||||
|
|
|
|||
|
|
@ -67,9 +67,10 @@ class _ChatMediaEntryState extends State<ChatMediaEntry> {
|
|||
if (widget.message.openedAt == null || widget.message.mediaStored) {
|
||||
return;
|
||||
}
|
||||
if (widget.mediaService.tempPath.existsSync()) {
|
||||
await sendCipherTextToGroup(
|
||||
widget.message.groupId,
|
||||
if (widget.mediaService.tempPath.existsSync() &&
|
||||
widget.message.senderId != null) {
|
||||
await sendCipherText(
|
||||
widget.message.senderId!,
|
||||
EncryptedContent(
|
||||
mediaUpdate: EncryptedContent_MediaUpdate(
|
||||
type: EncryptedContent_MediaUpdate_Type.REOPENED,
|
||||
|
|
|
|||
|
|
@ -77,10 +77,10 @@ class ChatTextEntry extends StatelessWidget {
|
|||
children: [
|
||||
if (info.expanded)
|
||||
Expanded(
|
||||
child: BetterText(text: text, textColor: info.textColor),
|
||||
child: BetterText(text: info.text, textColor: info.textColor),
|
||||
)
|
||||
else ...[
|
||||
BetterText(text: text, textColor: info.textColor),
|
||||
BetterText(text: info.text, textColor: info.textColor),
|
||||
SizedBox(
|
||||
width: info.spacerWidth,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -242,10 +242,10 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
|||
child: Center(
|
||||
child: Text(
|
||||
widget.lastReaction!.emoji,
|
||||
style: const TextStyle(fontSize: 18),
|
||||
style: const TextStyle(fontSize: 15),
|
||||
strutStyle: const StrutStyle(
|
||||
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();
|
||||
downloadStateListener?.cancel();
|
||||
videoController?.dispose();
|
||||
videoController = null;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +142,9 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
|
||||
Future<void> loadCurrentMediaFile({bool showTwonly = false}) async {
|
||||
if (!mounted || !context.mounted) return;
|
||||
if (allMediaFiles.isEmpty) return nextMediaOrExit();
|
||||
if (allMediaFiles.isEmpty || allMediaFiles.first.mediaId == null) {
|
||||
return nextMediaOrExit();
|
||||
}
|
||||
await _noScreenshot.screenshotOff();
|
||||
|
||||
setState(() {
|
||||
|
|
@ -175,7 +178,8 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
downloadTriggered = true;
|
||||
final mediaFile = await twonlyDB.mediaFilesDao
|
||||
.getMediaFileById(allMediaFiles.first.mediaId!);
|
||||
await startDownloadMedia(mediaFile!, true);
|
||||
if (mediaFile == null) return;
|
||||
await startDownloadMedia(mediaFile, true);
|
||||
unawaited(tryDownloadAllMediaFiles(force: true));
|
||||
}
|
||||
return;
|
||||
|
|
@ -269,6 +273,10 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
}
|
||||
});
|
||||
progressTimer = Timer.periodic(const Duration(milliseconds: 10), (timer) {
|
||||
if (currentMedia!.mediaFile.displayLimitInMilliseconds == null ||
|
||||
canBeSeenUntil == null) {
|
||||
return;
|
||||
}
|
||||
final difference = canBeSeenUntil!.difference(DateTime.now());
|
||||
// Calculate the progress as a value between 0.0 and 1.0
|
||||
progress = difference.inMilliseconds /
|
||||
|
|
@ -312,10 +320,12 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
|
||||
void displayShortReactions() {
|
||||
final renderBox =
|
||||
mediaWidgetKey.currentContext!.findRenderObject()! as RenderBox;
|
||||
mediaWidgetKey.currentContext!.findRenderObject() as RenderBox?;
|
||||
setState(() {
|
||||
showShortReactions = true;
|
||||
mediaViewerDistanceFromBottom = renderBox.size.height;
|
||||
if (renderBox != null) {
|
||||
mediaViewerDistanceFromBottom = renderBox.size.height;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class _MaxFlameListTitleState extends State<MaxFlameListTitle> {
|
|||
if (_directChat == null ||
|
||||
_directChat!.maxFlameCounter == 0 ||
|
||||
_flameCounter >= (_directChat!.maxFlameCounter + 1) ||
|
||||
_directChat!.lastFlameCounterChange!
|
||||
_directChat!.maxFlameCounterFrom!
|
||||
.isBefore(DateTime.now().subtract(const Duration(days: 4)))) {
|
||||
return Container();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class _AccountViewState extends State<AccountView> {
|
|||
.where(
|
||||
(x) =>
|
||||
x.transactionType != Response_TransactionTypes.ThanksForTesting ||
|
||||
kDebugMode,
|
||||
!kReleaseMode,
|
||||
)
|
||||
.map((a) => a.depositCents.toInt())
|
||||
.sum;
|
||||
|
|
@ -101,7 +101,7 @@ class _AccountViewState extends State<AccountView> {
|
|||
),
|
||||
)
|
||||
: Text(context.lang.settingsAccountDeleteAccountNoBallance),
|
||||
onLongPress: kDebugMode
|
||||
onLongPress: !kReleaseMode
|
||||
? () async {
|
||||
await deleteLocalUserData();
|
||||
await Restart.restartApp(
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ class _TwonlyIdentityBackupViewState extends State<TwonlyIdentityBackupView> {
|
|||
onPressed: (!isLoading &&
|
||||
(passwordCtrl.text == repeatedPasswordCtrl.text &&
|
||||
passwordCtrl.text.length >= 8 ||
|
||||
kDebugMode))
|
||||
!kReleaseMode))
|
||||
? onPressedEnableTwonlySafe
|
||||
: null,
|
||||
icon: isLoading
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class _AutomatedTestingViewState extends State<AutomatedTestingView> {
|
|||
),
|
||||
body: ListView(
|
||||
children: [
|
||||
if (kDebugMode)
|
||||
if (!kReleaseMode)
|
||||
ListTile(
|
||||
title: const Text('Sending a lot of messages.'),
|
||||
subtitle: Text(lotsOfMessagesStatus),
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class _DeveloperSettingsViewState extends State<DeveloperSettingsView> {
|
|||
);
|
||||
},
|
||||
),
|
||||
// if (kDebugMode)
|
||||
// if (!kReleaseMode)
|
||||
// ListTile(
|
||||
// title: const Text('FlameSync Test'),
|
||||
// onTap: () async {
|
||||
|
|
@ -74,7 +74,7 @@ class _DeveloperSettingsViewState extends State<DeveloperSettingsView> {
|
|||
// await syncFlameCounters();
|
||||
// },
|
||||
// ),
|
||||
if (kDebugMode)
|
||||
if (!kReleaseMode)
|
||||
ListTile(
|
||||
title: const Text('Automated Testing'),
|
||||
onTap: () async {
|
||||
|
|
|
|||
|
|
@ -25,11 +25,26 @@ class _ProfileViewState extends State<ProfileView> {
|
|||
final AvatarMakerController _avatarMakerController =
|
||||
PersistentAvatarMakerController(customizedPropertyCategories: []);
|
||||
|
||||
int twonlyScore = 0;
|
||||
late StreamSubscription<int> twonlyScoreSub;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
twonlyScoreSub =
|
||||
twonlyDB.groupsDao.watchSumTotalMediaCounter().listen((update) {
|
||||
setState(() {
|
||||
twonlyScore = update;
|
||||
});
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
twonlyScoreSub.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> updateUserDisplayName(String displayName) async {
|
||||
await updateUserdata((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: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Card(
|
||||
color: context.color.surfaceContainer,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ class _SelectPaymentViewState extends State<SelectPaymentView> {
|
|||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Card(
|
||||
color: context.color.surfaceContainer,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
|
|
@ -193,6 +194,7 @@ class _SelectPaymentViewState extends State<SelectPaymentView> {
|
|||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Card(
|
||||
color: context.color.surfaceContainer,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
|
|
@ -215,6 +217,7 @@ class _SelectPaymentViewState extends State<SelectPaymentView> {
|
|||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Card(
|
||||
color: context.color.surfaceContainer,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
|
|
|
|||
|
|
@ -444,6 +444,7 @@ class PlanCard extends StatelessWidget {
|
|||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
color: context.color.surfaceContainer,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||
child: Column(
|
||||
|
|
|
|||
Loading…
Reference in a new issue