merge conflicts

pull/1183/head
ggurdin 2 years ago
commit ba72857114

@ -2504,7 +2504,7 @@
"type": "text",
"placeholders": {}
},
"interactiveTranslatorAllowedDesc": "Students can choose whether to use translation assistance in space group chats in Settings > Learning Settings.",
"interactiveTranslatorAllowedDesc": "Students can choose whether to use translation assistance in space group chats in Main Menu > My Learning Settings.",
"@interactiveTranslatorAllowedDesc": {
"type": "text",
"placeholders": {}
@ -2984,9 +2984,9 @@
"errorDisableLanguageAssistanceClassDesc": "Translation assistance and grammar assistance are turned off for the space that this chat is in.",
"itIsDisabled": "Interactive Translation is disabled",
"igcIsDisabled": "Interactive Grammar Checking is disabled",
"goToLearningSettings": "Go to Learning Settings",
"goToLearningSettings": "Go to My Learning Settings",
"error405Title": "Languages not set",
"error405Desc": "Please set your languages in Settings > Learning Settings",
"error405Desc": "Please set your languages in Main Menu > My Learning Settings.",
"loginOrSignup": "Sign in with",
"@loginOrSignup": {
"type": "text",
@ -3049,7 +3049,7 @@
"type": "text",
"placeholders": {}
},
"learningSettings": "Learning Settings",
"learningSettings": "My Learning Settings",
"classNameRequired": "Please enter a space name",
"@classNameRequired": {
"type": "text",
@ -3674,7 +3674,7 @@
"bestAnswerFeedback": "That's correct!",
"definitionDefaultPrompt": "What does this word mean?",
"practiceDefaultPrompt": "What is the best answer?",
"correctionDefaultPrompt": "What is the best correction?",
"correctionDefaultPrompt": "What is the best replacement?",
"itStartDefaultPrompt": "Do you want help translating?",
"languageLevelWarning": "Please select a class language level",
"lockedChatWarning": "🔒 This chat has been locked",
@ -3946,5 +3946,7 @@
"points": "Points",
"noPaymentInfo": "No payment info necessary!",
"studentAnalyticsNotAvailable": "Student data not currently available",
"roomDataMissing": "Some data may be missing from rooms in which you are not a member."
"roomDataMissing": "Some data may be missing from rooms in which you are not a member.",
"updatePhoneOS": "You may need to update your device's OS version.",
"wordsPerMinute": "Words per minute"
}

@ -4389,7 +4389,7 @@
"bestAnswerFeedback": "¡Correcto!",
"definitionDefaultPrompt": "¿Qué significa esta palabra?",
"practiceDefaultPrompt": "¿Cuál es la mejor respuesta?",
"correctionDefaultPrompt": "¿Cuál es la mejor corrección?",
"correctionDefaultPrompt": "¿Cuál es el mejor reemplazo?",
"itStartDefaultPrompt": "¿Quiere ayuda para traducir?",
"suggestTo": "Sugerir a {spaceName}",
"suggestChatDesc": "Los chats sugeridos aparecerán en la lista de chats de {spaceName}.",
@ -4587,5 +4587,52 @@
"refresh": "Actualizar",
"joinToView": "Únete a esta sala para ver los detalles",
"autoPlayTitle": "Reproducción automática de mensajes",
"autoPlayDesc": "Cuando está activado, el audio de texto a voz de los mensajes se reproducirá automáticamente cuando se seleccione."
"autoPlayDesc": "Cuando está activado, el audio de texto a voz de los mensajes se reproducirá automáticamente cuando se seleccione.",
"presenceStyle": "Presencia:",
"presencesToggle": "Mostrar mensajes de estado de otros usuarios",
"writeAMessageFlag": "Escribe un mensaje en {l1flag} o {l2flag}...",
"@writeAMessageFlag": {
"type": "text",
"placeholders": {
"l1flag": {},
"l2flag": {}
}
},
"youInvitedToBy": "📩 Has sido invitado a través de un enlace a:\n{alias}",
"@youInvitedToBy": {
"placeholders": {
"alias": {}
}
},
"hidePresences": "¿Ocultar la lista de estados?",
"sendReadReceipts": "Enviar recibos de lectura",
"sendTypingNotificationsDescription": "Los demás participantes en un chat pueden ver cuándo estás escribiendo un nuevo mensaje.",
"sendReadReceiptsDescription": "Los demás participantes en un chat pueden ver cuándo has leído un mensaje.",
"formattedMessages": "Mensajes con formato",
"formattedMessagesDescription": "Mostrar contenido de mensajes enriquecido como texto en negrita utilizando markdown.",
"verifyOtherUser": "🔐 Verificar otro usuario",
"verifyOtherUserDescription": "Si verificas a otro usuario, puedes estar seguro de saber a quién estás escribiendo realmente. 💪\n\nCuando inicies una verificación, tú y el otro usuario veréis una ventana emergente en la aplicación. Allí veréis una serie de emojis o números que tendréis que comparar entre vosotros.\n\nLa mejor forma de hacerlo es quedar o iniciar una videollamada. 👭",
"verifyOtherDevice": "🔐 Verificar otro dispositivo",
"verifyOtherDeviceDescription": "Cuando verificas otro dispositivo, esos dispositivos pueden intercambiar claves, aumentando tu seguridad general. 💪 Cuando inicies una verificación, aparecerá una ventana emergente en la app de ambos dispositivos. Allí verás entonces una serie de emojis o números que tienes que comparar entre sí. Lo mejor es que tengas ambos dispositivos a mano antes de iniciar la verificación. 🤳",
"transparent": "Transparente",
"incomingMessages": "Mensajes entrantes",
"stickers": "Pegatinas",
"commandHint_ignore": "Ignorar el ID de matriz dado",
"commandHint_unignore": "Designorar el ID de matriz dado",
"unreadChatsInApp": "{appname}: {unread} chats no leídos",
"@unreadChatsInApp": {
"type": "text",
"placeholders": {
"appname": {},
"unread": {}
}
},
"messageAnalytics": "Análisis de mensajes",
"words": "Palabras",
"score": "Puntuación",
"accuracy": "Precisión",
"points": "Puntos",
"noPaymentInfo": "No se necesitan datos de pago.",
"updatePhoneOS": "Puede que necesites actualizar la versión del sistema operativo de tu dispositivo.",
"wordsPerMinute": "Palabras por minuto"
}

@ -29,6 +29,8 @@ abstract class AppConfig {
static const Color primaryColorLight = Color(0xFFDBC9FF);
static const Color secondaryColor = Color(0xFF41a2bc);
static const Color activeToggleColor = Color(0xFF33D057);
static const Color success = Color(0xFF33D057);
static const Color warning = Color.fromARGB(255, 210, 124, 12);
// static String _privacyUrl =
// 'https://gitlab.com/famedly/fluffychat/-/blob/main/PRIVACY.md';
static String _privacyUrl = "https://www.pangeachat.com/privacy";

@ -26,7 +26,6 @@ import 'package:fluffychat/pages/settings_security/settings_security.dart';
import 'package:fluffychat/pages/settings_style/settings_style.dart';
import 'package:fluffychat/pangea/guard/p_vguard.dart';
import 'package:fluffychat/pangea/pages/analytics/student_analytics/student_analytics.dart';
import 'package:fluffychat/pangea/pages/class_settings/class_settings_page.dart';
import 'package:fluffychat/pangea/pages/exchange/add_exchange_to_class.dart';
import 'package:fluffychat/pangea/pages/find_partner/find_partner.dart';
import 'package:fluffychat/pangea/pages/p_user_age/p_user_age.dart';
@ -150,19 +149,6 @@ abstract class AppRoutes {
: child,
),
routes: [
// #Pangea
GoRoute(
path: '/spaces/:roomid',
pageBuilder: (context, state) => defaultPageBuilder(
context,
state,
ChatDetails(
roomId: state.pathParameters['roomid']!,
),
),
redirect: loggedOutRedirect,
),
// Pangea#
GoRoute(
path: '/rooms',
redirect: loggedOutRedirect,
@ -521,17 +507,6 @@ abstract class AppRoutes {
),
redirect: loggedOutRedirect,
),
// #Pangea
GoRoute(
path: 'class_settings',
pageBuilder: (context, state) => defaultPageBuilder(
context,
state,
const ClassSettingsPage(),
),
redirect: loggedOutRedirect,
),
// Pangea#
GoRoute(
path: 'invite',
pageBuilder: (context, state) => defaultPageBuilder(

@ -481,7 +481,16 @@ class ChatController extends State<ChatPageWithRoom>
}
// Do not send read markers when app is not in foreground
if (kIsWeb && !Matrix.of(context).webHasFocus) return;
// #Pangea
try {
// Pangea#
if (kIsWeb && !Matrix.of(context).webHasFocus) return;
// #Pangea
} catch (err, s) {
ErrorHandler.logError(e: err, s: s);
return;
}
// Pangea#
if (!kIsWeb &&
WidgetsBinding.instance.lifecycleState != AppLifecycleState.resumed) {
return;

@ -167,9 +167,10 @@ class Message extends StatelessWidget {
// #Pangea
ToolbarDisplayController? toolbarController;
if (event.type == EventTypes.Message &&
event.messageType == MessageTypes.Text ||
event.messageType == MessageTypes.Notice ||
event.messageType == MessageTypes.Audio) {
!event.redacted &&
(event.messageType == MessageTypes.Text ||
event.messageType == MessageTypes.Notice ||
event.messageType == MessageTypes.Audio)) {
toolbarController = controller.getToolbarDisplayController(
event.eventId,
nextEvent: nextEvent,

@ -1,6 +1,7 @@
import 'dart:async';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/utils/update_version_dialog.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@ -27,7 +28,10 @@ class RecordingDialogState extends State<RecordingDialog> {
bool error = false;
String? _recordedPath;
final _audioRecorder = Record();
// #Pangea
// final _audioRecorder = Record();
final _audioRecorder = AudioRecorder();
// Pangea#
final List<double> amplitudeTimeline = [];
static const int bitRate = 64000;
@ -45,13 +49,28 @@ class RecordingDialogState extends State<RecordingDialog> {
return;
}
await WakelockPlus.enable();
await _audioRecorder.start(
path: _recordedPath,
bitRate: bitRate,
samplingRate: samplingRate,
encoder: AudioEncoder.wav,
numChannels: 1,
// #Pangea
final bool isNotError = await showUpdateVersionDialog(
future: () =>
// Pangea#
_audioRecorder.start(
path: _recordedPath!,
const RecordConfig(
bitRate: bitRate,
sampleRate: samplingRate,
encoder: AudioEncoder.wav,
numChannels: 1,
),
),
// #Pangea
context: context,
);
if (!isNotError) {
Navigator.of(context).pop();
return;
}
// Pangea#
setState(() => _duration = Duration.zero);
_recorderSubscription?.cancel();
_recorderSubscription =

@ -61,11 +61,22 @@ class ChatDetailsView extends StatelessWidget {
);
return Scaffold(
appBar: AppBar(
leading: controller.widget.embeddedCloseButton ??
const Center(child: BackButton()),
leading:
// #Pangea
!room.isSpace
?
// Pangea#
controller.widget.embeddedCloseButton ??
const Center(child: BackButton())
// #Pangea
: BackButton(
onPressed: () => context.go("/rooms"),
)
// Pangea#
,
elevation: Theme.of(context).appBarTheme.elevation,
actions: <Widget>[
// #Pangeas
// #Pangea
//if (room.canonicalAlias.isNotEmpty)
// IconButton(
// tooltip: L10n.of(context)!.share,

@ -75,7 +75,12 @@ class ChatListView extends StatelessWidget {
label: L10n.of(context)!.allChats,
// Pangea#
),
if (controller.spaces.isNotEmpty)
if (controller.spaces.isNotEmpty
// #Pangea
&&
!FluffyThemes.isColumnMode(context)
// Pangea#
)
// #Pangea
// const NavigationDestination(
// icon: Icon(Icons.workspaces_outlined),

@ -154,6 +154,18 @@ class ClientChooserButton extends StatelessWidget {
],
),
),
// #Pangea
PopupMenuItem(
value: SettingsAction.learning,
child: Row(
children: [
const Icon(Icons.psychology_outlined),
const SizedBox(width: 18),
Expanded(child: Text(L10n.of(context)!.learningSettings)),
],
),
),
// Pangea#
PopupMenuItem(
value: SettingsAction.settings,
child: Row(
@ -382,6 +394,9 @@ class ClientChooserButton extends StatelessWidget {
case SettingsAction.setStatus:
controller.setStatus();
// #Pangea
case SettingsAction.learning:
context.go('/rooms/settings/learning');
break;
case SettingsAction.newClass:
context.go('/rooms/newspace');
break;
@ -493,6 +508,7 @@ enum SettingsAction {
settings,
archive,
// #Pangea
learning,
joinWithClassCode,
classAnalytics,
myAnalytics,

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:collection/collection.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat_list/chat_list.dart';
import 'package:fluffychat/pages/chat_list/chat_list_item.dart';
import 'package:fluffychat/pages/chat_list/search_title.dart';
@ -47,11 +48,23 @@ class _SpaceViewState extends State<SpaceView> {
// #Pangea
StreamSubscription<SyncUpdate>? _roomSubscription;
bool refreshing = false;
final String _chatCountsKey = 'chatCounts';
Map<String, int> get chatCounts => Map.from(
widget.controller.pangeaController.pStoreService.read(
_chatCountsKey,
local: true,
) ??
{},
);
// Pangea#
@override
void initState() {
loadHierarchy();
// #Pangea
loadChatCounts();
// Pangea#
super.initState();
}
@ -74,9 +87,15 @@ class _SpaceViewState extends State<SpaceView> {
// Pangea#
}
Future<GetSpaceHierarchyResponse> loadHierarchy([String? prevBatch]) async {
Future<GetSpaceHierarchyResponse> loadHierarchy([
String? prevBatch,
// #Pangea
String? spaceId,
// Pangea#
]) async {
// #Pangea
if (widget.controller.activeSpaceId == null || loading) {
if ((widget.controller.activeSpaceId == null && spaceId == null) ||
loading) {
return GetSpaceHierarchyResponse(
rooms: [],
nextBatch: null,
@ -89,7 +108,10 @@ class _SpaceViewState extends State<SpaceView> {
});
// Pangea#
final activeSpaceId = widget.controller.activeSpaceId!;
// #Pangea
// final activeSpaceId = widget.controller.activeSpaceId!;
final activeSpaceId = (widget.controller.activeSpaceId ?? spaceId)!;
// Pangea#
final client = Matrix.of(context).client;
final activeSpace = client.getRoomById(activeSpaceId);
@ -122,6 +144,14 @@ class _SpaceViewState extends State<SpaceView> {
});
rethrow;
} finally {
// #Pangea
if (activeSpace != null) {
await setChatCount(
activeSpace,
_lastResponse[activeSpaceId],
);
}
// Pangea#
setState(() {
loading = false;
});
@ -174,7 +204,7 @@ class _SpaceViewState extends State<SpaceView> {
if (spaceChild.roomId == widget.controller.activeSpaceId) {
// #Pangea
// context.go('/rooms/${spaceChild.roomId}');
context.push('/spaces/${spaceChild.roomId}');
context.go('/rooms/${spaceChild.roomId}/details');
// Pangea#
} else {
widget.controller.setActiveSpace(spaceChild.roomId);
@ -387,6 +417,14 @@ class _SpaceViewState extends State<SpaceView> {
}
// #Pangea
Future<void> loadChatCounts() async {
for (final Room room in Matrix.of(context).client.rooms) {
if (room.isSpace && !chatCounts.containsKey(room.id)) {
await loadHierarchy(null, room.id);
}
}
}
Future<void> refreshOnUpdate(SyncUpdate event) async {
/* refresh on leave, invite, and space child update
not join events, because there's already a listener on
@ -424,6 +462,78 @@ class _SpaceViewState extends State<SpaceView> {
);
return !isAnalyticsRoom && (isMember || isSuggested);
}
List<SpaceRoomsChunk> filterSpaceChildren(
Room space,
List<SpaceRoomsChunk> spaceChildren,
) {
final childIds =
spaceChildren.map((hierarchyMember) => hierarchyMember.roomId);
final matchingSpaceChildren = space.spaceChildren
.where((spaceChild) => childIds.contains(spaceChild.roomId))
.toList();
final filteredSpaceChildren = spaceChildren
.where(
(sc) => includeSpaceChild(
sc,
matchingSpaceChildren,
),
)
.toList();
return filteredSpaceChildren;
}
int sortSpaceChildren(
SpaceRoomsChunk a,
SpaceRoomsChunk b,
) {
final bool aIsSpace = a.roomType == 'm.space';
final bool bIsSpace = b.roomType == 'm.space';
if (aIsSpace && !bIsSpace) {
return -1;
} else if (!aIsSpace && bIsSpace) {
return 1;
}
return 0;
}
Future<void> setChatCount(
Room space,
GetSpaceHierarchyResponse? response,
) async {
final Map<String, int> updatedChatCounts = Map.from(chatCounts);
final List<SpaceRoomsChunk> spaceChildren = response?.rooms ?? [];
final filteredChildren = filterSpaceChildren(space, spaceChildren)
.where((sc) => sc.roomId != space.id)
.toList();
updatedChatCounts[space.id] = filteredChildren.length;
await widget.controller.pangeaController.pStoreService.save(
_chatCountsKey,
updatedChatCounts,
local: true,
);
}
bool roomCountLoading(Room space) =>
space.membership == Membership.join && !chatCounts.containsKey(space.id);
Widget spaceSubtitle(Room space) {
if (roomCountLoading(space)) {
return const CircularProgressIndicator.adaptive();
}
return Text(
space.membership == Membership.join
? L10n.of(context)!.numChats(
chatCounts[space.id].toString(),
)
: L10n.of(context)!.youreInvited,
);
}
// Pangea#
@override
@ -485,13 +595,7 @@ class _SpaceViewState extends State<SpaceView> {
// #Pangea
subtitle: Row(
children: [
Text(
rootSpace.membership == Membership.join
? L10n.of(context)!.numChats(
rootSpace.spaceChildren.length.toString(),
)
: L10n.of(context)!.youreInvited,
),
spaceSubtitle(rootSpace),
if (rootSpace.locked)
const Padding(
padding: EdgeInsets.only(left: 4.0),
@ -558,12 +662,25 @@ class _SpaceViewState extends State<SpaceView> {
titleSpacing: 0,
title: ListTile(
leading: BackButton(
onPressed: () =>
widget.controller.setActiveSpace(parentSpace?.id),
// #Pangea
onPressed: () {
!FluffyThemes.isColumnMode(context) ||
parentSpace?.id != null
? widget.controller.setActiveSpace(parentSpace?.id)
: widget.controller.onDestinationSelected(0);
},
// onPressed: () =>
// widget.controller.setActiveSpace(parentSpace?.id),
// Pangea#
),
title: Text(
parentSpace == null
? L10n.of(context)!.allSpaces
// #Pangea
// ? L10n.of(context)!.allSpaces
? !FluffyThemes.isColumnMode(context)
? L10n.of(context)!.allSpaces
: L10n.of(context)!.allChats
// Pangea#
: parentSpace.getLocalizedDisplayname(
MatrixLocals(L10n.of(context)!),
),
@ -624,35 +741,9 @@ class _SpaceViewState extends State<SpaceView> {
final space =
Matrix.of(context).client.getRoomById(activeSpaceId);
if (space != null) {
final matchingSpaceChildren = space.spaceChildren
.where(
(spaceChild) => spaceChildren
.map((hierarchyMember) => hierarchyMember.roomId)
.contains(spaceChild.roomId),
)
.toList();
spaceChildren = spaceChildren
.where(
(sc) => includeSpaceChild(
sc,
matchingSpaceChildren,
),
)
.toList();
spaceChildren = filterSpaceChildren(space, spaceChildren);
}
spaceChildren.sort((a, b) {
final bool aIsSpace = a.roomType == 'm.space';
final bool bIsSpace = b.roomType == 'm.space';
if (aIsSpace && !bIsSpace) {
return -1;
} else if (!aIsSpace && bIsSpace) {
return 1;
}
return 0;
});
spaceChildren.sort(sortSpaceChildren);
// Pangea#
final canLoadMore = response.nextBatch != null;
return SliverList(
@ -727,8 +818,8 @@ class _SpaceViewState extends State<SpaceView> {
),
// #Pangea
// onTap: () => _onJoinSpaceChild(spaceChild),
onTap: () => context.push(
'/spaces/${spaceChild.roomId}',
onTap: () => context.go(
'/rooms/${spaceChild.roomId}/details',
),
// Pangea#
),

@ -91,7 +91,7 @@ class NewGroupView extends StatelessWidget {
const Divider(height: 1),
AddToSpaceToggles(
key: controller.addToSpaceKey,
startOpen: false,
startOpen: true,
activeSpaceId: controller.activeSpaceId,
mode: AddToClassMode.chat,
),

@ -216,7 +216,7 @@ class NewSpaceController extends State<NewSpace> {
);
MatrixState.pangeaController.classController
.setActiveSpaceIdInChatListController(spaceId);
context.push('/spaces/$spaceId');
context.go("/rooms/$spaceId/details");
return;
}
@ -245,7 +245,7 @@ class NewSpaceController extends State<NewSpace> {
// context.pop<String>(spaceId);
MatrixState.pangeaController.classController
.setActiveSpaceIdInChatListController(spaceId);
context.push('/spaces/$spaceId');
context.go("/rooms/$spaceId/details");
// Pangea#
} catch (e) {
setState(() {

@ -138,7 +138,7 @@ class NewSpaceView extends StatelessWidget {
if (!controller.newClassMode)
AddToSpaceToggles(
key: controller.addToSpaceKey,
startOpen: false,
startOpen: true,
mode: !controller.newClassMode
? AddToClassMode.exchange
: AddToClassMode.chat,

@ -181,14 +181,6 @@ class SettingsView extends StatelessWidget {
trailing: const Icon(Icons.chevron_right_outlined),
),
// #Pangea
ListTile(
leading: const Icon(Icons.account_circle_outlined),
title: Text(L10n.of(context)!.learningSettings),
onTap: () => context.go('/rooms/settings/learning'),
trailing: const Icon(
Icons.chevron_right_outlined,
),
),
ListTile(
leading: const Icon(Icons.account_circle_outlined),
title: Text(L10n.of(context)!.subscriptionManagement),

@ -74,18 +74,21 @@ class SpeechToTextController {
}
debugPrint('Saving transcript as matrix event');
requestModel.audioEvent?.room.sendPangeaEvent(
content: PangeaRepresentation(
langCode: response.langCode,
text: response.transcript.text,
originalSent: false,
originalWritten: false,
speechToText: response,
).toJson(),
parentEventId: requestModel.audioEvent!.eventId,
type: PangeaEventTypes.representation,
);
debugPrint('Transcript saved as matrix event');
requestModel.audioEvent?.room
.sendPangeaEvent(
content: PangeaRepresentation(
langCode: response.langCode,
text: response.transcript.text,
originalSent: false,
originalWritten: false,
speechToText: response,
).toJson(),
parentEventId: requestModel.audioEvent!.eventId,
type: PangeaEventTypes.representation,
)
.then(
(_) => debugPrint('Transcript saved as matrix event'),
);
return Future.value(null);
}

@ -60,7 +60,7 @@ class PangeaToken {
static const String _lemmaKey = ModelKey.lemma;
Map<String, dynamic> toJson() => {
_textKey: text,
_textKey: text.toJson(),
_hasInfoKey: hasInfo,
_lemmaKey: lemmas.map((e) => e.toJson()).toList(),
};

@ -1,11 +1,14 @@
import 'dart:convert';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/enum/audio_encoding_enum.dart';
import 'package:fluffychat/pangea/models/pangea_token_model.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
const int THRESHOLD_FOR_GREEN = 80;
class SpeechToTextAudioConfigModel {
final AudioEncodingEnum encoding;
final int sampleRateHertz;
@ -93,13 +96,10 @@ class STTToken {
? Colors.white
: Colors.black);
}
if (confidence! > 80) {
return const Color.fromARGB(255, 0, 152, 0);
}
if (confidence! > 50) {
return const Color.fromARGB(255, 184, 142, 43);
if (confidence! > THRESHOLD_FOR_GREEN) {
return AppConfig.success;
}
return Colors.red;
return AppConfig.warning;
}
factory STTToken.fromJson(Map<String, dynamic> json) {
@ -107,17 +107,17 @@ class STTToken {
return STTToken(
token: PangeaToken.fromJson(json['token']),
startTime: json['start_time'] != null
? Duration(milliseconds: json['start_time'] * 1000.toInt())
? Duration(milliseconds: (json['start_time'] * 1000).round())
: null,
endTime: json['end_time'] != null
? Duration(milliseconds: json['end_time'] * 1000.toInt())
? Duration(milliseconds: (json['end_time'] * 1000).round())
: null,
confidence: json['confidence'],
);
}
Map<String, dynamic> toJson() => {
"token": token,
"token": token.toJson(),
"start_time": startTime?.inMilliseconds,
"end_time": endTime?.inMilliseconds,
"confidence": confidence,
@ -150,14 +150,19 @@ class Transcript {
final int confidence;
final List<STTToken> sttTokens;
final String langCode;
final int? wordsPerHr;
Transcript({
required this.text,
required this.confidence,
required this.sttTokens,
required this.langCode,
required this.wordsPerHr,
});
/// Returns the number of words per minute rounded to one decimal place.
double? get wordsPerMinute => wordsPerHr != null ? wordsPerHr! / 60 : null;
factory Transcript.fromJson(Map<String, dynamic> json) => Transcript(
text: json['transcript'],
confidence: json['confidence'] <= 100
@ -167,6 +172,7 @@ class Transcript {
.map((e) => STTToken.fromJson(e))
.toList(),
langCode: json['lang_code'],
wordsPerHr: json['words_per_hr'],
);
Map<String, dynamic> toJson() => {
@ -174,7 +180,15 @@ class Transcript {
"confidence": confidence,
"stt_tokens": sttTokens.map((e) => e.toJson()).toList(),
"lang_code": langCode,
"words_per_hr": wordsPerHr,
};
Color color(BuildContext context) {
if (confidence > THRESHOLD_FOR_GREEN) {
return AppConfig.success;
}
return AppConfig.warning;
}
}
class SpeechToTextResult {

@ -1,96 +0,0 @@
import 'dart:async';
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/widgets/layouts/empty_page.dart';
import '../../../widgets/matrix.dart';
import '../../utils/error_handler.dart';
import '../../utils/set_class_name.dart';
import '../../widgets/space/class_settings.dart';
import 'class_settings_view.dart';
import 'p_class_widgets/room_rules_editor.dart';
class ClassSettingsPage extends StatefulWidget {
const ClassSettingsPage({super.key});
@override
State<ClassSettingsPage> createState() => ClassSettingsController();
}
class ClassSettingsController extends State<ClassSettingsPage> {
PangeaController pangeaController = MatrixState.pangeaController;
final GlobalKey<RoomRulesState> rulesEditorKey = GlobalKey<RoomRulesState>();
final GlobalKey<ClassSettingsState> classSettingsKey =
GlobalKey<ClassSettingsState>();
Room? room;
String? get roomId => GoRouterState.of(context).pathParameters['roomid'];
Future<void> handleSave(BuildContext context) async {
if (classSettingsKey.currentState!.sameLanguages) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(L10n.of(context)!.noIdenticalLanguages),
),
);
return;
}
if (rulesEditorKey.currentState != null) {
await rulesEditorKey.currentState?.setRoomRules(roomId!);
} else {
debugger(when: kDebugMode);
ErrorHandler.logError(m: "Null rules editor state");
}
if (classSettingsKey.currentState != null) {
await classSettingsKey.currentState?.setClassSettings(
roomId!,
);
} else {
debugger(when: kDebugMode);
ErrorHandler.logError(m: "Null class settings state");
}
}
void goback(BuildContext context) {
context.push("/spaces/$roomId");
}
String get className =>
Matrix.of(context).client.getRoomById(roomId!)?.name ?? '';
@override
void initState() {
// TODO: implement initState
super.initState();
Future.delayed(Duration.zero, () {
room = Matrix.of(context).client.getRoomById(roomId!);
if (room == null) {
debugger(when: kDebugMode);
context.pop();
}
setState(() {});
});
}
//PTODO - show loading widget
void setDisplaynameAction() => setClassDisplayname(context, roomId);
bool showEditNameIcon = false;
void hoverEditNameIcon(bool hovering) =>
setState(() => showEditNameIcon = !showEditNameIcon);
@override
Widget build(BuildContext context) => room != null
? ClassSettingsPageView(controller: this)
: const EmptyPage();
}

@ -1,85 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:go_router/go_router.dart';
import 'package:fluffychat/pangea/pages/class_settings/class_settings_page.dart';
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_rules_editor.dart';
import 'package:fluffychat/pangea/widgets/space/class_settings.dart';
import '../../../widgets/layouts/max_width_body.dart';
class ClassSettingsPageView extends StatelessWidget {
final ClassSettingsController controller;
const ClassSettingsPageView({super.key, required this.controller});
@override
Widget build(BuildContext context) {
debugPrint("in class settings page with roomId ${controller.roomId}");
// PTODO-Lala - make the page scrollable anywhere, not just in the area of the elements
// so like, the user should be able scroll using the mouse wheel from anywhere within this view
// currently, your cursor needs be horizontally within the tiles in order to scroll
return Scaffold(
appBar: AppBar(
leading: GoRouterState.of(context).path?.startsWith('/spaces/') ?? false
? null
: IconButton(
icon: const Icon(Icons.close_outlined),
onPressed: () => controller.goback(context),
),
centerTitle: true,
title: Text(L10n.of(context)!.classSettings),
),
body: ListView(
children: [
MaxWidthBody(
child: ListTile(
title: Center(
child: TextButton.icon(
onPressed: controller.setDisplaynameAction,
onHover: controller.hoverEditNameIcon,
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 25),
),
label: Visibility(
visible: controller.showEditNameIcon,
child: Icon(
Icons.edit,
color: Theme.of(context).colorScheme.onBackground,
),
),
icon: Text(
controller.className,
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
MaxWidthBody(
child: Column(
children: [
ClassSettings(
roomId: controller.roomId,
startOpen: true,
),
RoomRulesEditor(roomId: controller.roomId),
],
),
),
],
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => showFutureLoadingDialog(
context: context,
future: () => controller.handleSave(context),
),
label: Text(L10n.of(context)!.saveChanges),
icon: const Icon(Icons.save_outlined),
),
);
}
}

@ -1,41 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:go_router/go_router.dart';
class ClassSettingsButton extends StatelessWidget {
const ClassSettingsButton({super.key});
// final PangeaController _pangeaController = MatrixState.pangeaController;
@override
Widget build(BuildContext context) {
// final roomId = GoRouterState.of(context).pathParameters['roomid'];
final iconColor = Theme.of(context).textTheme.bodyLarge!.color;
return Column(
children: [
ListTile(
// enabled: roomId != null &&
// _pangeaController.classController
// .getClassModelBySpaceIdLocal(roomId) !=
// null,
title: Text(
L10n.of(context)!.classSettings,
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
),
),
subtitle: Text(L10n.of(context)!.classSettingsDesc),
leading: CircleAvatar(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
foregroundColor: iconColor,
child: const Icon(Icons.settings_outlined),
),
onTap: () => context.go('/class_settings'),
),
],
);
}
}

@ -1,122 +0,0 @@
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart' as sdk;
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/pages/new_class/new_class_view.dart';
import 'package:fluffychat/pangea/utils/class_code.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../controllers/pangea_controller.dart';
import '../../widgets/space/class_settings.dart';
import '../class_settings/p_class_widgets/room_rules_editor.dart';
class NewClass extends StatefulWidget {
const NewClass({super.key});
@override
NewClassController createState() => NewClassController();
}
class NewClassController extends State<NewClass> {
TextEditingController controller = TextEditingController();
final PangeaController pangeaController = MatrixState.pangeaController;
final GlobalKey<RoomRulesState> rulesEditorKey = GlobalKey<RoomRulesState>();
final GlobalKey<ClassSettingsState> classSettingsKey =
GlobalKey<ClassSettingsState>();
void submitAction([_]) async {
//TODO: validate that object is complete
final matrix = Matrix.of(context);
if (controller.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(L10n.of(context)!.classNameRequired),
),
);
return;
}
if (classSettingsKey.currentState == null) {
debugger(when: kDebugMode);
}
if (classSettingsKey.currentState!.sameLanguages) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(L10n.of(context)!.noIdenticalLanguages),
),
);
return;
}
final roomID = await showFutureLoadingDialog(
context: context,
future: () async {
final String roomID = await matrix.client.createRoom(
//PTODO - investigate effects of changing visibility from public
preset: sdk.CreateRoomPreset.publicChat,
creationContent: {
'type': RoomCreationTypes.mSpace,
},
visibility: sdk.Visibility.public,
// roomAliasName: controller.text.isNotEmpty
// ? "${matrix.client.userID!.localpart}-${controller.text.trim().toLowerCase().replaceAll(' ', '_')}"
// : null,
roomAliasName: ClassCodeUtil.generateClassCode(),
name: controller.text.isNotEmpty ? controller.text : null,
);
if (rulesEditorKey.currentState != null) {
await rulesEditorKey.currentState!.setRoomRules(roomID);
} else {
debugger(when: kDebugMode);
ErrorHandler.logError(m: "Null rules editor state");
}
if (classSettingsKey.currentState != null) {
await classSettingsKey.currentState!.setClassSettings(
roomID,
);
} else {
debugger(when: kDebugMode);
ErrorHandler.logError(m: "Null class settings state");
}
return roomID;
},
onError: (e) {
debugger(when: kDebugMode);
return e;
},
);
if (roomID.error == null && roomID.result is String) {
pangeaController.classController.setActiveSpaceIdInChatListController(
roomID.result!,
);
context.push('/spaces/${roomID.result!}');
} else {
debugger(when: kDebugMode);
ErrorHandler.logError(e: roomID.error, s: StackTrace.current);
}
}
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => NewSpaceView(this);
}

@ -1,88 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/pangea/constants/class_default_values.dart';
import 'package:fluffychat/pangea/pages/new_class/new_class.dart';
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
import '../../widgets/space/class_settings.dart';
import '../class_settings/p_class_widgets/room_rules_editor.dart';
class NewSpaceView extends StatelessWidget {
// #Pangea
// final NewSpaceController controller;
final NewClassController controller;
// Pangea#
const NewSpaceView(this.controller, {super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// #Pangea
centerTitle: true,
// Pangea#
title: Text(L10n.of(context)!.createNewClass),
),
body: MaxWidthBody(
// #Pangea
child: ListView(
// child: Column(
// mainAxisSize: MainAxisSize.min,
// #Pangea
children: <Widget>[
Padding(
padding: const EdgeInsets.all(12.0),
child: TextField(
// #Pangea
maxLength: ClassDefaultValues.maxClassName,
maxLengthEnforcement: MaxLengthEnforcement.enforced,
// #Pangea
controller: controller.controller,
autofocus: true,
autocorrect: false,
textInputAction: TextInputAction.go,
onSubmitted: controller.submitAction,
decoration: InputDecoration(
labelText: L10n.of(context)!.spaceName,
prefixIcon: const Icon(Icons.people_outlined),
hintText: L10n.of(context)!.enterASpacepName,
),
),
),
// #Pangea
ClassSettings(
key: controller.classSettingsKey,
roomId: null,
startOpen: true,
),
RoomRulesEditor(
key: controller.rulesEditorKey,
roomId: null,
),
const SizedBox(height: 45),
// SwitchListTile.adaptive(
// title: Text(L10n.of(context)!.spaceIsPublic),
// value: controller.publicGroup,
// onChanged: controller.setPublicGroup,
// ),
// ListTile(
// trailing: const Padding(
// padding: EdgeInsets.symmetric(horizontal: 16.0),
// child: Icon(Icons.info_outlined),
// ),
// subtitle: Text(L10n.of(context)!.newSpaceDescription),
// ),
// #Pangea
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: controller.submitAction,
child: const Icon(Icons.arrow_forward_outlined),
),
);
}
}

@ -65,7 +65,7 @@ class SettingsLearningView extends StatelessWidget {
defaultValue: controller.pangeaController.pStoreService.read(
PLocalKey.autoPlayMessages,
) ??
true,
false,
title: L10n.of(context)!.autoPlayTitle,
subtitle: L10n.of(context)!.autoPlayDesc,
pStoreKey: PLocalKey.autoPlayMessages,

@ -1,11 +1,9 @@
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/widgets/matrix.dart';
bool canAddToSpace(Room space, PangeaController pangeaController) {
final bool pangeaPermission =
pangeaController.permissionsController.canUserGroupChat(roomID: space.id);
@ -27,8 +25,9 @@ Future<void> pangeaAddToSpace(
Room space,
List<String> selectedRoomIds,
BuildContext context,
PangeaController pangeaController,
) async {
PangeaController pangeaController, {
bool suggested = true,
}) async {
if (!canAddToSpace(space, pangeaController)) {
throw L10n.of(context)!.noAddToSpacePermissions;
}
@ -37,6 +36,6 @@ Future<void> pangeaAddToSpace(
if (room != null && chatIsInSpace(room, space)) {
throw L10n.of(context)!.alreadyInSpace;
}
await space.setSpaceChild(roomId);
await space.setSpaceChild(roomId, suggested: suggested);
}
}

@ -1,3 +1,4 @@
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:flutter/material.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
@ -39,7 +40,17 @@ class PangeaAnyState {
void closeOverlay() {
if (overlay != null) {
overlay?.remove();
try {
overlay?.remove();
} catch (err, s) {
ErrorHandler.logError(
e: err,
s: s,
data: {
"overlay": overlay,
},
);
}
overlay = null;
}
}

@ -21,7 +21,7 @@ void chatListHandleSpaceTap(
controller.setActiveSpace(space.id);
if (FluffyThemes.isColumnMode(context)) {
context.push('/spaces/${space.id}');
context.go('/rooms/${space.id}/details');
} else if (controller.activeChat != null &&
!space.isFirstOrSecondChild(controller.activeChat!)) {
context.go("/rooms");
@ -111,6 +111,9 @@ void chatListHandleSpaceTap(
showAlertDialog(context);
}
break;
case Membership.leave:
autoJoin(space);
break;
default:
setActiveSpaceAndCloseChat();
ErrorHandler.logError(

@ -0,0 +1,26 @@
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
Future<bool> showUpdateVersionDialog({
required Future Function() future,
required BuildContext context,
}) async {
try {
await future();
return true;
} catch (err, s) {
ErrorHandler.logError(
e: err,
s: s,
);
await showOkAlertDialog(
context: context,
title: L10n.of(context)!.oopsSomethingWentWrong,
message: L10n.of(context)!.updatePhoneOS,
okLabel: L10n.of(context)!.close,
);
return false;
}
}

@ -1,9 +1,13 @@
import 'dart:developer';
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/models/speech_to_text_models.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:fluffychat/pangea/widgets/chat/toolbar_content_loading_indicator.dart';
import 'package:fluffychat/pangea/widgets/common/icon_number_widget.dart';
import 'package:fluffychat/pangea/widgets/igc/card_error_widget.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -41,27 +45,27 @@ class MessageSpeechToTextCardState extends State<MessageSpeechToTextCard> {
// look for transcription in message event
// if not found, call API to transcribe audio
Future<void> getSpeechToText() async {
// try {
if (l1Code == null || l2Code == null) {
throw Exception('Language selection not found');
}
speechToTextResponse ??=
await widget.messageEvent.getSpeechToText(l1Code!, l2Code!);
try {
if (l1Code == null || l2Code == null) {
throw Exception('Language selection not found');
}
speechToTextResponse ??=
await widget.messageEvent.getSpeechToText(l1Code!, l2Code!);
debugPrint(
'Speech to text transcript: ${speechToTextResponse?.transcript.text}',
);
// } catch (e, s) {
// debugger(when: kDebugMode);
// error = e;
// ErrorHandler.logError(
// e: e,
// s: s,
// data: widget.messageEvent.event.content,
// );
// } finally {
setState(() => _fetchingTranscription = false);
// }
debugPrint(
'Speech to text transcript: ${speechToTextResponse?.transcript.text}',
);
} catch (e, s) {
debugger(when: kDebugMode);
error = e;
ErrorHandler.logError(
e: e,
s: s,
data: widget.messageEvent.event.content,
);
} finally {
setState(() => _fetchingTranscription = false);
}
}
TextSpan _buildTranscriptText(BuildContext context) {
@ -133,6 +137,9 @@ class MessageSpeechToTextCardState extends State<MessageSpeechToTextCard> {
getSpeechToText();
}
String? get wordsPerMinuteString =>
speechToTextResponse?.transcript.wordsPerMinute?.toString();
@override
Widget build(BuildContext context) {
if (_fetchingTranscription) {
@ -158,11 +165,11 @@ class MessageSpeechToTextCardState extends State<MessageSpeechToTextCard> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconNumberWidget(
icon: Icons.abc,
number: (selectedToken == null ? words : 1).toString(),
toolTip: L10n.of(context)!.words,
),
// IconNumberWidget(
// icon: Icons.abc,
// number: (selectedToken == null ? words : 1).toString(),
// toolTip: L10n.of(context)!.words,
// ),
IconNumberWidget(
icon: Symbols.target,
number:
@ -171,8 +178,9 @@ class MessageSpeechToTextCardState extends State<MessageSpeechToTextCard> {
),
IconNumberWidget(
icon: Icons.speed,
number: (selectedToken?.confidence ?? total).toString(),
toolTip: L10n.of(context)!.points,
number:
wordsPerMinuteString != null ? "$wordsPerMinuteString" : "??",
toolTip: L10n.of(context)!.wordsPerMinute,
),
],
),

@ -28,7 +28,7 @@ import package_info_plus
import pasteboard
import path_provider_foundation
import purchases_flutter
import record_macos
import record_darwin
import sentry_flutter
import share_plus
import shared_preferences_foundation
@ -64,7 +64,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
PurchasesFlutterPlugin.register(with: registry.registrar(forPlugin: "PurchasesFlutterPlugin"))
RecordMacosPlugin.register(with: registry.registrar(forPlugin: "RecordMacosPlugin"))
RecordPlugin.register(with: registry.registrar(forPlugin: "RecordPlugin"))
SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))

@ -820,7 +820,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"be": [
@ -2239,7 +2241,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"bn": [
@ -3120,7 +3124,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"bo": [
@ -4001,7 +4007,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"ca": [
@ -4882,7 +4890,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"cs": [
@ -5763,7 +5773,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"de": [
@ -6591,7 +6603,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"el": [
@ -7472,7 +7486,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"eo": [
@ -8353,36 +8369,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
],
"es": [
"presenceStyle",
"presencesToggle",
"writeAMessageFlag",
"youInvitedToBy",
"hidePresences",
"sendReadReceipts",
"sendTypingNotificationsDescription",
"sendReadReceiptsDescription",
"formattedMessages",
"formattedMessagesDescription",
"verifyOtherUser",
"verifyOtherUserDescription",
"verifyOtherDevice",
"verifyOtherDeviceDescription",
"transparent",
"incomingMessages",
"stickers",
"commandHint_ignore",
"commandHint_unignore",
"unreadChatsInApp",
"messageAnalytics",
"words",
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"et": [
@ -9206,7 +9195,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"eu": [
@ -10030,7 +10021,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"fa": [
@ -10911,7 +10904,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"fi": [
@ -11792,7 +11787,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"fr": [
@ -12673,7 +12670,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"ga": [
@ -13554,7 +13553,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"gl": [
@ -14378,7 +14379,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"he": [
@ -15259,7 +15262,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"hi": [
@ -16140,7 +16145,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"hr": [
@ -17008,7 +17015,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"hu": [
@ -17889,7 +17898,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"ia": [
@ -19294,7 +19305,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"id": [
@ -20175,7 +20188,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"ie": [
@ -21056,7 +21071,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"it": [
@ -21922,7 +21939,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"ja": [
@ -22803,7 +22822,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"ko": [
@ -23684,7 +23705,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"lt": [
@ -24565,7 +24588,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"lv": [
@ -25446,7 +25471,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"nb": [
@ -26327,7 +26354,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"nl": [
@ -27208,7 +27237,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"pl": [
@ -28089,7 +28120,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"pt": [
@ -28970,7 +29003,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"pt_BR": [
@ -29820,7 +29855,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"pt_PT": [
@ -30701,7 +30738,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"ro": [
@ -31582,7 +31621,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"ru": [
@ -32406,7 +32447,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"sk": [
@ -33287,7 +33330,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"sl": [
@ -34168,7 +34213,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"sr": [
@ -35049,7 +35096,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"sv": [
@ -35895,7 +35944,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"ta": [
@ -36776,7 +36827,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"th": [
@ -37657,7 +37710,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"tr": [
@ -38523,7 +38578,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"uk": [
@ -39347,7 +39404,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"vi": [
@ -40228,7 +40287,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"zh": [
@ -41052,7 +41113,9 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
],
"zh_Hant": [
@ -41933,6 +41996,8 @@
"score",
"accuracy",
"points",
"noPaymentInfo"
"noPaymentInfo",
"updatePhoneOS",
"wordsPerMinute"
]
}

@ -1841,50 +1841,58 @@ packages:
dependency: "direct main"
description:
name: record
sha256: f703397f5a60d9b2b655b3acc94ba079b2d9a67dc0725bdb90ef2fee2441ebf7
sha256: "113b368168c49c78902ab37c2b354dea30a0aec5bdeca434073826b6ea73eca1"
url: "https://pub.dev"
source: hosted
version: "4.4.4"
record_linux:
version: "5.0.5"
record_android:
dependency: transitive
description:
name: record_linux
sha256: "348db92c4ec1b67b1b85d791381c8c99d7c6908de141e7c9edc20dad399b15ce"
name: record_android
sha256: "0df98e05873b22b443309e289bf1eb3b5b9a60e7779134334e2073eb0763a992"
url: "https://pub.dev"
source: hosted
version: "0.4.1"
record_macos:
version: "1.1.0"
record_darwin:
dependency: transitive
description:
name: record_macos
sha256: d1d0199d1395f05e218207e8cacd03eb9dc9e256ddfe2cfcbbb90e8edea06057
name: record_darwin
sha256: ee8cb1bb1712d7ce38140ecabe70e5c286c02f05296d66043bee865ace7eb1b9
url: "https://pub.dev"
source: hosted
version: "0.2.2"
version: "1.0.1"
record_linux:
dependency: transitive
description:
name: record_linux
sha256: "7d0e70cd51635128fe9d37d89bafd6011d7cbba9af8dc323079ae60f23546aef"
url: "https://pub.dev"
source: hosted
version: "0.7.1"
record_platform_interface:
dependency: transitive
description:
name: record_platform_interface
sha256: "7a2d4ce7ac3752505157e416e4e0d666a54b1d5d8601701b7e7e5e30bec181b4"
sha256: "3a4b56e94ecd2a0b2b43eb1fa6f94c5b8484334f5d38ef43959c4bf97fb374cf"
url: "https://pub.dev"
source: hosted
version: "0.5.0"
version: "1.0.2"
record_web:
dependency: transitive
description:
name: record_web
sha256: "219ffb4ca59b4338117857db56d3ffadbde3169bcaf1136f5f4d4656f4a2372d"
sha256: "24847cdbcf999f7a5762170792f622ac844858766becd0f2370ec8ae22f7526e"
url: "https://pub.dev"
source: hosted
version: "0.5.0"
version: "1.0.5"
record_windows:
dependency: transitive
description:
name: record_windows
sha256: "42d545155a26b20d74f5107648dbb3382dbbc84dc3f1adc767040359e57a1345"
sha256: "39998b3ea7d8d28b04159d82220e6e5e32a7c357c6fb2794f5736beea272f6c3"
url: "https://pub.dev"
source: hosted
version: "0.7.1"
version: "1.0.2"
remove_emoji:
dependency: transitive
description:
@ -1945,18 +1953,18 @@ packages:
dependency: transitive
description:
name: sentry
sha256: e572d33a3ff1d69549f33ee828a8ff514047d43ca8eea4ab093d72461205aa3e
sha256: fd1fbfe860c05f5c52820ec4dbf2b6473789e83ead26cfc18bca4fe80bf3f008
url: "https://pub.dev"
source: hosted
version: "7.20.1"
version: "8.2.0"
sentry_flutter:
dependency: "direct main"
description:
name: sentry_flutter
sha256: ac8cf6bb849f3560353ae33672e17b2713809a4e8de0d3cf372e9e9c42013757
sha256: c64f0aec5332bec87083b61514d1b6b29e435b9045d03ce1575861192b9a5680
url: "https://pub.dev"
source: hosted
version: "7.20.1"
version: "8.2.0"
share_plus:
dependency: "direct main"
description:

@ -83,7 +83,10 @@ dependencies:
punycode: ^1.0.0
qr_code_scanner: ^1.0.1
receive_sharing_intent: 1.4.5 # Update needs more work
record: 4.4.4 # Upgrade to 5 currently breaks playing on iOS
# #Pangea
# record: 4.4.4 # Upgrade to 5 currently breaks playing on iOS
record: ^5.0.5
# Pangea#
scroll_to_index: ^3.0.1
share_plus: ^8.0.2
shared_preferences: ^2.2.0 # Pinned because https://github.com/flutter/flutter/issues/118401

Loading…
Cancel
Save