mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2024-11-16 17:09:31 +01:00
Version 0.10.0
This commit is contained in:
parent
5367d9d037
commit
a79e8b1d8d
@ -2,6 +2,12 @@
|
|||||||
### New features
|
### New features
|
||||||
- Voice messages
|
- Voice messages
|
||||||
- New message bubble design
|
- New message bubble design
|
||||||
|
### Changes:
|
||||||
|
- Use SnackBars instead of Toasts
|
||||||
|
### Fixes:
|
||||||
|
- Minor fixes in the SDK
|
||||||
|
- Loading dialog when sending files is displayed too long
|
||||||
|
- Fixed device settings list
|
||||||
|
|
||||||
# Version 0.9.0 - 2020-03-13
|
# Version 0.9.0 - 2020-03-13
|
||||||
### New features
|
### New features
|
||||||
|
@ -5,7 +5,6 @@ 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:toast/toast.dart';
|
|
||||||
|
|
||||||
import 'dialogs/simple_dialogs.dart';
|
import 'dialogs/simple_dialogs.dart';
|
||||||
import 'matrix.dart';
|
import 'matrix.dart';
|
||||||
@ -22,8 +21,11 @@ class _EncryptionButtonState extends State<EncryptionButton> {
|
|||||||
|
|
||||||
void _enableEncryptionAction() async {
|
void _enableEncryptionAction() async {
|
||||||
if (widget.room.encrypted) {
|
if (widget.room.encrypted) {
|
||||||
Toast.show(I18n.of(context).warningEncryptionInBeta, context,
|
Scaffold.of(context).showSnackBar(
|
||||||
duration: 5);
|
SnackBar(
|
||||||
|
content: Text(I18n.of(context).warningEncryptionInBeta),
|
||||||
|
),
|
||||||
|
);
|
||||||
await Navigator.of(context).push(
|
await Navigator.of(context).push(
|
||||||
AppRoute.defaultRoute(
|
AppRoute.defaultRoute(
|
||||||
context,
|
context,
|
||||||
@ -33,7 +35,13 @@ class _EncryptionButtonState extends State<EncryptionButton> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!widget.room.client.encryptionEnabled) {
|
if (!widget.room.client.encryptionEnabled) {
|
||||||
Toast.show(I18n.of(context).needPantalaimonWarning, context, duration: 8);
|
Scaffold.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
I18n.of(context).needPantalaimonWarning,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (await SimpleDialogs(context).askConfirmation(
|
if (await SimpleDialogs(context).askConfirmation(
|
||||||
|
@ -3,7 +3,6 @@ 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:pedantic/pedantic.dart';
|
import 'package:pedantic/pedantic.dart';
|
||||||
import 'package:toast/toast.dart';
|
|
||||||
|
|
||||||
import '../../i18n/i18n.dart';
|
import '../../i18n/i18n.dart';
|
||||||
import '../../utils/app_route.dart';
|
import '../../utils/app_route.dart';
|
||||||
@ -32,8 +31,13 @@ class ChatListItem extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (room.membership == Membership.ban) {
|
if (room.membership == Membership.ban) {
|
||||||
Toast.show(I18n.of(context).youHaveBeenBannedFromThisChat, context,
|
Scaffold.of(context).showSnackBar(
|
||||||
duration: 5);
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
I18n.of(context).youHaveBeenBannedFromThisChat,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,19 +143,26 @@ class ChatListItem extends StatelessWidget {
|
|||||||
leading: Avatar(room.avatar, room.displayname),
|
leading: Avatar(room.avatar, room.displayname),
|
||||||
title: Row(
|
title: Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Expanded(
|
||||||
room.getLocalizedDisplayname(context),
|
child: Row(
|
||||||
maxLines: 1,
|
mainAxisSize: MainAxisSize.min,
|
||||||
overflow: TextOverflow.ellipsis,
|
children: <Widget>[
|
||||||
),
|
Text(
|
||||||
SizedBox(width: 4),
|
room.getLocalizedDisplayname(context),
|
||||||
room.pushRuleState == PushRuleState.notify
|
maxLines: 1,
|
||||||
? Container()
|
overflow: TextOverflow.ellipsis,
|
||||||
: Icon(
|
|
||||||
Icons.notifications_off,
|
|
||||||
color: Colors.grey[400],
|
|
||||||
size: 16,
|
|
||||||
),
|
),
|
||||||
|
SizedBox(width: 4),
|
||||||
|
room.pushRuleState == PushRuleState.notify
|
||||||
|
? Container()
|
||||||
|
: Icon(
|
||||||
|
Icons.notifications_off,
|
||||||
|
color: Colors.grey[400],
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
Text(
|
Text(
|
||||||
room.timeCreated.localizedTimeShort(context),
|
room.timeCreated.localizedTimeShort(context),
|
||||||
|
@ -10,7 +10,6 @@ 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:localstorage/localstorage.dart';
|
import 'package:localstorage/localstorage.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:toast/toast.dart';
|
|
||||||
|
|
||||||
import '../i18n/i18n.dart';
|
import '../i18n/i18n.dart';
|
||||||
import '../utils/app_route.dart';
|
import '../utils/app_route.dart';
|
||||||
@ -80,17 +79,21 @@ class MatrixState extends State<Matrix> {
|
|||||||
onAdditionalAuth != null) {
|
onAdditionalAuth != null) {
|
||||||
return await tryRequestWithErrorToast(onAdditionalAuth(exception));
|
return await tryRequestWithErrorToast(onAdditionalAuth(exception));
|
||||||
} else {
|
} else {
|
||||||
Toast.show(
|
Scaffold.of(context).showSnackBar(
|
||||||
exception.errorMessage,
|
SnackBar(
|
||||||
context,
|
content: Text(
|
||||||
duration: Toast.LENGTH_LONG,
|
exception.errorMessage,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
Toast.show(
|
Scaffold.of(context).showSnackBar(
|
||||||
exception.toString(),
|
SnackBar(
|
||||||
context,
|
content: Text(
|
||||||
duration: Toast.LENGTH_LONG,
|
exception.toString(),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -141,10 +144,12 @@ class MatrixState extends State<Matrix> {
|
|||||||
|
|
||||||
final String token = await _firebaseMessaging.getToken();
|
final String token = await _firebaseMessaging.getToken();
|
||||||
if (token?.isEmpty ?? true) {
|
if (token?.isEmpty ?? true) {
|
||||||
return Toast.show(
|
return Scaffold.of(context).showSnackBar(
|
||||||
I18n.of(context).noGoogleServicesWarning,
|
SnackBar(
|
||||||
context,
|
content: Text(
|
||||||
duration: 10,
|
I18n.of(context).noGoogleServicesWarning,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await client.setPushers(
|
await client.setPushers(
|
||||||
@ -175,7 +180,13 @@ class MatrixState extends State<Matrix> {
|
|||||||
),
|
),
|
||||||
(r) => r.isFirst);
|
(r) => r.isFirst);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
Toast.show("Failed to open chat...", context);
|
Scaffold.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
"Failed to open chat...",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
debugPrint(_);
|
debugPrint(_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:bubble/bubble.dart';
|
import 'package:bubble/bubble.dart';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:famedlysdk/famedlysdk.dart';
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
@ -8,7 +10,9 @@ import 'package:fluffychat/views/image_viewer.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:link_text/link_text.dart';
|
import 'package:link_text/link_text.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
import 'package:open_file/open_file.dart';
|
||||||
|
|
||||||
import 'matrix.dart';
|
import 'matrix.dart';
|
||||||
|
|
||||||
@ -20,11 +24,21 @@ class MessageContent extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
var messageType = event.messageType;
|
||||||
|
if (event.room.encrypted &&
|
||||||
|
[
|
||||||
|
MessageTypes.Image,
|
||||||
|
MessageTypes.Sticker,
|
||||||
|
MessageTypes.Audio,
|
||||||
|
MessageTypes.Video,
|
||||||
|
].contains(messageType)) {
|
||||||
|
messageType = MessageTypes.File;
|
||||||
|
}
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case EventTypes.Message:
|
case EventTypes.Message:
|
||||||
case EventTypes.Encrypted:
|
case EventTypes.Encrypted:
|
||||||
case EventTypes.Sticker:
|
case EventTypes.Sticker:
|
||||||
switch (event.messageType) {
|
switch (messageType) {
|
||||||
case MessageTypes.Image:
|
case MessageTypes.Image:
|
||||||
case MessageTypes.Sticker:
|
case MessageTypes.Sticker:
|
||||||
final int size = 400;
|
final int size = 400;
|
||||||
@ -72,19 +86,41 @@ class MessageContent extends StatelessWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
RaisedButton(
|
RaisedButton(
|
||||||
color: Colors.blueGrey,
|
color: Colors.blueGrey,
|
||||||
child: Text(
|
child: Text(
|
||||||
I18n.of(context).downloadFile,
|
I18n.of(context).downloadFile,
|
||||||
overflow: TextOverflow.fade,
|
overflow: TextOverflow.fade,
|
||||||
softWrap: false,
|
softWrap: false,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
onPressed: () => launch(
|
onPressed: () async {
|
||||||
MxContent(event.content["url"])
|
if (kIsWeb) {
|
||||||
.getDownloadLink(event.room.client),
|
if (event.room.encrypted) {
|
||||||
),
|
Scaffold.of(context).showSnackBar(
|
||||||
),
|
SnackBar(
|
||||||
|
content:
|
||||||
|
Text(I18n.of(context).notSupportedInWeb),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await launch(
|
||||||
|
MxContent(event.content["url"])
|
||||||
|
.getDownloadLink(event.room.client),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final matrixFile = await Matrix.of(context)
|
||||||
|
.tryRequestWithLoadingDialog(
|
||||||
|
event.downloadAndDecryptAttachment(),
|
||||||
|
);
|
||||||
|
Directory tempDir = await getTemporaryDirectory();
|
||||||
|
final file = File(tempDir.path +
|
||||||
|
"/" +
|
||||||
|
matrixFile.path.split("/").last);
|
||||||
|
file.writeAsBytesSync(matrixFile.bytes);
|
||||||
|
await OpenFile.open(file.path);
|
||||||
|
}),
|
||||||
Text(
|
Text(
|
||||||
"- " +
|
"- " +
|
||||||
(event.content.containsKey("filename")
|
(event.content.containsKey("filename")
|
||||||
|
@ -16,6 +16,9 @@ final ThemeData lightTheme = ThemeData(
|
|||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
secondaryHeaderColor: Color(0xFFECECF2),
|
secondaryHeaderColor: Color(0xFFECECF2),
|
||||||
scaffoldBackgroundColor: Colors.white,
|
scaffoldBackgroundColor: Colors.white,
|
||||||
|
snackBarTheme: SnackBarThemeData(
|
||||||
|
behavior: kIsWeb ? SnackBarBehavior.floating : SnackBarBehavior.fixed,
|
||||||
|
),
|
||||||
dialogTheme: DialogTheme(
|
dialogTheme: DialogTheme(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
@ -47,6 +50,9 @@ final ThemeData darkTheme = ThemeData.dark().copyWith(
|
|||||||
scaffoldBackgroundColor: Color(0xff121212),
|
scaffoldBackgroundColor: Color(0xff121212),
|
||||||
accentColor: Color(0xFFF5B4D2),
|
accentColor: Color(0xFFF5B4D2),
|
||||||
secondaryHeaderColor: Color(0xff1D1D1D),
|
secondaryHeaderColor: Color(0xff1D1D1D),
|
||||||
|
snackBarTheme: SnackBarThemeData(
|
||||||
|
behavior: kIsWeb ? SnackBarBehavior.floating : SnackBarBehavior.fixed,
|
||||||
|
),
|
||||||
dialogTheme: DialogTheme(
|
dialogTheme: DialogTheme(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
@ -78,6 +84,9 @@ final ThemeData amoledTheme = ThemeData.dark().copyWith(
|
|||||||
scaffoldBackgroundColor: Colors.black,
|
scaffoldBackgroundColor: Colors.black,
|
||||||
accentColor: Color(0xFFF5B4D2),
|
accentColor: Color(0xFFF5B4D2),
|
||||||
secondaryHeaderColor: Color(0xff1D1D1D),
|
secondaryHeaderColor: Color(0xff1D1D1D),
|
||||||
|
snackBarTheme: SnackBarThemeData(
|
||||||
|
behavior: kIsWeb ? SnackBarBehavior.floating : SnackBarBehavior.fixed,
|
||||||
|
),
|
||||||
dialogTheme: DialogTheme(
|
dialogTheme: DialogTheme(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:famedlysdk/famedlysdk.dart';
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
@ -29,7 +30,11 @@ class Store extends StoreAPI {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return await secureStorage.read(key: key);
|
try {
|
||||||
|
return await secureStorage.read(key: key);
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setItem(String key, String value) async {
|
Future<void> setItem(String key, String value) async {
|
||||||
@ -71,12 +76,18 @@ class Store extends StoreAPI {
|
|||||||
}
|
}
|
||||||
debugPrint("[Matrix] Restoring account credentials");
|
debugPrint("[Matrix] Restoring account credentials");
|
||||||
final Map<String, dynamic> credentials = json.decode(credentialsStr);
|
final Map<String, dynamic> credentials = json.decode(credentialsStr);
|
||||||
|
if (credentials["homeserver"] == null ||
|
||||||
|
credentials["token"] == null ||
|
||||||
|
credentials["userID"] == null) {
|
||||||
|
client.onLoginStateChanged.add(LoginState.loggedOut);
|
||||||
|
return;
|
||||||
|
}
|
||||||
client.connect(
|
client.connect(
|
||||||
newDeviceID: credentials["deviceID"],
|
newDeviceID: credentials["deviceID"],
|
||||||
newDeviceName: credentials["deviceName"],
|
newDeviceName: credentials["deviceName"],
|
||||||
newHomeserver: credentials["homeserver"],
|
newHomeserver: credentials["homeserver"],
|
||||||
newLazyLoadMembers: credentials["lazyLoadMembers"],
|
newLazyLoadMembers: credentials["lazyLoadMembers"],
|
||||||
newMatrixVersions: List<String>.from(credentials["matrixVersions"]),
|
newMatrixVersions: List<String>.from(credentials["matrixVersions"] ?? []),
|
||||||
newToken: credentials["token"],
|
newToken: credentials["token"],
|
||||||
newUserID: credentials["userID"],
|
newUserID: credentials["userID"],
|
||||||
newPrevBatch: kIsWeb
|
newPrevBatch: kIsWeb
|
||||||
@ -109,6 +120,10 @@ class Store extends StoreAPI {
|
|||||||
/// Responsible to store all data persistent and to query objects from the
|
/// Responsible to store all data persistent and to query objects from the
|
||||||
/// database.
|
/// database.
|
||||||
class ExtendedStore extends Store implements ExtendedStoreAPI {
|
class ExtendedStore extends Store implements ExtendedStoreAPI {
|
||||||
|
/// The maximum time that files are allowed to stay in the
|
||||||
|
/// store. By default this is are 30 days.
|
||||||
|
static const int MAX_FILE_STORING_TIME = 1 * 30 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final bool extended = true;
|
final bool extended = true;
|
||||||
|
|
||||||
@ -126,21 +141,29 @@ class ExtendedStore extends Store implements ExtendedStoreAPI {
|
|||||||
// Open the database and migrate if necessary.
|
// Open the database and migrate if necessary.
|
||||||
var databasePath = await getDatabasesPath();
|
var databasePath = await getDatabasesPath();
|
||||||
String path = p.join(databasePath, "FluffyMatrix.db");
|
String path = p.join(databasePath, "FluffyMatrix.db");
|
||||||
_db = await openDatabase(path, version: 16,
|
_db = await openDatabase(path, version: 20,
|
||||||
onCreate: (Database db, int version) async {
|
onCreate: (Database db, int version) async {
|
||||||
await createTables(db);
|
await createTables(db);
|
||||||
}, onUpgrade: (Database db, int oldVersion, int newVersion) async {
|
}, onUpgrade: (Database db, int oldVersion, int newVersion) async {
|
||||||
debugPrint(
|
debugPrint(
|
||||||
"[Store] Migrate database from version $oldVersion to $newVersion");
|
"[Store] Migrate database from version $oldVersion to $newVersion");
|
||||||
if (oldVersion != newVersion) {
|
if (oldVersion >= 18 && newVersion <= 20) {
|
||||||
|
await createTables(db);
|
||||||
|
} else if (oldVersion != newVersion) {
|
||||||
// Look for an old entry in an old clients library
|
// Look for an old entry in an old clients library
|
||||||
List<Map> list = [];
|
List<Map> list = [];
|
||||||
try {
|
try {
|
||||||
list = await db.rawQuery(
|
list = await db.rawQuery(
|
||||||
"SELECT * FROM Clients WHERE client=?", [client.clientName]);
|
"SELECT * FROM Clients WHERE client=?", [client.clientName]);
|
||||||
} on DatabaseException catch (_) {} catch (_) {
|
} catch (_) {
|
||||||
rethrow;
|
list = [];
|
||||||
}
|
}
|
||||||
|
client.prevBatch = null;
|
||||||
|
await this.storePrevBatch(null);
|
||||||
|
schemes.forEach((String name, String scheme) async {
|
||||||
|
await db.execute("DROP TABLE IF EXISTS $name");
|
||||||
|
});
|
||||||
|
await createTables(db);
|
||||||
|
|
||||||
if (list.length == 1) {
|
if (list.length == 1) {
|
||||||
debugPrint("[Store] Found old client from deprecated store");
|
debugPrint("[Store] Found old client from deprecated store");
|
||||||
@ -158,22 +181,26 @@ class ExtendedStore extends Store implements ExtendedStoreAPI {
|
|||||||
newPrevBatch: null,
|
newPrevBatch: null,
|
||||||
);
|
);
|
||||||
await db.execute("DROP TABLE IF EXISTS Clients");
|
await db.execute("DROP TABLE IF EXISTS Clients");
|
||||||
if (client.debug) {
|
debugPrint(
|
||||||
debugPrint(
|
"[Store] Restore client credentials from deprecated database of ${client.userID}");
|
||||||
"[Store] Restore client credentials from deprecated database of ${client.userID}");
|
|
||||||
}
|
|
||||||
schemes.forEach((String name, String scheme) async {
|
|
||||||
await db.execute("DROP TABLE IF EXISTS $name");
|
|
||||||
});
|
|
||||||
await createTables(db);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
client.onLoginStateChanged.add(LoginState.loggedOut);
|
client.onLoginStateChanged.add(LoginState.loggedOut);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mark all pending events as failed.
|
// Mark all pending events as failed.
|
||||||
await _db.rawUpdate("UPDATE Events SET status=-1 WHERE status=0");
|
await _db.rawUpdate("UPDATE Events SET status=-1 WHERE status=0");
|
||||||
|
|
||||||
|
// Delete all stored files which are older than [MAX_FILE_STORING_TIME]
|
||||||
|
final int currentDeadline = DateTime.now().millisecondsSinceEpoch -
|
||||||
|
ExtendedStore.MAX_FILE_STORING_TIME;
|
||||||
|
await _db.rawDelete(
|
||||||
|
"DELETE From Files WHERE saved_at<?",
|
||||||
|
[currentDeadline],
|
||||||
|
);
|
||||||
|
|
||||||
super._init();
|
super._init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,6 +542,23 @@ class ExtendedStore extends Store implements ExtendedStoreAPI {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> storeFile(Uint8List bytes, String mxcUri) async {
|
||||||
|
await _db.rawInsert(
|
||||||
|
"INSERT OR REPLACE INTO Files VALUES(?, ?, ?)",
|
||||||
|
[mxcUri, bytes, DateTime.now().millisecondsSinceEpoch],
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Uint8List> getFile(String mxcUri) async {
|
||||||
|
List<Map<String, dynamic>> res = await _db.rawQuery(
|
||||||
|
"SELECT * FROM Files WHERE mxc_uri=?",
|
||||||
|
[mxcUri],
|
||||||
|
);
|
||||||
|
if (res.isEmpty) return null;
|
||||||
|
return res.first["bytes"];
|
||||||
|
}
|
||||||
|
|
||||||
static final Map<String, String> schemes = {
|
static final Map<String, String> schemes = {
|
||||||
/// The database scheme for the Room class.
|
/// The database scheme for the Room class.
|
||||||
'Rooms': 'CREATE TABLE IF NOT EXISTS Rooms(' +
|
'Rooms': 'CREATE TABLE IF NOT EXISTS Rooms(' +
|
||||||
@ -574,5 +618,12 @@ class ExtendedStore extends Store implements ExtendedStoreAPI {
|
|||||||
'sender TEXT, ' +
|
'sender TEXT, ' +
|
||||||
'content TEXT, ' +
|
'content TEXT, ' +
|
||||||
'UNIQUE(sender))',
|
'UNIQUE(sender))',
|
||||||
|
|
||||||
|
/// The database scheme for room states.
|
||||||
|
'Files': 'CREATE TABLE IF NOT EXISTS Files(' +
|
||||||
|
'mxc_uri TEXT PRIMARY KEY, ' +
|
||||||
|
'bytes BLOB, ' +
|
||||||
|
'saved_at INTEGER, ' +
|
||||||
|
'UNIQUE(mxc_uri))',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:toast/toast.dart';
|
|
||||||
import 'package:pedantic/pedantic.dart';
|
import 'package:pedantic/pedantic.dart';
|
||||||
|
|
||||||
import 'chat_list.dart';
|
import 'chat_list.dart';
|
||||||
@ -178,7 +177,14 @@ class _ChatState extends State<_Chat> {
|
|||||||
|
|
||||||
void sendFileAction(BuildContext context) async {
|
void sendFileAction(BuildContext context) async {
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
return Toast.show(I18n.of(context).notSupportedInWeb, context);
|
Scaffold.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
I18n.of(context).notSupportedInWeb,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
File file = await FilePicker.getFile();
|
File file = await FilePicker.getFile();
|
||||||
if (file == null) return;
|
if (file == null) return;
|
||||||
@ -191,7 +197,14 @@ class _ChatState extends State<_Chat> {
|
|||||||
|
|
||||||
void sendImageAction(BuildContext context) async {
|
void sendImageAction(BuildContext context) async {
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
return Toast.show(I18n.of(context).notSupportedInWeb, context);
|
Scaffold.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
I18n.of(context).notSupportedInWeb,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
File file = await ImagePicker.pickImage(
|
File file = await ImagePicker.pickImage(
|
||||||
source: ImageSource.gallery,
|
source: ImageSource.gallery,
|
||||||
@ -208,7 +221,14 @@ class _ChatState extends State<_Chat> {
|
|||||||
|
|
||||||
void openCameraAction(BuildContext context) async {
|
void openCameraAction(BuildContext context) async {
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
return Toast.show(I18n.of(context).notSupportedInWeb, context);
|
Scaffold.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
I18n.of(context).notSupportedInWeb,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
File file = await ImagePicker.pickImage(
|
File file = await ImagePicker.pickImage(
|
||||||
source: ImageSource.camera,
|
source: ImageSource.camera,
|
||||||
|
@ -19,7 +19,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.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';
|
||||||
import 'package:toast/toast.dart';
|
|
||||||
|
|
||||||
class ChatDetails extends StatefulWidget {
|
class ChatDetails extends StatefulWidget {
|
||||||
final Room room;
|
final Room room;
|
||||||
@ -44,10 +43,12 @@ class _ChatDetailsState extends State<ChatDetails> {
|
|||||||
widget.room.setName(displayname),
|
widget.room.setName(displayname),
|
||||||
);
|
);
|
||||||
if (success != false) {
|
if (success != false) {
|
||||||
Toast.show(
|
Scaffold.of(context).showSnackBar(
|
||||||
I18n.of(context).displaynameHasBeenChanged,
|
SnackBar(
|
||||||
context,
|
content: Text(
|
||||||
duration: Toast.LENGTH_LONG,
|
I18n.of(context).displaynameHasBeenChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,10 +110,12 @@ class _ChatDetailsState extends State<ChatDetails> {
|
|||||||
widget.room.setDescription(displayname),
|
widget.room.setDescription(displayname),
|
||||||
);
|
);
|
||||||
if (success != false) {
|
if (success != false) {
|
||||||
Toast.show(
|
Scaffold.of(context).showSnackBar(
|
||||||
I18n.of(context).groupDescriptionHasBeenChanged,
|
SnackBar(
|
||||||
context,
|
content: Text(
|
||||||
duration: Toast.LENGTH_LONG,
|
I18n.of(context).groupDescriptionHasBeenChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,10 +137,12 @@ class _ChatDetailsState extends State<ChatDetails> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (success != false) {
|
if (success != false) {
|
||||||
Toast.show(
|
Scaffold.of(context).showSnackBar(
|
||||||
I18n.of(context).avatarHasBeenChanged,
|
SnackBar(
|
||||||
context,
|
content: Text(
|
||||||
duration: Toast.LENGTH_LONG,
|
I18n.of(context).avatarHasBeenChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,8 +200,13 @@ class _ChatDetailsState extends State<ChatDetails> {
|
|||||||
Clipboard.setData(
|
Clipboard.setData(
|
||||||
ClipboardData(text: widget.room.canonicalAlias),
|
ClipboardData(text: widget.room.canonicalAlias),
|
||||||
);
|
);
|
||||||
Toast.show(I18n.of(context).copiedToClipboard, context,
|
Scaffold.of(context).showSnackBar(
|
||||||
duration: 5);
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
I18n.of(context).copiedToClipboard,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ChatSettingsPopupMenu(widget.room, false)
|
ChatSettingsPopupMenu(widget.room, false)
|
||||||
|
@ -6,7 +6,6 @@ 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_speed_dial/flutter_speed_dial.dart';
|
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
||||||
import 'package:toast/toast.dart';
|
|
||||||
import 'package:uni_links/uni_links.dart';
|
import 'package:uni_links/uni_links.dart';
|
||||||
|
|
||||||
import '../components/dialogs/simple_dialogs.dart';
|
import '../components/dialogs/simple_dialogs.dart';
|
||||||
@ -125,10 +124,13 @@ class _ChatListState extends State<ChatList> {
|
|||||||
debugPrint("initUniLinks failed during platform exception");
|
debugPrint("initUniLinks failed during platform exception");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (error) => Toast.show(
|
onError: (error) => Scaffold.of(context).showSnackBar(
|
||||||
I18n.of(context).oopsSomethingWentWrong + " " + error.toString(),
|
SnackBar(
|
||||||
context,
|
content: Text(
|
||||||
duration: 5),
|
I18n.of(context).oopsSomethingWentWrong + " " + error.toString(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ 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:toast/toast.dart';
|
|
||||||
|
|
||||||
import 'chat_list.dart';
|
import 'chat_list.dart';
|
||||||
|
|
||||||
@ -52,10 +51,12 @@ class _InvitationSelectionState extends State<InvitationSelection> {
|
|||||||
widget.room.invite(id),
|
widget.room.invite(id),
|
||||||
);
|
);
|
||||||
if (success != false) {
|
if (success != false) {
|
||||||
Toast.show(
|
Scaffold.of(context).showSnackBar(
|
||||||
I18n.of(context).contactHasBeenInvitedToTheGroup,
|
SnackBar(
|
||||||
context,
|
content: Text(
|
||||||
duration: Toast.LENGTH_LONG,
|
I18n.of(context).contactHasBeenInvitedToTheGroup,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import 'package:fluffychat/components/settings_themes.dart';
|
|||||||
import 'package:fluffychat/views/settings_devices.dart';
|
import 'package:fluffychat/views/settings_devices.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:toast/toast.dart';
|
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
import 'app_info.dart';
|
import 'app_info.dart';
|
||||||
@ -86,11 +85,6 @@ class _SettingsState extends State<Settings> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (success != false) {
|
if (success != false) {
|
||||||
Toast.show(
|
|
||||||
I18n.of(context).avatarHasBeenChanged,
|
|
||||||
context,
|
|
||||||
duration: Toast.LENGTH_LONG,
|
|
||||||
);
|
|
||||||
setState(() {
|
setState(() {
|
||||||
profileFuture = null;
|
profileFuture = null;
|
||||||
profile = null;
|
profile = null;
|
||||||
@ -194,25 +188,19 @@ class _SettingsState extends State<Settings> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(Icons.help),
|
trailing: Icon(Icons.help),
|
||||||
title: Text(I18n.of(context).help),
|
title: Text(I18n.of(context).help),
|
||||||
onTap: () => launch(
|
onTap: () => launch(
|
||||||
"https://gitlab.com/ChristianPauly/fluffychat-flutter/issues"),
|
"https://gitlab.com/ChristianPauly/fluffychat-flutter/issues"),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(Icons.list),
|
trailing: Icon(Icons.link),
|
||||||
title: Text(I18n.of(context).changelog),
|
|
||||||
onTap: () => launch(
|
|
||||||
"https://gitlab.com/ChristianPauly/fluffychat-flutter/blob/master/CHANGELOG.md"),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
leading: Icon(Icons.link),
|
|
||||||
title: Text(I18n.of(context).license),
|
title: Text(I18n.of(context).license),
|
||||||
onTap: () => launch(
|
onTap: () => launch(
|
||||||
"https://gitlab.com/ChristianPauly/fluffychat-flutter/raw/master/LICENSE"),
|
"https://gitlab.com/ChristianPauly/fluffychat-flutter/raw/master/LICENSE"),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(Icons.code),
|
trailing: Icon(Icons.code),
|
||||||
title: Text(I18n.of(context).sourceCode),
|
title: Text(I18n.of(context).sourceCode),
|
||||||
onTap: () => launch(
|
onTap: () => launch(
|
||||||
"https://gitlab.com/ChristianPauly/fluffychat-flutter"),
|
"https://gitlab.com/ChristianPauly/fluffychat-flutter"),
|
||||||
|
@ -87,6 +87,7 @@ class DevicesSettingsState extends State<DevicesSettings> {
|
|||||||
UserDevice thisDevice =
|
UserDevice thisDevice =
|
||||||
devices.firstWhere(isOwnDevice, orElse: () => null);
|
devices.firstWhere(isOwnDevice, orElse: () => null);
|
||||||
devices.removeWhere(isOwnDevice);
|
devices.removeWhere(isOwnDevice);
|
||||||
|
devices.sort((a, b) => b.lastSeenTs.compareTo(a.lastSeenTs));
|
||||||
return Column(
|
return Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
if (thisDevice != null)
|
if (thisDevice != null)
|
||||||
@ -159,9 +160,15 @@ class UserDeviceListItem extends StatelessWidget {
|
|||||||
contentPadding: EdgeInsets.all(16.0),
|
contentPadding: EdgeInsets.all(16.0),
|
||||||
title: Row(
|
title: Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text((userDevice.displayName?.isNotEmpty ?? false)
|
Expanded(
|
||||||
? userDevice.displayName
|
child: Text(
|
||||||
: I18n.of(context).unknownDevice),
|
(userDevice.displayName?.isNotEmpty ?? false)
|
||||||
|
? userDevice.displayName
|
||||||
|
: I18n.of(context).unknownDevice,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
Text(userDevice.lastSeenTs.localizedTimeShort(context)),
|
Text(userDevice.lastSeenTs.localizedTimeShort(context)),
|
||||||
],
|
],
|
||||||
|
@ -7,7 +7,6 @@ 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:toast/toast.dart';
|
|
||||||
|
|
||||||
import 'chat_list.dart';
|
import 'chat_list.dart';
|
||||||
|
|
||||||
@ -96,7 +95,13 @@ class _SignUpPasswordState extends State<SignUpPassword> {
|
|||||||
try {
|
try {
|
||||||
await matrix.client.setDisplayname(widget.displayname);
|
await matrix.client.setDisplayname(widget.displayname);
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
Toast.show(I18n.of(context).couldNotSetDisplayname, context, duration: 5);
|
Scaffold.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
I18n.of(context).couldNotSetDisplayname,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (widget.avatar != null) {
|
if (widget.avatar != null) {
|
||||||
try {
|
try {
|
||||||
@ -107,7 +112,13 @@ class _SignUpPasswordState extends State<SignUpPassword> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
Toast.show(I18n.of(context).couldNotSetAvatar, context, duration: 5);
|
Scaffold.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
I18n.of(context).couldNotSetAvatar,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Navigator.of(context).pushAndRemoveUntil(
|
await Navigator.of(context).pushAndRemoveUntil(
|
||||||
|
40
pubspec.lock
40
pubspec.lock
@ -124,8 +124,8 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: eb84c2a0856af99527f00697cbed4eb67a47887d
|
ref: eb66ec79d431c73d5d752cb237b94da56b92f10f
|
||||||
resolved-ref: eb84c2a0856af99527f00697cbed4eb67a47887d
|
resolved-ref: eb66ec79d431c73d5d752cb237b94da56b92f10f
|
||||||
url: "https://gitlab.com/famedly/famedlysdk.git"
|
url: "https://gitlab.com/famedly/famedlysdk.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.1"
|
version: "0.0.1"
|
||||||
@ -331,6 +331,15 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.6"
|
version: "0.12.6"
|
||||||
|
matrix_file_e2ee:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: HEAD
|
||||||
|
resolved-ref: b043fcc29031979dc65e5b08e10ebb9b8d2fae30
|
||||||
|
url: "https://gitlab.com/famedly/libraries/matrix_file_e2ee.git"
|
||||||
|
source: git
|
||||||
|
version: "1.0.2"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -384,11 +393,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: bbc7ce10a52be5d5c10d2eb6c3591aade71356e2
|
ref: "1.x.y"
|
||||||
resolved-ref: bbc7ce10a52be5d5c10d2eb6c3591aade71356e2
|
resolved-ref: "79868b06b3ea156f90b73abafb3bbf3ac4114cc6"
|
||||||
url: "https://gitlab.com/famedly/libraries/dart-olm.git"
|
url: "https://gitlab.com/famedly/libraries/dart-olm.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.0"
|
version: "1.0.0"
|
||||||
|
open_file:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: open_file
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -466,6 +482,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
pointycastle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pointycastle
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -611,13 +634,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.15"
|
version: "0.2.15"
|
||||||
toast:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: toast
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.1.5"
|
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -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.9.0+28
|
version: 0.10.0+29
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.6.0 <3.0.0"
|
sdk: ">=2.6.0 <3.0.0"
|
||||||
@ -27,11 +27,10 @@ dependencies:
|
|||||||
famedlysdk:
|
famedlysdk:
|
||||||
git:
|
git:
|
||||||
url: https://gitlab.com/famedly/famedlysdk.git
|
url: https://gitlab.com/famedly/famedlysdk.git
|
||||||
ref: eb84c2a0856af99527f00697cbed4eb67a47887d
|
ref: eb66ec79d431c73d5d752cb237b94da56b92f10f
|
||||||
|
|
||||||
localstorage: ^3.0.1+4
|
localstorage: ^3.0.1+4
|
||||||
bubble: ^1.1.9+1
|
bubble: ^1.1.9+1
|
||||||
toast: ^0.1.5
|
|
||||||
file_picker: ^1.4.3+2
|
file_picker: ^1.4.3+2
|
||||||
image_picker: ^0.6.2+3
|
image_picker: ^0.6.2+3
|
||||||
flutter_speed_dial: ^1.2.5
|
flutter_speed_dial: ^1.2.5
|
||||||
@ -53,6 +52,7 @@ dependencies:
|
|||||||
flutter_slidable: ^0.5.4
|
flutter_slidable: ^0.5.4
|
||||||
photo_view: ^0.9.2
|
photo_view: ^0.9.2
|
||||||
flutter_sound: ^2.1.1
|
flutter_sound: ^2.1.1
|
||||||
|
open_file: ^3.0.1
|
||||||
|
|
||||||
intl: ^0.16.0
|
intl: ^0.16.0
|
||||||
intl_translation: ^0.17.9
|
intl_translation: ^0.17.9
|
||||||
|
Loading…
Reference in New Issue
Block a user