mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2024-12-03 17:59:45 +01:00
Enable Desktop support
This commit is contained in:
parent
be948ff8b1
commit
f51123150d
@ -3,7 +3,6 @@ import 'package:fluffychat/utils/string_color.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_advanced_networkimage/provider.dart';
|
import 'package:flutter_advanced_networkimage/provider.dart';
|
||||||
|
|
||||||
import 'matrix.dart';
|
import 'matrix.dart';
|
||||||
|
|
||||||
class Avatar extends StatelessWidget {
|
class Avatar extends StatelessWidget {
|
||||||
@ -42,7 +41,7 @@ class Avatar extends StatelessWidget {
|
|||||||
backgroundImage: mxContent.mxc?.isNotEmpty ?? false
|
backgroundImage: mxContent.mxc?.isNotEmpty ?? false
|
||||||
? AdvancedNetworkImage(
|
? AdvancedNetworkImage(
|
||||||
src,
|
src,
|
||||||
useDiskCache: !kIsWeb,
|
useDiskCache: Matrix.of(context).client.storeAPI.extended,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: mxContent.mxc.isEmpty
|
backgroundColor: mxContent.mxc.isEmpty
|
||||||
|
@ -6,7 +6,7 @@ import 'package:fluffychat/utils/app_route.dart';
|
|||||||
import 'package:fluffychat/views/chat_details.dart';
|
import 'package:fluffychat/views/chat_details.dart';
|
||||||
import 'package:fluffychat/views/chat_list.dart';
|
import 'package:fluffychat/views/chat_list.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:fluffychat/utils/cross_url_launcher.dart';
|
||||||
|
|
||||||
import 'dialogs/simple_dialogs.dart';
|
import 'dialogs/simple_dialogs.dart';
|
||||||
import 'matrix.dart';
|
import 'matrix.dart';
|
||||||
|
@ -53,7 +53,8 @@ class ContentBanner extends StatelessWidget {
|
|||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
image: AdvancedNetworkImage(
|
image: AdvancedNetworkImage(
|
||||||
src,
|
src,
|
||||||
useDiskCache: !kIsWeb,
|
useDiskCache:
|
||||||
|
Matrix.of(context).client.storeAPI.extended,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Icon(defaultIcon, size: 300)
|
: Icon(defaultIcon, size: 300)
|
||||||
|
@ -55,9 +55,9 @@ class _ImageBubbleState extends State<ImageBubble> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
_getFile().then((MatrixFile file) {
|
_getFile().then((MatrixFile file) {
|
||||||
setState(() => _file = file);
|
if (mounted) setState(() => _file = file);
|
||||||
}, onError: (error) {
|
}, onError: (error) {
|
||||||
setState(() => _error = error);
|
if (mounted) setState(() => _error = error);
|
||||||
});
|
});
|
||||||
return Center(
|
return Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
|
@ -9,9 +9,9 @@ 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:flutter_styled_toast/flutter_styled_toast.dart';
|
||||||
import 'package:localstorage/localstorage.dart';
|
import 'package:cross_local_storage/cross_local_storage.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:fluffychat/utils/cross_url_launcher.dart';
|
||||||
|
|
||||||
import '../i18n/i18n.dart';
|
import '../i18n/i18n.dart';
|
||||||
import '../utils/app_route.dart';
|
import '../utils/app_route.dart';
|
||||||
@ -25,6 +25,8 @@ import 'avatar.dart';
|
|||||||
class Matrix extends StatefulWidget {
|
class Matrix extends StatefulWidget {
|
||||||
static const String callNamespace = 'chat.fluffy.jitsi_call';
|
static const String callNamespace = 'chat.fluffy.jitsi_call';
|
||||||
static const String defaultHomeserver = 'tchncs.de';
|
static const String defaultHomeserver = 'tchncs.de';
|
||||||
|
static bool get isMobile =>
|
||||||
|
kIsWeb ? false : (Platform.isAndroid || Platform.isIOS);
|
||||||
|
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
@ -70,11 +72,10 @@ class MatrixState extends State<Matrix> {
|
|||||||
String jitsiInstance = 'https://meet.jit.si/';
|
String jitsiInstance = 'https://meet.jit.si/';
|
||||||
|
|
||||||
void clean() async {
|
void clean() async {
|
||||||
if (!kIsWeb) return;
|
if (Matrix.isMobile) return;
|
||||||
|
|
||||||
final LocalStorage storage = LocalStorage('LocalStorage');
|
final LocalStorageInterface storage = await LocalStorage.getInstance();
|
||||||
await storage.ready;
|
await storage.remove(widget.clientName);
|
||||||
await storage.deleteItem(widget.clientName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildContext _loadingDialogContext;
|
BuildContext _loadingDialogContext;
|
||||||
@ -325,10 +326,10 @@ class MatrixState extends State<Matrix> {
|
|||||||
|
|
||||||
void _initWithStore() async {
|
void _initWithStore() async {
|
||||||
Future<LoginState> initLoginState = client.onLoginStateChanged.stream.first;
|
Future<LoginState> initLoginState = client.onLoginStateChanged.stream.first;
|
||||||
client.storeAPI = kIsWeb ? Store(client) : ExtendedStore(client);
|
client.storeAPI = !Matrix.isMobile ? Store(client) : ExtendedStore(client);
|
||||||
debugPrint(
|
debugPrint(
|
||||||
"[Store] Store is extended: ${client.storeAPI.extended.toString()}");
|
"[Store] Store is extended: ${client.storeAPI.extended.toString()}");
|
||||||
if (await initLoginState == LoginState.logged && !kIsWeb) {
|
if (await initLoginState == LoginState.logged && Matrix.isMobile) {
|
||||||
await setupFirebase();
|
await setupFirebase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -406,7 +407,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: true);
|
client = Client(widget.clientName, debug: false);
|
||||||
onJitsiCallSub ??= client.onEvent.stream
|
onJitsiCallSub ??= client.onEvent.stream
|
||||||
.where((e) =>
|
.where((e) =>
|
||||||
e.type == 'timeline' &&
|
e.type == 'timeline' &&
|
||||||
|
@ -7,7 +7,7 @@ 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: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:fluffychat/utils/cross_url_launcher.dart';
|
||||||
import 'package:fluffychat/utils/matrix_file_extension.dart';
|
import 'package:fluffychat/utils/matrix_file_extension.dart';
|
||||||
|
|
||||||
import 'matrix.dart';
|
import 'matrix.dart';
|
||||||
|
@ -34,6 +34,7 @@ class App extends StatelessWidget {
|
|||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
title: 'FluffyChat',
|
title: 'FluffyChat',
|
||||||
theme: ThemeSwitcherWidget.of(context).themeData,
|
theme: ThemeSwitcherWidget.of(context).themeData,
|
||||||
|
debugShowCheckedModeBanner: kIsWeb || Matrix.isMobile,
|
||||||
localizationsDelegates: [
|
localizationsDelegates: [
|
||||||
AppLocalizationsDelegate(),
|
AppLocalizationsDelegate(),
|
||||||
GlobalMaterialLocalizations.delegate,
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
18
lib/utils/cross_url_launcher.dart
Normal file
18
lib/utils/cross_url_launcher.dart
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart' as native_launcher;
|
||||||
|
import 'package:system/system.dart';
|
||||||
|
|
||||||
|
void launch(String url) {
|
||||||
|
if (kIsWeb || Platform.isAndroid || Platform.isIOS) {
|
||||||
|
native_launcher.launch(url);
|
||||||
|
} else if (Platform.isLinux) {
|
||||||
|
System.invoke('xdg-open $url');
|
||||||
|
} else if (Platform.isMacOS) {
|
||||||
|
System.invoke('open $url');
|
||||||
|
} else {
|
||||||
|
showToast('Open urls is not yet supported on this platform.');
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:famedlysdk/famedlysdk.dart';
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:localstorage/localstorage.dart';
|
import 'package:cross_local_storage/cross_local_storage.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
@ -12,20 +13,23 @@ import 'package:sqflite/sqflite.dart';
|
|||||||
|
|
||||||
class Store extends StoreAPI {
|
class Store extends StoreAPI {
|
||||||
final Client client;
|
final Client client;
|
||||||
final LocalStorage storage;
|
Future<LocalStorageInterface> storageFuture;
|
||||||
|
LocalStorageInterface storage;
|
||||||
final FlutterSecureStorage secureStorage;
|
final FlutterSecureStorage secureStorage;
|
||||||
|
|
||||||
Store(this.client)
|
Store(this.client)
|
||||||
: storage = LocalStorage('LocalStorage'),
|
: storageFuture = LocalStorage.getInstance(),
|
||||||
secureStorage = kIsWeb ? null : FlutterSecureStorage() {
|
secureStorage = !(Platform.isIOS || Platform.isAndroid)
|
||||||
|
? null
|
||||||
|
: FlutterSecureStorage() {
|
||||||
_init();
|
_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> getItem(String key) async {
|
Future<dynamic> getItem(String key) async {
|
||||||
if (kIsWeb) {
|
if (!(Platform.isIOS || Platform.isAndroid)) {
|
||||||
await storage.ready;
|
storage = await storageFuture;
|
||||||
try {
|
try {
|
||||||
return await storage.getItem(key);
|
return await storage.get(key);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -38,9 +42,9 @@ class Store extends StoreAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setItem(String key, String value) async {
|
Future<void> setItem(String key, String value) async {
|
||||||
if (kIsWeb) {
|
if (!(Platform.isIOS || Platform.isAndroid)) {
|
||||||
await storage.ready;
|
storage = await storageFuture;
|
||||||
return await storage.setItem(key, value);
|
return await storage.setString(key, value);
|
||||||
}
|
}
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return await secureStorage.delete(key: key);
|
return await secureStorage.delete(key: key);
|
||||||
@ -89,7 +93,7 @@ class Store extends StoreAPI {
|
|||||||
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: !(Platform.isIOS || Platform.isAndroid)
|
||||||
? null
|
? null
|
||||||
: (credentials["prev_batch"]?.isEmpty ?? true)
|
: (credentials["prev_batch"]?.isEmpty ?? true)
|
||||||
? null
|
? null
|
||||||
@ -112,7 +116,9 @@ class Store extends StoreAPI {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> clear() => kIsWeb ? storage.clear() : secureStorage.deleteAll();
|
Future<void> clear() => !(Platform.isIOS || Platform.isAndroid)
|
||||||
|
? storage.clear()
|
||||||
|
: secureStorage.deleteAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Responsible to store all data persistent and to query objects from the
|
/// Responsible to store all data persistent and to query objects from the
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:famedlysdk/famedlysdk.dart';
|
import 'package:famedlysdk/famedlysdk.dart';
|
||||||
|
import 'package:fluffychat/components/matrix.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:open_file/open_file.dart';
|
import 'package:open_file/open_file.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:system/system.dart';
|
||||||
import 'package:universal_html/prefer_universal/html.dart' as html;
|
import 'package:universal_html/prefer_universal/html.dart' as html;
|
||||||
import 'package:mime_type/mime_type.dart';
|
import 'package:mime_type/mime_type.dart';
|
||||||
|
|
||||||
extension MatrixFileExtension on MatrixFile {
|
extension MatrixFileExtension on MatrixFile {
|
||||||
void open() async {
|
void open() async {
|
||||||
Directory tempDir = await getTemporaryDirectory();
|
|
||||||
final file = File(tempDir.path + "/" + path.split("/").last);
|
|
||||||
file.writeAsBytesSync(bytes);
|
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
final fileName = path.split('/').last;
|
final fileName = path.split('/').last;
|
||||||
final mimeType = mime(fileName);
|
final mimeType = mime(fileName);
|
||||||
@ -26,8 +25,16 @@ extension MatrixFileExtension on MatrixFile {
|
|||||||
html.document.body.append(element);
|
html.document.body.append(element);
|
||||||
element.click();
|
element.click();
|
||||||
element.remove();
|
element.remove();
|
||||||
} else {
|
} else if (Matrix.isMobile) {
|
||||||
|
Directory tempDir = await getTemporaryDirectory();
|
||||||
|
final file = File(tempDir.path + "/" + path.split("/").last);
|
||||||
|
file.writeAsBytesSync(bytes);
|
||||||
await OpenFile.open(file.path);
|
await OpenFile.open(file.path);
|
||||||
|
} else if (Platform.isLinux) {
|
||||||
|
final filePath = "/home/krille/Downloads/";
|
||||||
|
final file = File(filePath + path.split("/").last);
|
||||||
|
file.writeAsBytesSync(bytes);
|
||||||
|
System.invoke('xdg-open $filePath');
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import 'package:fluffychat/components/matrix.dart';
|
|||||||
import 'package:fluffychat/utils/app_route.dart';
|
import 'package:fluffychat/utils/app_route.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:url_launcher/url_launcher.dart';
|
import 'package:fluffychat/utils/cross_url_launcher.dart';
|
||||||
|
|
||||||
class UrlLauncher {
|
class UrlLauncher {
|
||||||
final String url;
|
final String url;
|
||||||
|
@ -2,7 +2,7 @@ import 'package:fluffychat/components/matrix.dart';
|
|||||||
import 'package:fluffychat/i18n/i18n.dart';
|
import 'package:fluffychat/i18n/i18n.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:fluffychat/utils/cross_url_launcher.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
|
|
||||||
class AuthWebView extends StatelessWidget {
|
class AuthWebView extends StatelessWidget {
|
||||||
|
@ -176,10 +176,6 @@ class _ChatState extends State<_Chat> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sendFileAction(BuildContext context) async {
|
void sendFileAction(BuildContext context) async {
|
||||||
if (kIsWeb) {
|
|
||||||
showToast(I18n.of(context).notSupportedInWeb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
File file = await FilePicker.getFile();
|
File file = await FilePicker.getFile();
|
||||||
if (file == null) return;
|
if (file == null) return;
|
||||||
await matrix.tryRequestWithLoadingDialog(
|
await matrix.tryRequestWithLoadingDialog(
|
||||||
@ -190,10 +186,6 @@ class _ChatState extends State<_Chat> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sendImageAction(BuildContext context) async {
|
void sendImageAction(BuildContext context) async {
|
||||||
if (kIsWeb) {
|
|
||||||
showToast(I18n.of(context).notSupportedInWeb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
File file = await ImagePicker.pickImage(
|
File file = await ImagePicker.pickImage(
|
||||||
source: ImageSource.gallery,
|
source: ImageSource.gallery,
|
||||||
imageQuality: 50,
|
imageQuality: 50,
|
||||||
@ -208,10 +200,6 @@ class _ChatState extends State<_Chat> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void openCameraAction(BuildContext context) async {
|
void openCameraAction(BuildContext context) async {
|
||||||
if (kIsWeb) {
|
|
||||||
showToast(I18n.of(context).notSupportedInWeb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
File file = await ImagePicker.pickImage(
|
File file = await ImagePicker.pickImage(
|
||||||
source: ImageSource.camera,
|
source: ImageSource.camera,
|
||||||
imageQuality: 50,
|
imageQuality: 50,
|
||||||
@ -590,7 +578,7 @@ class _ChatState extends State<_Chat> {
|
|||||||
: Container(),
|
: Container(),
|
||||||
]
|
]
|
||||||
: <Widget>[
|
: <Widget>[
|
||||||
if (!kIsWeb && inputText.isEmpty)
|
if (Matrix.isMobile && inputText.isEmpty)
|
||||||
PopupMenuButton<String>(
|
PopupMenuButton<String>(
|
||||||
icon: Icon(Icons.add),
|
icon: Icon(Icons.add),
|
||||||
onSelected: (String choice) async {
|
onSelected: (String choice) async {
|
||||||
@ -669,8 +657,8 @@ class _ChatState extends State<_Chat> {
|
|||||||
vertical: 4.0),
|
vertical: 4.0),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
minLines: 1,
|
minLines: 1,
|
||||||
maxLines: kIsWeb ? 1 : 8,
|
maxLines: !Matrix.isMobile ? 1 : 8,
|
||||||
keyboardType: kIsWeb
|
keyboardType: !Matrix.isMobile
|
||||||
? TextInputType.text
|
? TextInputType.text
|
||||||
: TextInputType.multiline,
|
: TextInputType.multiline,
|
||||||
onSubmitted: (String text) {
|
onSubmitted: (String text) {
|
||||||
@ -709,13 +697,13 @@ class _ChatState extends State<_Chat> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!kIsWeb && inputText.isEmpty)
|
if (Matrix.isMobile && inputText.isEmpty)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.mic),
|
icon: Icon(Icons.mic),
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
voiceMessageAction(context),
|
voiceMessageAction(context),
|
||||||
),
|
),
|
||||||
if (kIsWeb || inputText.isNotEmpty)
|
if (!Matrix.isMobile || inputText.isNotEmpty)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.send),
|
icon: Icon(Icons.send),
|
||||||
onPressed: () => send(),
|
onPressed: () => send(),
|
||||||
|
@ -143,7 +143,7 @@ class _ChatListState extends State<ChatList> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _initReceiveSharingINtent() {
|
void _initReceiveSharingINtent() {
|
||||||
if (kIsWeb) return;
|
if (!Matrix.isMobile) return;
|
||||||
|
|
||||||
// For sharing images coming from outside the app while the app is in the memory
|
// For sharing images coming from outside the app while the app is in the memory
|
||||||
_intentFileStreamSubscription = ReceiveSharingIntent.getMediaStream()
|
_intentFileStreamSubscription = ReceiveSharingIntent.getMediaStream()
|
||||||
|
@ -7,7 +7,7 @@ import 'package:fluffychat/views/settings_devices.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.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:url_launcher/url_launcher.dart';
|
import 'package:fluffychat/utils/cross_url_launcher.dart';
|
||||||
|
|
||||||
import 'app_info.dart';
|
import 'app_info.dart';
|
||||||
import 'chat_list.dart';
|
import 'chat_list.dart';
|
||||||
|
1
linux/.gitignore
vendored
Normal file
1
linux/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
flutter/ephemeral
|
146
linux/Makefile
Normal file
146
linux/Makefile
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
include app_configuration.mk
|
||||||
|
|
||||||
|
# Default build type.
|
||||||
|
BUILD=debug
|
||||||
|
|
||||||
|
FLUTTER_MANAGED_DIR=flutter
|
||||||
|
FLUTTER_EPHEMERAL_DIR=$(FLUTTER_MANAGED_DIR)/ephemeral
|
||||||
|
|
||||||
|
# Configuration provided via flutter tool.
|
||||||
|
FLUTTER_CONFIG_FILE=$(FLUTTER_EPHEMERAL_DIR)/generated_config.mk
|
||||||
|
include $(FLUTTER_CONFIG_FILE)
|
||||||
|
|
||||||
|
# Dependency locations
|
||||||
|
FLUTTER_APP_DIR=$(CURDIR)/..
|
||||||
|
FLUTTER_APP_BUILD_DIR=$(FLUTTER_APP_DIR)/build
|
||||||
|
|
||||||
|
OUT_DIR=$(FLUTTER_APP_BUILD_DIR)/linux
|
||||||
|
OBJ_DIR=$(OUT_DIR)/obj/$(BUILD)
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
FLUTTER_LIB_NAME=flutter_linux_glfw
|
||||||
|
FLUTTER_LIB=$(FLUTTER_EPHEMERAL_DIR)/lib$(FLUTTER_LIB_NAME).so
|
||||||
|
|
||||||
|
# Tools
|
||||||
|
FLUTTER_BIN=$(FLUTTER_ROOT)/bin/flutter
|
||||||
|
LINUX_BUILD=$(FLUTTER_ROOT)/packages/flutter_tools/bin/tool_backend.sh
|
||||||
|
|
||||||
|
# Resources
|
||||||
|
ICU_DATA_NAME=icudtl.dat
|
||||||
|
ICU_DATA_SOURCE=$(FLUTTER_EPHEMERAL_DIR)/$(ICU_DATA_NAME)
|
||||||
|
FLUTTER_ASSETS_NAME=flutter_assets
|
||||||
|
FLUTTER_ASSETS_SOURCE=$(FLUTTER_APP_BUILD_DIR)/$(FLUTTER_ASSETS_NAME)
|
||||||
|
|
||||||
|
# Bundle structure
|
||||||
|
BUNDLE_OUT_DIR=$(OUT_DIR)/$(BUILD)
|
||||||
|
BUNDLE_DATA_DIR=$(BUNDLE_OUT_DIR)/data
|
||||||
|
BUNDLE_LIB_DIR=$(BUNDLE_OUT_DIR)/lib
|
||||||
|
|
||||||
|
BIN_OUT=$(BUNDLE_OUT_DIR)/$(BINARY_NAME)
|
||||||
|
ICU_DATA_OUT=$(BUNDLE_DATA_DIR)/$(ICU_DATA_NAME)
|
||||||
|
FLUTTER_LIB_OUT=$(BUNDLE_LIB_DIR)/$(notdir $(FLUTTER_LIB))
|
||||||
|
ALL_LIBS_OUT=$(FLUTTER_LIB_OUT) \
|
||||||
|
$(foreach lib,$(EXTRA_BUNDLED_LIBRARIES),$(BUNDLE_LIB_DIR)/$(notdir $(lib)))
|
||||||
|
|
||||||
|
# Add relevant code from the wrapper library, which is intended to be statically
|
||||||
|
# built into the client.
|
||||||
|
# Use abspath for the wrapper root, which can contain relative paths; the
|
||||||
|
# intermediate build files will be based on the source path, which will cause
|
||||||
|
# issues if they start with one or more '../'s.
|
||||||
|
WRAPPER_ROOT=$(abspath $(FLUTTER_EPHEMERAL_DIR)/cpp_client_wrapper_glfw)
|
||||||
|
WRAPPER_SOURCES= \
|
||||||
|
$(WRAPPER_ROOT)/flutter_window_controller.cc \
|
||||||
|
$(WRAPPER_ROOT)/plugin_registrar.cc \
|
||||||
|
$(WRAPPER_ROOT)/engine_method_result.cc
|
||||||
|
|
||||||
|
# Use abspath for extra sources, which may also contain relative paths (see
|
||||||
|
# note above about WRAPPER_ROOT).
|
||||||
|
SOURCES=main.cc window_configuration.cc \
|
||||||
|
flutter/generated_plugin_registrant.cc \
|
||||||
|
$(WRAPPER_SOURCES) $(abspath $(EXTRA_SOURCES))
|
||||||
|
|
||||||
|
# Headers
|
||||||
|
WRAPPER_INCLUDE_DIR=$(WRAPPER_ROOT)/include
|
||||||
|
INCLUDE_DIRS=$(FLUTTER_EPHEMERAL_DIR) $(WRAPPER_INCLUDE_DIR)
|
||||||
|
|
||||||
|
# Build settings
|
||||||
|
ifneq ($(strip $(SYSTEM_LIBRARIES)),)
|
||||||
|
EXTRA_CPPFLAGS+=$(patsubst -I%,-isystem%,$(shell pkg-config --cflags $(SYSTEM_LIBRARIES)))
|
||||||
|
EXTRA_LDFLAGS+=$(shell pkg-config --libs $(SYSTEM_LIBRARIES))
|
||||||
|
endif
|
||||||
|
CXX=clang++
|
||||||
|
CPPFLAGS.release=-DNDEBUG
|
||||||
|
CPPFLAGS.profile=$(CPPFLAGS.release)
|
||||||
|
CXXFLAGS.release=-O2
|
||||||
|
CXXFLAGS.profile=$(CXXFLAGS.release)
|
||||||
|
CXXFLAGS=-std=c++14 -Wall -Werror $(CXXFLAGS.$(BUILD)) $(EXTRA_CXXFLAGS)
|
||||||
|
CPPFLAGS=$(patsubst %,-I%,$(INCLUDE_DIRS)) \
|
||||||
|
$(CPPFLAGS.$(BUILD)) $(EXTRA_CPPFLAGS)
|
||||||
|
LDFLAGS=-L$(BUNDLE_LIB_DIR) \
|
||||||
|
-l$(FLUTTER_LIB_NAME) \
|
||||||
|
$(EXTRA_LDFLAGS) \
|
||||||
|
-Wl,-rpath=\$$ORIGIN/lib
|
||||||
|
|
||||||
|
# Intermediate files.
|
||||||
|
OBJ_FILES=$(SOURCES:%.cc=$(OBJ_DIR)/%.o)
|
||||||
|
DEPENDENCY_FILES=$(OBJ_FILES:%.o=%.d)
|
||||||
|
|
||||||
|
# Targets
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: $(BIN_OUT) bundle
|
||||||
|
|
||||||
|
# Add the plugin targets, and their associated settings.
|
||||||
|
include $(FLUTTER_MANAGED_DIR)/generated_plugins.mk
|
||||||
|
EXTRA_BUNDLED_LIBRARIES+=$(PLUGIN_LIBRARIES)
|
||||||
|
EXTRA_LDFLAGS+=$(PLUGIN_LDFLAGS)
|
||||||
|
EXTRA_CPPFLAGS+=$(PLUGIN_CPPFLAGS)
|
||||||
|
|
||||||
|
# This is a phony target because the flutter tool cannot describe
|
||||||
|
# its inputs and outputs yet.
|
||||||
|
.PHONY: sync
|
||||||
|
sync: $(FLUTTER_CONFIG_FILE)
|
||||||
|
$(LINUX_BUILD) linux-x64 $(BUILD)
|
||||||
|
|
||||||
|
.PHONY: bundle
|
||||||
|
bundle: $(ICU_DATA_OUT) $(ALL_LIBS_OUT) bundleflutterassets
|
||||||
|
|
||||||
|
$(BIN_OUT): $(OBJ_FILES) $(ALL_LIBS_OUT)
|
||||||
|
mkdir -p $(@D)
|
||||||
|
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OBJ_FILES) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
$(WRAPPER_SOURCES) $(FLUTTER_LIB) $(ICU_DATA_SOURCE) $(FLUTTER_ASSETS_SOURCE) \
|
||||||
|
$(PLUGIN_TARGETS): | sync
|
||||||
|
|
||||||
|
# Plugin library bundling pattern.
|
||||||
|
$(BUNDLE_LIB_DIR)/%: $(OUT_DIR)/%
|
||||||
|
mkdir -p $(BUNDLE_LIB_DIR)
|
||||||
|
cp $< $@
|
||||||
|
|
||||||
|
$(FLUTTER_LIB_OUT): $(FLUTTER_LIB)
|
||||||
|
mkdir -p $(@D)
|
||||||
|
cp $< $@
|
||||||
|
|
||||||
|
$(ICU_DATA_OUT): $(ICU_DATA_SOURCE)
|
||||||
|
mkdir -p $(@D)
|
||||||
|
cp $< $@
|
||||||
|
|
||||||
|
-include $(DEPENDENCY_FILES)
|
||||||
|
|
||||||
|
$(OBJ_DIR)/%.o : %.cc | sync
|
||||||
|
mkdir -p $(@D)
|
||||||
|
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -c $< -o $@
|
||||||
|
|
||||||
|
# Fully re-copy the assets directory on each build to avoid having to keep a
|
||||||
|
# comprehensive list of all asset files here, which would be fragile to changes
|
||||||
|
# in other files (e.g., adding a new font to pubspec.yaml).
|
||||||
|
.PHONY: bundleflutterassets
|
||||||
|
bundleflutterassets: $(FLUTTER_ASSETS_SOURCE)
|
||||||
|
mkdir -p $(BUNDLE_DATA_DIR)
|
||||||
|
rsync -rpu --delete $(FLUTTER_ASSETS_SOURCE) $(BUNDLE_DATA_DIR)
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -rf $(OUT_DIR); \
|
||||||
|
cd $(FLUTTER_APP_DIR); \
|
||||||
|
$(FLUTTER_BIN) clean
|
16
linux/app_configuration.mk
Normal file
16
linux/app_configuration.mk
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# This file contains variables that applications are likely to need to
|
||||||
|
# change, to isolate them from the main Makefile where the build rules are still
|
||||||
|
# in flux. This should simplify re-creating the runner while preserving local
|
||||||
|
# changes.
|
||||||
|
|
||||||
|
# Executable name.
|
||||||
|
BINARY_NAME=testbed
|
||||||
|
# Any extra source files to build.
|
||||||
|
EXTRA_SOURCES=
|
||||||
|
# Paths of any additional libraries to be bundled in the output directory.
|
||||||
|
EXTRA_BUNDLED_LIBRARIES=
|
||||||
|
# Extra flags (e.g., for library dependencies).
|
||||||
|
SYSTEM_LIBRARIES=gtk+-3.0 x11
|
||||||
|
EXTRA_CXXFLAGS=
|
||||||
|
EXTRA_CPPFLAGS=
|
||||||
|
EXTRA_LDFLAGS=
|
1
linux/flutter/.template_version
Normal file
1
linux/flutter/.template_version
Normal file
@ -0,0 +1 @@
|
|||||||
|
1
|
9
linux/flutter/generated_plugin_registrant.cc
Normal file
9
linux/flutter/generated_plugin_registrant.cc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// Generated file. Do not edit.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
|
||||||
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
}
|
13
linux/flutter/generated_plugin_registrant.h
Normal file
13
linux/flutter/generated_plugin_registrant.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// Generated file. Do not edit.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GENERATED_PLUGIN_REGISTRANT_
|
||||||
|
#define GENERATED_PLUGIN_REGISTRANT_
|
||||||
|
|
||||||
|
#include <flutter/plugin_registry.h>
|
||||||
|
|
||||||
|
// Registers Flutter plugins.
|
||||||
|
void RegisterPlugins(flutter::PluginRegistry* registry);
|
||||||
|
|
||||||
|
#endif // GENERATED_PLUGIN_REGISTRANT_
|
25
linux/flutter/generated_plugins.mk
Normal file
25
linux/flutter/generated_plugins.mk
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Plugins to include in the build.
|
||||||
|
GENERATED_PLUGINS=\
|
||||||
|
|
||||||
|
GENERATED_PLUGINS_DIR=flutter/ephemeral/.plugin_symlinks
|
||||||
|
# A plugin library name plugin name with _plugin appended.
|
||||||
|
GENERATED_PLUGIN_LIB_NAMES=$(foreach plugin,$(GENERATED_PLUGINS),$(plugin)_plugin)
|
||||||
|
|
||||||
|
# Variables for use in the enclosing Makefile. Changes to these names are
|
||||||
|
# breaking changes.
|
||||||
|
PLUGIN_TARGETS=$(GENERATED_PLUGINS)
|
||||||
|
PLUGIN_LIBRARIES=$(foreach plugin,$(GENERATED_PLUGIN_LIB_NAMES),\
|
||||||
|
$(OUT_DIR)/lib$(plugin).so)
|
||||||
|
PLUGIN_LDFLAGS=$(patsubst %,-l%,$(GENERATED_PLUGIN_LIB_NAMES))
|
||||||
|
PLUGIN_CPPFLAGS=$(foreach plugin,$(GENERATED_PLUGINS),\
|
||||||
|
-I$(GENERATED_PLUGINS_DIR)/$(plugin)/linux)
|
||||||
|
|
||||||
|
# Targets
|
||||||
|
|
||||||
|
# Implicit rules don't match phony targets, so list plugin builds explicitly.
|
||||||
|
|
||||||
|
.PHONY: $(GENERATED_PLUGINS)
|
||||||
|
$(GENERATED_PLUGINS):
|
||||||
|
make -C $(GENERATED_PLUGINS_DIR)/$@/linux \
|
||||||
|
OUT_DIR=$(OUT_DIR) \
|
||||||
|
FLUTTER_EPHEMERAL_DIR="$(abspath flutter/ephemeral)"
|
82
linux/main.cc
Normal file
82
linux/main.cc
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#include <flutter/flutter_window_controller.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// For plugin-compatible event handling (e.g., modal windows).
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#include "flutter/generated_plugin_registrant.h"
|
||||||
|
#include "window_configuration.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Returns the path of the directory containing this executable, or an empty
|
||||||
|
// string if the directory cannot be found.
|
||||||
|
std::string GetExecutableDirectory() {
|
||||||
|
char buffer[PATH_MAX + 1];
|
||||||
|
ssize_t length = readlink("/proc/self/exe", buffer, sizeof(buffer));
|
||||||
|
if (length > PATH_MAX) {
|
||||||
|
std::cerr << "Couldn't locate executable" << std::endl;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
std::string executable_path(buffer, length);
|
||||||
|
size_t last_separator_position = executable_path.find_last_of('/');
|
||||||
|
if (last_separator_position == std::string::npos) {
|
||||||
|
std::cerr << "Unabled to find parent directory of " << executable_path
|
||||||
|
<< std::endl;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return executable_path.substr(0, last_separator_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
// Resources are located relative to the executable.
|
||||||
|
std::string base_directory = GetExecutableDirectory();
|
||||||
|
if (base_directory.empty()) {
|
||||||
|
base_directory = ".";
|
||||||
|
}
|
||||||
|
std::string data_directory = base_directory + "/data";
|
||||||
|
std::string assets_path = data_directory + "/flutter_assets";
|
||||||
|
std::string icu_data_path = data_directory + "/icudtl.dat";
|
||||||
|
|
||||||
|
// Arguments for the Flutter Engine.
|
||||||
|
std::vector<std::string> arguments;
|
||||||
|
#ifdef NDEBUG
|
||||||
|
arguments.push_back("--disable-dart-asserts");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
flutter::FlutterWindowController flutter_controller(icu_data_path);
|
||||||
|
flutter::WindowProperties window_properties = {};
|
||||||
|
window_properties.title = kFlutterWindowTitle;
|
||||||
|
window_properties.width = kFlutterWindowWidth;
|
||||||
|
window_properties.height = kFlutterWindowHeight;
|
||||||
|
|
||||||
|
// Start the engine.
|
||||||
|
if (!flutter_controller.CreateWindow(window_properties, assets_path,
|
||||||
|
arguments)) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
RegisterPlugins(&flutter_controller);
|
||||||
|
|
||||||
|
// Set up for GTK event handling, needed by the GTK-based plugins.
|
||||||
|
gtk_init(0, nullptr);
|
||||||
|
XInitThreads();
|
||||||
|
|
||||||
|
// Run until the window is closed, processing GTK events in parallel for
|
||||||
|
// plugin handling.
|
||||||
|
while (flutter_controller.RunEventLoopWithTimeout(
|
||||||
|
std::chrono::milliseconds(10))) {
|
||||||
|
if (gtk_events_pending()) {
|
||||||
|
gtk_main_iteration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
5
linux/window_configuration.cc
Normal file
5
linux/window_configuration.cc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "window_configuration.h"
|
||||||
|
|
||||||
|
const char *kFlutterWindowTitle = "testbed";
|
||||||
|
const unsigned int kFlutterWindowWidth = 800;
|
||||||
|
const unsigned int kFlutterWindowHeight = 600;
|
15
linux/window_configuration.h
Normal file
15
linux/window_configuration.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef WINDOW_CONFIGURATION_
|
||||||
|
#define WINDOW_CONFIGURATION_
|
||||||
|
|
||||||
|
// This is a temporary approach to isolate common customizations from main.cpp,
|
||||||
|
// where the APIs are still in flux. This should simplify re-creating the
|
||||||
|
// runner while preserving local changes.
|
||||||
|
//
|
||||||
|
// Longer term there should be simpler configuration options for common
|
||||||
|
// customizations like this, without requiring native code changes.
|
||||||
|
|
||||||
|
extern const char *kFlutterWindowTitle;
|
||||||
|
extern const unsigned int kFlutterWindowWidth;
|
||||||
|
extern const unsigned int kFlutterWindowHeight;
|
||||||
|
|
||||||
|
#endif // WINDOW_CONFIGURATION_
|
1
preferences.json
Normal file
1
preferences.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"theme":"light","amoled_enabled":"false","FluffyChat linux":"{\"deviceID\":\"FWTWDQTSXK\",\"deviceName\":\"FluffyChat linux\",\"homeserver\":\"https://ubports.chat\",\"matrixVersions\":[\"r0.0.1\",\"r0.1.0\",\"r0.2.0\",\"r0.3.0\",\"r0.4.0\",\"r0.5.0\"],\"token\":\"MDAxYWxvY2F0aW9uIHVicG9ydHMuY2hhdAowMDEzaWRlbnRpZmllciBrZXkKMDAxMGNpZCBnZW4gPSAxCjAwMjZjaWQgdXNlcl9pZCA9IEBldGVzdDp1YnBvcnRzLmNoYXQKMDAxNmNpZCB0eXBlID0gYWNjZXNzCjAwMjFjaWQgbm9uY2UgPSBHQkBDQ25SYldCaStUbkQ5CjAwMmZzaWduYXR1cmUgoRJsL-s7bzq9MjfAN3ygl9KAKAkAjIrRrqr9V0PyWgEK\",\"userID\":\"@etest:ubports.chat\",\"olmAccount\":null}","/clients/FWTWDQTSXK/rooms/!NMplDtFmBvmtIiWDaa:ubports.chat/session_keys":"{}","/clients/FWTWDQTSXK/rooms/!LYRTvuBiZMyRGBADSe:ubports.chat/session_keys":"{}","/clients/FWTWDQTSXK/rooms/!WyihYMAfvwVpokHAjR:ubports.chat/session_keys":"{}","FluffyChat linux.user_device_keys":"{\"@etest:ubports.chat\":{\"user_id\":\"@etest:ubports.chat\",\"outdated\":false,\"device_keys\":{}}}"}
|
97
pubspec.lock
97
pubspec.lock
@ -35,14 +35,14 @@ packages:
|
|||||||
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,21 @@ 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"
|
||||||
|
clock:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: clock
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
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:
|
||||||
@ -85,6 +92,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.13.6"
|
version: "0.13.6"
|
||||||
|
cross_local_storage:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: cross_local_storage
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -113,6 +127,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.3"
|
version: "1.3.3"
|
||||||
|
fake_async:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fake_async
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
famedlysdk:
|
famedlysdk:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -281,7 +302,7 @@ packages:
|
|||||||
name: intl
|
name: intl
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.16.0"
|
version: "0.16.1"
|
||||||
intl_translation:
|
intl_translation:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -310,13 +331,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.1"
|
version: "0.1.1"
|
||||||
localstorage:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: localstorage
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.1+4"
|
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -425,7 +439,7 @@ packages:
|
|||||||
name: path
|
name: path
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.6.4"
|
version: "1.7.0"
|
||||||
path_drawing:
|
path_drawing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -503,13 +517,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.2"
|
version: "1.4.2"
|
||||||
quiver:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: quiver
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.5"
|
|
||||||
receive_sharing_intent:
|
receive_sharing_intent:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -524,6 +531,34 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.3+5"
|
version: "0.6.3+5"
|
||||||
|
shared_preferences:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.7"
|
||||||
|
shared_preferences_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_macos
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.1+7"
|
||||||
|
shared_preferences_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_platform_interface
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
|
shared_preferences_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_web
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.2+4"
|
||||||
shelf:
|
shelf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -577,7 +612,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:
|
||||||
@ -613,6 +648,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
|
system:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: system
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.0"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -626,21 +668,21 @@ packages:
|
|||||||
name: test
|
name: test
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.4"
|
version: "1.13.0"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.11"
|
version: "0.2.15"
|
||||||
test_core:
|
test_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_core
|
name: test_core
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.15"
|
version: "0.3.1"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -725,6 +767,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
webkit_inspection_protocol:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webkit_inspection_protocol
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.0+1"
|
||||||
webview_flutter:
|
webview_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -29,7 +29,7 @@ dependencies:
|
|||||||
url: https://gitlab.com/famedly/famedlysdk.git
|
url: https://gitlab.com/famedly/famedlysdk.git
|
||||||
ref: 28dee0e2e3dc2fdde64b29d0a65028b49b4c4dc7
|
ref: 28dee0e2e3dc2fdde64b29d0a65028b49b4c4dc7
|
||||||
|
|
||||||
localstorage: ^3.0.1+4
|
cross_local_storage: ^1.1.1
|
||||||
bubble: ^1.1.9+1
|
bubble: ^1.1.9+1
|
||||||
file_picker: ^1.4.3+2
|
file_picker: ^1.4.3+2
|
||||||
image_picker: ^0.6.2+3
|
image_picker: ^0.6.2+3
|
||||||
@ -54,6 +54,7 @@ dependencies:
|
|||||||
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
|
flutter_styled_toast: ^1.2.1
|
||||||
|
system: ^0.2.0
|
||||||
|
|
||||||
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