Fix login and toasts

This commit is contained in:
Christian Pauly 2020-04-12 09:19:22 +02:00
parent c746778f3f
commit 0b570b86f0
12 changed files with 166 additions and 240 deletions

View File

@ -5,6 +5,7 @@ import 'package:fluffychat/i18n/i18n.dart';
import 'package:fluffychat/utils/app_route.dart'; import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/chat_encryption_settings.dart'; import 'package:fluffychat/views/chat_encryption_settings.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'dialogs/simple_dialogs.dart'; import 'dialogs/simple_dialogs.dart';
import 'matrix.dart'; import 'matrix.dart';
@ -21,11 +22,7 @@ class _EncryptionButtonState extends State<EncryptionButton> {
void _enableEncryptionAction() async { void _enableEncryptionAction() async {
if (widget.room.encrypted) { if (widget.room.encrypted) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).warningEncryptionInBeta);
SnackBar(
content: Text(I18n.of(context).warningEncryptionInBeta),
),
);
await Navigator.of(context).push( await Navigator.of(context).push(
AppRoute.defaultRoute( AppRoute.defaultRoute(
context, context,
@ -35,13 +32,7 @@ class _EncryptionButtonState extends State<EncryptionButton> {
return; return;
} }
if (!widget.room.client.encryptionEnabled) { if (!widget.room.client.encryptionEnabled) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).needPantalaimonWarning);
SnackBar(
content: Text(
I18n.of(context).needPantalaimonWarning,
),
),
);
return; return;
} }
if (await SimpleDialogs(context).askConfirmation( if (await SimpleDialogs(context).askConfirmation(

View File

@ -2,6 +2,7 @@ import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/views/chat.dart'; import 'package:fluffychat/views/chat.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:pedantic/pedantic.dart'; import 'package:pedantic/pedantic.dart';
import '../../i18n/i18n.dart'; import '../../i18n/i18n.dart';
@ -31,13 +32,7 @@ class ChatListItem extends StatelessWidget {
} }
if (room.membership == Membership.ban) { if (room.membership == Membership.ban) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).youHaveBeenBannedFromThisChat);
SnackBar(
content: Text(
I18n.of(context).youHaveBeenBannedFromThisChat,
),
),
);
return; return;
} }

View File

@ -8,6 +8,7 @@ import 'package:fluffychat/components/dialogs/simple_dialogs.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:localstorage/localstorage.dart'; import 'package:localstorage/localstorage.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@ -95,22 +96,10 @@ class MatrixState extends State<Matrix> {
onAdditionalAuth != null) { onAdditionalAuth != null) {
return await tryRequestWithErrorToast(onAdditionalAuth(exception)); return await tryRequestWithErrorToast(onAdditionalAuth(exception));
} else { } else {
Scaffold.of(context).showSnackBar( showToast(exception.errorMessage);
SnackBar(
content: Text(
exception.errorMessage,
),
),
);
} }
} catch (exception) { } catch (exception) {
Scaffold.of(context).showSnackBar( showToast(exception.toString());
SnackBar(
content: Text(
exception.toString(),
),
),
);
return false; return false;
} }
} }
@ -158,15 +147,14 @@ class MatrixState extends State<Matrix> {
Future<void> setupFirebase() async { Future<void> setupFirebase() async {
if (Platform.isIOS) iOS_Permission(); if (Platform.isIOS) iOS_Permission();
final String token = await _firebaseMessaging.getToken(); String token;
try {
token = await _firebaseMessaging.getToken();
} catch (_) {
token = null;
}
if (token?.isEmpty ?? true) { if (token?.isEmpty ?? true) {
return Scaffold.of(context).showSnackBar( showToast(I18n.of(context).noGoogleServicesWarning);
SnackBar(
content: Text(
I18n.of(context).noGoogleServicesWarning,
),
),
);
} }
await client.setPushers( await client.setPushers(
token, token,
@ -196,13 +184,7 @@ class MatrixState extends State<Matrix> {
), ),
(r) => r.isFirst); (r) => r.isFirst);
} catch (_) { } catch (_) {
Scaffold.of(context).showSnackBar( showToast("Failed to open chat...");
SnackBar(
content: Text(
"Failed to open chat...",
),
),
);
debugPrint(_); debugPrint(_);
} }
}; };
@ -419,7 +401,7 @@ class MatrixState extends State<Matrix> {
void initState() { void initState() {
if (widget.client == null) { if (widget.client == null) {
debugPrint("[Matrix] Init matrix client"); debugPrint("[Matrix] Init matrix client");
client = Client(widget.clientName, debug: false); client = Client(widget.clientName, debug: true);
onJitsiCallSub ??= client.onEvent.stream onJitsiCallSub ??= client.onEvent.stream
.where((e) => .where((e) =>
e.type == 'timeline' && e.type == 'timeline' &&

View File

@ -5,6 +5,7 @@ import 'package:fluffychat/i18n/i18n.dart';
import 'package:fluffychat/utils/event_extension.dart'; import 'package:fluffychat/utils/event_extension.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:link_text/link_text.dart'; import 'package:link_text/link_text.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:fluffychat/utils/matrix_file_extension.dart'; import 'package:fluffychat/utils/matrix_file_extension.dart';
@ -51,12 +52,7 @@ class MessageContent extends StatelessWidget {
onPressed: () async { onPressed: () async {
if (kIsWeb) { if (kIsWeb) {
if (event.room.encrypted) { if (event.room.encrypted) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).notSupportedInWeb);
SnackBar(
content:
Text(I18n.of(context).notSupportedInWeb),
),
);
} }
await launch( await launch(
MxContent(event.content["url"]) MxContent(event.content["url"])

View File

@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'i18n/i18n.dart'; import 'i18n/i18n.dart';
import 'views/sign_up.dart'; import 'views/sign_up.dart';
@ -28,38 +29,43 @@ class App extends StatelessWidget {
child: Builder( child: Builder(
builder: (BuildContext context) => ThemeSwitcherWidget( builder: (BuildContext context) => ThemeSwitcherWidget(
child: Builder( child: Builder(
builder: (BuildContext context) => MaterialApp( builder: (BuildContext context) => StyledToast(
title: 'FluffyChat', child: MaterialApp(
theme: ThemeSwitcherWidget.of(context).themeData, title: 'FluffyChat',
localizationsDelegates: [ theme: ThemeSwitcherWidget.of(context).themeData,
AppLocalizationsDelegate(), localizationsDelegates: [
GlobalMaterialLocalizations.delegate, AppLocalizationsDelegate(),
GlobalWidgetsLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
], GlobalCupertinoLocalizations.delegate,
supportedLocales: [ ],
const Locale('en'), // English supportedLocales: [
const Locale('de'), // German const Locale('en'), // English
], const Locale('de'), // German
locale: kIsWeb ],
? Locale(html.window.navigator.language.split("-").first) locale: kIsWeb
: null, ? Locale(html.window.navigator.language.split("-").first)
home: FutureBuilder<LoginState>( : null,
future: home: FutureBuilder<LoginState>(
Matrix.of(context).client.onLoginStateChanged.stream.first, future: Matrix.of(context)
builder: (context, snapshot) { .client
if (!snapshot.hasData) { .onLoginStateChanged
return Scaffold( .stream
body: Center( .first,
child: CircularProgressIndicator(), builder: (context, snapshot) {
), if (!snapshot.hasData) {
); return Scaffold(
} body: Center(
if (Matrix.of(context).client.isLogged()) { child: CircularProgressIndicator(),
return ChatListView(); ),
} );
return SignUp(); }
}, if (Matrix.of(context).client.isLogged()) {
return ChatListView();
}
return SignUp();
},
),
), ),
), ),
), ),

View File

@ -17,6 +17,7 @@ import 'package:fluffychat/utils/room_extension.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:pedantic/pedantic.dart'; import 'package:pedantic/pedantic.dart';
@ -176,13 +177,7 @@ class _ChatState extends State<_Chat> {
void sendFileAction(BuildContext context) async { void sendFileAction(BuildContext context) async {
if (kIsWeb) { if (kIsWeb) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).notSupportedInWeb);
SnackBar(
content: Text(
I18n.of(context).notSupportedInWeb,
),
),
);
return; return;
} }
File file = await FilePicker.getFile(); File file = await FilePicker.getFile();
@ -196,13 +191,7 @@ class _ChatState extends State<_Chat> {
void sendImageAction(BuildContext context) async { void sendImageAction(BuildContext context) async {
if (kIsWeb) { if (kIsWeb) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).notSupportedInWeb);
SnackBar(
content: Text(
I18n.of(context).notSupportedInWeb,
),
),
);
return; return;
} }
File file = await ImagePicker.pickImage( File file = await ImagePicker.pickImage(
@ -220,13 +209,7 @@ class _ChatState extends State<_Chat> {
void openCameraAction(BuildContext context) async { void openCameraAction(BuildContext context) async {
if (kIsWeb) { if (kIsWeb) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).notSupportedInWeb);
SnackBar(
content: Text(
I18n.of(context).notSupportedInWeb,
),
),
);
return; return;
} }
File file = await ImagePicker.pickImage( File file = await ImagePicker.pickImage(

View File

@ -17,6 +17,7 @@ import 'package:fluffychat/views/invitation_selection.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:link_text/link_text.dart'; import 'package:link_text/link_text.dart';
@ -43,13 +44,7 @@ class _ChatDetailsState extends State<ChatDetails> {
widget.room.setName(displayname), widget.room.setName(displayname),
); );
if (success != false) { if (success != false) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).displaynameHasBeenChanged);
SnackBar(
content: Text(
I18n.of(context).displaynameHasBeenChanged,
),
),
);
} }
} }
@ -110,13 +105,7 @@ class _ChatDetailsState extends State<ChatDetails> {
widget.room.setDescription(displayname), widget.room.setDescription(displayname),
); );
if (success != false) { if (success != false) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).groupDescriptionHasBeenChanged);
SnackBar(
content: Text(
I18n.of(context).groupDescriptionHasBeenChanged,
),
),
);
} }
} }
@ -137,13 +126,7 @@ class _ChatDetailsState extends State<ChatDetails> {
), ),
); );
if (success != false) { if (success != false) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).avatarHasBeenChanged);
SnackBar(
content: Text(
I18n.of(context).avatarHasBeenChanged,
),
),
);
} }
} }
@ -201,13 +184,7 @@ class _ChatDetailsState extends State<ChatDetails> {
Clipboard.setData( Clipboard.setData(
ClipboardData(text: widget.room.canonicalAlias), ClipboardData(text: widget.room.canonicalAlias),
); );
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).copiedToClipboard);
SnackBar(
content: Text(
I18n.of(context).copiedToClipboard,
),
),
);
}, },
), ),
ChatSettingsPopupMenu(widget.room, false) ChatSettingsPopupMenu(widget.room, false)

View File

@ -6,6 +6,7 @@ import 'package:fluffychat/components/avatar.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/i18n/i18n.dart'; import 'package:fluffychat/i18n/i18n.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'chat_list.dart'; import 'chat_list.dart';
@ -56,13 +57,7 @@ class _InvitationSelectionState extends State<InvitationSelection> {
widget.room.invite(id), widget.room.invite(id),
); );
if (success != false) { if (success != false) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).contactHasBeenInvitedToTheGroup);
SnackBar(
content: Text(
I18n.of(context).contactHasBeenInvitedToTheGroup,
),
),
);
} }
} }

View File

@ -104,82 +104,86 @@ class _LoginState extends State<Login> {
labelText: serverError == null ? "Homeserver" : serverError), labelText: serverError == null ? "Homeserver" : serverError),
), ),
), ),
body: ListView( body: Builder(builder: (context) {
padding: EdgeInsets.symmetric( return ListView(
horizontal: max((MediaQuery.of(context).size.width - 600) / 2, 0)), padding: EdgeInsets.symmetric(
children: <Widget>[ horizontal:
Container( max((MediaQuery.of(context).size.width - 600) / 2, 0)),
height: 150, children: <Widget>[
color: Theme.of(context).secondaryHeaderColor, Container(
child: Center( height: 150,
child: Icon( color: Theme.of(context).secondaryHeaderColor,
Icons.vpn_key, child: Center(
size: 60, child: Icon(
Icons.vpn_key,
size: 60,
),
), ),
), ),
), ListTile(
ListTile( leading: CircleAvatar(
leading: CircleAvatar( child: Icon(Icons.account_box,
child: Icon(Icons.account_box, color: Theme.of(context).primaryColor),
color: Theme.of(context).primaryColor),
),
title: TextField(
readOnly: loading,
autocorrect: false,
controller: usernameController,
decoration: InputDecoration(
hintText:
"@${I18n.of(context).username.toLowerCase()}:domain",
errorText: usernameError,
labelText: I18n.of(context).username),
),
),
ListTile(
leading: CircleAvatar(
backgroundColor: Theme.of(context).brightness == Brightness.dark
? Color(0xff121212)
: Colors.white,
child: Icon(Icons.lock, color: Theme.of(context).primaryColor),
),
title: TextField(
readOnly: loading,
autocorrect: false,
controller: passwordController,
obscureText: !showPassword,
onSubmitted: (t) => login(context),
decoration: InputDecoration(
hintText: "****",
errorText: passwordError,
suffixIcon: IconButton(
icon: Icon(
showPassword ? Icons.visibility_off : Icons.visibility),
onPressed: () =>
setState(() => showPassword = !showPassword),
),
labelText: I18n.of(context).password),
),
),
SizedBox(height: 20),
Container(
height: 50,
padding: EdgeInsets.symmetric(horizontal: 12),
child: RaisedButton(
elevation: 7,
color: Theme.of(context).primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
), ),
child: loading title: TextField(
? CircularProgressIndicator() readOnly: loading,
: Text( autocorrect: false,
I18n.of(context).login.toUpperCase(), controller: usernameController,
style: TextStyle(color: Colors.white, fontSize: 16), decoration: InputDecoration(
hintText:
"@${I18n.of(context).username.toLowerCase()}:domain",
errorText: usernameError,
labelText: I18n.of(context).username),
),
),
ListTile(
leading: CircleAvatar(
backgroundColor: Theme.of(context).brightness == Brightness.dark
? Color(0xff121212)
: Colors.white,
child: Icon(Icons.lock, color: Theme.of(context).primaryColor),
),
title: TextField(
readOnly: loading,
autocorrect: false,
controller: passwordController,
obscureText: !showPassword,
onSubmitted: (t) => login(context),
decoration: InputDecoration(
hintText: "****",
errorText: passwordError,
suffixIcon: IconButton(
icon: Icon(showPassword
? Icons.visibility_off
: Icons.visibility),
onPressed: () =>
setState(() => showPassword = !showPassword),
), ),
onPressed: () => loading ? null : login(context), labelText: I18n.of(context).password),
),
), ),
), SizedBox(height: 20),
], Container(
), height: 50,
padding: EdgeInsets.symmetric(horizontal: 12),
child: RaisedButton(
elevation: 7,
color: Theme.of(context).primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: loading
? CircularProgressIndicator()
: Text(
I18n.of(context).login.toUpperCase(),
style: TextStyle(color: Colors.white, fontSize: 16),
),
onPressed: () => loading ? null : login(context),
),
),
],
);
}),
); );
} }
} }

View File

@ -7,6 +7,7 @@ import 'package:fluffychat/i18n/i18n.dart';
import 'package:fluffychat/utils/app_route.dart'; import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/auth_web_view.dart'; import 'package:fluffychat/views/auth_web_view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'chat_list.dart'; import 'chat_list.dart';
@ -95,13 +96,7 @@ class _SignUpPasswordState extends State<SignUpPassword> {
try { try {
await matrix.client.setDisplayname(widget.displayname); await matrix.client.setDisplayname(widget.displayname);
} catch (exception) { } catch (exception) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).couldNotSetDisplayname);
SnackBar(
content: Text(
I18n.of(context).couldNotSetDisplayname,
),
),
);
} }
if (widget.avatar != null) { if (widget.avatar != null) {
try { try {
@ -112,13 +107,7 @@ class _SignUpPasswordState extends State<SignUpPassword> {
), ),
); );
} catch (exception) { } catch (exception) {
Scaffold.of(context).showSnackBar( showToast(I18n.of(context).couldNotSetAvatar);
SnackBar(
content: Text(
I18n.of(context).couldNotSetAvatar,
),
),
);
} }
} }
await Navigator.of(context).pushAndRemoveUntil( await Navigator.of(context).pushAndRemoveUntil(

View File

@ -21,28 +21,28 @@ packages:
name: archive name: archive
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.11" version: "2.0.13"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.5.2" version: "1.6.0"
async: async:
dependency: transitive dependency: transitive
description: description:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.0" version: "2.4.1"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.5" version: "2.0.0"
bubble: bubble:
dependency: "direct main" dependency: "direct main"
description: description:
@ -63,14 +63,14 @@ packages:
name: charcode name: charcode
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.2" version: "1.1.3"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.14.11" version: "1.14.12"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@ -91,7 +91,7 @@ packages:
name: crypto name: crypto
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.3" version: "2.1.4"
csslib: csslib:
dependency: transitive dependency: transitive
description: description:
@ -202,6 +202,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.5" version: "1.2.5"
flutter_styled_toast:
dependency: "direct main"
description:
name: flutter_styled_toast
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
flutter_svg: flutter_svg:
dependency: transitive dependency: transitive
description: description:
@ -260,7 +267,7 @@ packages:
name: image name: image
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.4" version: "2.1.12"
image_picker: image_picker:
dependency: "direct main" dependency: "direct main"
description: description:
@ -502,7 +509,7 @@ packages:
name: quiver name: quiver
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.5" version: "2.1.3"
receive_sharing_intent: receive_sharing_intent:
dependency: "direct main" dependency: "direct main"
description: description:
@ -570,7 +577,7 @@ packages:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.5.5" version: "1.7.0"
sqflite: sqflite:
dependency: "direct main" dependency: "direct main"
description: description:
@ -738,7 +745,7 @@ packages:
name: xml name: xml
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.5.0" version: "3.6.1"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:

View File

@ -11,7 +11,7 @@ description: Chat with your friends.
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.12.0+32 version: 0.12.2+34
environment: environment:
sdk: ">=2.6.0 <3.0.0" sdk: ">=2.6.0 <3.0.0"
@ -53,6 +53,7 @@ dependencies:
flutter_sound: ^2.1.1 flutter_sound: ^2.1.1
open_file: ^3.0.1 open_file: ^3.0.1
mime_type: ^0.2.7 mime_type: ^0.2.7
flutter_styled_toast: ^1.2.1
intl: ^0.16.0 intl: ^0.16.0
intl_translation: ^0.17.9 intl_translation: ^0.17.9