mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2024-12-02 17:29:34 +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/material.dart';
|
||||
import 'package:flutter_advanced_networkimage/provider.dart';
|
||||
|
||||
import 'matrix.dart';
|
||||
|
||||
class Avatar extends StatelessWidget {
|
||||
@ -42,7 +41,7 @@ class Avatar extends StatelessWidget {
|
||||
backgroundImage: mxContent.mxc?.isNotEmpty ?? false
|
||||
? AdvancedNetworkImage(
|
||||
src,
|
||||
useDiskCache: !kIsWeb,
|
||||
useDiskCache: Matrix.of(context).client.storeAPI.extended,
|
||||
)
|
||||
: null,
|
||||
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_list.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 'matrix.dart';
|
||||
|
@ -53,7 +53,8 @@ class ContentBanner extends StatelessWidget {
|
||||
fit: BoxFit.cover,
|
||||
image: AdvancedNetworkImage(
|
||||
src,
|
||||
useDiskCache: !kIsWeb,
|
||||
useDiskCache:
|
||||
Matrix.of(context).client.storeAPI.extended,
|
||||
),
|
||||
)
|
||||
: Icon(defaultIcon, size: 300)
|
||||
|
@ -55,9 +55,9 @@ class _ImageBubbleState extends State<ImageBubble> {
|
||||
);
|
||||
}
|
||||
_getFile().then((MatrixFile file) {
|
||||
setState(() => _file = file);
|
||||
if (mounted) setState(() => _file = file);
|
||||
}, onError: (error) {
|
||||
setState(() => _error = error);
|
||||
if (mounted) setState(() => _error = error);
|
||||
});
|
||||
return Center(
|
||||
child: CircularProgressIndicator(),
|
||||
|
@ -9,9 +9,9 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.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:cross_local_storage/cross_local_storage.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 '../utils/app_route.dart';
|
||||
@ -25,6 +25,8 @@ import 'avatar.dart';
|
||||
class Matrix extends StatefulWidget {
|
||||
static const String callNamespace = 'chat.fluffy.jitsi_call';
|
||||
static const String defaultHomeserver = 'tchncs.de';
|
||||
static bool get isMobile =>
|
||||
kIsWeb ? false : (Platform.isAndroid || Platform.isIOS);
|
||||
|
||||
final Widget child;
|
||||
|
||||
@ -70,11 +72,10 @@ class MatrixState extends State<Matrix> {
|
||||
String jitsiInstance = 'https://meet.jit.si/';
|
||||
|
||||
void clean() async {
|
||||
if (!kIsWeb) return;
|
||||
if (Matrix.isMobile) return;
|
||||
|
||||
final LocalStorage storage = LocalStorage('LocalStorage');
|
||||
await storage.ready;
|
||||
await storage.deleteItem(widget.clientName);
|
||||
final LocalStorageInterface storage = await LocalStorage.getInstance();
|
||||
await storage.remove(widget.clientName);
|
||||
}
|
||||
|
||||
BuildContext _loadingDialogContext;
|
||||
@ -325,10 +326,10 @@ class MatrixState extends State<Matrix> {
|
||||
|
||||
void _initWithStore() async {
|
||||
Future<LoginState> initLoginState = client.onLoginStateChanged.stream.first;
|
||||
client.storeAPI = kIsWeb ? Store(client) : ExtendedStore(client);
|
||||
client.storeAPI = !Matrix.isMobile ? Store(client) : ExtendedStore(client);
|
||||
debugPrint(
|
||||
"[Store] Store is extended: ${client.storeAPI.extended.toString()}");
|
||||
if (await initLoginState == LoginState.logged && !kIsWeb) {
|
||||
if (await initLoginState == LoginState.logged && Matrix.isMobile) {
|
||||
await setupFirebase();
|
||||
}
|
||||
}
|
||||
@ -406,7 +407,7 @@ class MatrixState extends State<Matrix> {
|
||||
void initState() {
|
||||
if (widget.client == null) {
|
||||
debugPrint("[Matrix] Init matrix client");
|
||||
client = Client(widget.clientName, debug: true);
|
||||
client = Client(widget.clientName, debug: false);
|
||||
onJitsiCallSub ??= client.onEvent.stream
|
||||
.where((e) =>
|
||||
e.type == 'timeline' &&
|
||||
|
@ -7,7 +7,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_styled_toast/flutter_styled_toast.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 'matrix.dart';
|
||||
|
@ -34,6 +34,7 @@ class App extends StatelessWidget {
|
||||
child: MaterialApp(
|
||||
title: 'FluffyChat',
|
||||
theme: ThemeSwitcherWidget.of(context).themeData,
|
||||
debugShowCheckedModeBanner: kIsWeb || Matrix.isMobile,
|
||||
localizationsDelegates: [
|
||||
AppLocalizationsDelegate(),
|
||||
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:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
import 'package:flutter/foundation.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:core';
|
||||
import 'package:path/path.dart' as p;
|
||||
@ -12,20 +13,23 @@ import 'package:sqflite/sqflite.dart';
|
||||
|
||||
class Store extends StoreAPI {
|
||||
final Client client;
|
||||
final LocalStorage storage;
|
||||
Future<LocalStorageInterface> storageFuture;
|
||||
LocalStorageInterface storage;
|
||||
final FlutterSecureStorage secureStorage;
|
||||
|
||||
Store(this.client)
|
||||
: storage = LocalStorage('LocalStorage'),
|
||||
secureStorage = kIsWeb ? null : FlutterSecureStorage() {
|
||||
: storageFuture = LocalStorage.getInstance(),
|
||||
secureStorage = !(Platform.isIOS || Platform.isAndroid)
|
||||
? null
|
||||
: FlutterSecureStorage() {
|
||||
_init();
|
||||
}
|
||||
|
||||
Future<dynamic> getItem(String key) async {
|
||||
if (kIsWeb) {
|
||||
await storage.ready;
|
||||
if (!(Platform.isIOS || Platform.isAndroid)) {
|
||||
storage = await storageFuture;
|
||||
try {
|
||||
return await storage.getItem(key);
|
||||
return await storage.get(key);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
@ -38,9 +42,9 @@ class Store extends StoreAPI {
|
||||
}
|
||||
|
||||
Future<void> setItem(String key, String value) async {
|
||||
if (kIsWeb) {
|
||||
await storage.ready;
|
||||
return await storage.setItem(key, value);
|
||||
if (!(Platform.isIOS || Platform.isAndroid)) {
|
||||
storage = await storageFuture;
|
||||
return await storage.setString(key, value);
|
||||
}
|
||||
if (value == null) {
|
||||
return await secureStorage.delete(key: key);
|
||||
@ -89,7 +93,7 @@ class Store extends StoreAPI {
|
||||
newMatrixVersions: List<String>.from(credentials["matrixVersions"] ?? []),
|
||||
newToken: credentials["token"],
|
||||
newUserID: credentials["userID"],
|
||||
newPrevBatch: kIsWeb
|
||||
newPrevBatch: !(Platform.isIOS || Platform.isAndroid)
|
||||
? null
|
||||
: (credentials["prev_batch"]?.isEmpty ?? true)
|
||||
? null
|
||||
@ -112,7 +116,9 @@ class Store extends StoreAPI {
|
||||
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
|
||||
|
@ -1,17 +1,16 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
import 'package:fluffychat/components/matrix.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:open_file/open_file.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:mime_type/mime_type.dart';
|
||||
|
||||
extension MatrixFileExtension on MatrixFile {
|
||||
void open() async {
|
||||
Directory tempDir = await getTemporaryDirectory();
|
||||
final file = File(tempDir.path + "/" + path.split("/").last);
|
||||
file.writeAsBytesSync(bytes);
|
||||
if (kIsWeb) {
|
||||
final fileName = path.split('/').last;
|
||||
final mimeType = mime(fileName);
|
||||
@ -26,8 +25,16 @@ extension MatrixFileExtension on MatrixFile {
|
||||
html.document.body.append(element);
|
||||
element.click();
|
||||
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);
|
||||
} 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;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import 'package:fluffychat/components/matrix.dart';
|
||||
import 'package:fluffychat/utils/app_route.dart';
|
||||
import 'package:fluffychat/views/chat.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:fluffychat/utils/cross_url_launcher.dart';
|
||||
|
||||
class UrlLauncher {
|
||||
final String url;
|
||||
|
@ -2,7 +2,7 @@ import 'package:fluffychat/components/matrix.dart';
|
||||
import 'package:fluffychat/i18n/i18n.dart';
|
||||
import 'package:flutter/foundation.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';
|
||||
|
||||
class AuthWebView extends StatelessWidget {
|
||||
|
@ -176,10 +176,6 @@ class _ChatState extends State<_Chat> {
|
||||
}
|
||||
|
||||
void sendFileAction(BuildContext context) async {
|
||||
if (kIsWeb) {
|
||||
showToast(I18n.of(context).notSupportedInWeb);
|
||||
return;
|
||||
}
|
||||
File file = await FilePicker.getFile();
|
||||
if (file == null) return;
|
||||
await matrix.tryRequestWithLoadingDialog(
|
||||
@ -190,10 +186,6 @@ class _ChatState extends State<_Chat> {
|
||||
}
|
||||
|
||||
void sendImageAction(BuildContext context) async {
|
||||
if (kIsWeb) {
|
||||
showToast(I18n.of(context).notSupportedInWeb);
|
||||
return;
|
||||
}
|
||||
File file = await ImagePicker.pickImage(
|
||||
source: ImageSource.gallery,
|
||||
imageQuality: 50,
|
||||
@ -208,10 +200,6 @@ class _ChatState extends State<_Chat> {
|
||||
}
|
||||
|
||||
void openCameraAction(BuildContext context) async {
|
||||
if (kIsWeb) {
|
||||
showToast(I18n.of(context).notSupportedInWeb);
|
||||
return;
|
||||
}
|
||||
File file = await ImagePicker.pickImage(
|
||||
source: ImageSource.camera,
|
||||
imageQuality: 50,
|
||||
@ -590,7 +578,7 @@ class _ChatState extends State<_Chat> {
|
||||
: Container(),
|
||||
]
|
||||
: <Widget>[
|
||||
if (!kIsWeb && inputText.isEmpty)
|
||||
if (Matrix.isMobile && inputText.isEmpty)
|
||||
PopupMenuButton<String>(
|
||||
icon: Icon(Icons.add),
|
||||
onSelected: (String choice) async {
|
||||
@ -669,8 +657,8 @@ class _ChatState extends State<_Chat> {
|
||||
vertical: 4.0),
|
||||
child: TextField(
|
||||
minLines: 1,
|
||||
maxLines: kIsWeb ? 1 : 8,
|
||||
keyboardType: kIsWeb
|
||||
maxLines: !Matrix.isMobile ? 1 : 8,
|
||||
keyboardType: !Matrix.isMobile
|
||||
? TextInputType.text
|
||||
: TextInputType.multiline,
|
||||
onSubmitted: (String text) {
|
||||
@ -709,13 +697,13 @@ class _ChatState extends State<_Chat> {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!kIsWeb && inputText.isEmpty)
|
||||
if (Matrix.isMobile && inputText.isEmpty)
|
||||
IconButton(
|
||||
icon: Icon(Icons.mic),
|
||||
onPressed: () =>
|
||||
voiceMessageAction(context),
|
||||
),
|
||||
if (kIsWeb || inputText.isNotEmpty)
|
||||
if (!Matrix.isMobile || inputText.isNotEmpty)
|
||||
IconButton(
|
||||
icon: Icon(Icons.send),
|
||||
onPressed: () => send(),
|
||||
|
@ -143,7 +143,7 @@ class _ChatListState extends State<ChatList> {
|
||||
}
|
||||
|
||||
void _initReceiveSharingINtent() {
|
||||
if (kIsWeb) return;
|
||||
if (!Matrix.isMobile) return;
|
||||
|
||||
// For sharing images coming from outside the app while the app is in the memory
|
||||
_intentFileStreamSubscription = ReceiveSharingIntent.getMediaStream()
|
||||
|
@ -7,7 +7,7 @@ import 'package:fluffychat/views/settings_devices.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.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 '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
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
version: "2.4.1"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
version: "2.0.0"
|
||||
bubble:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -63,14 +63,21 @@ packages:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.14.11"
|
||||
version: "1.14.12"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -85,6 +92,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -113,6 +127,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
famedlysdk:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -281,7 +302,7 @@ packages:
|
||||
name: intl
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.16.0"
|
||||
version: "0.16.1"
|
||||
intl_translation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -310,13 +331,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.1"
|
||||
localstorage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: localstorage
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1+4"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -425,7 +439,7 @@ packages:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.4"
|
||||
version: "1.7.0"
|
||||
path_drawing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -503,13 +517,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.4.2"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: quiver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
receive_sharing_intent:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -524,6 +531,34 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -577,7 +612,7 @@ packages:
|
||||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.5"
|
||||
version: "1.7.0"
|
||||
sqflite:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -613,6 +648,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
system:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: system
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -626,21 +668,21 @@ packages:
|
||||
name: test
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.4"
|
||||
version: "1.13.0"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.11"
|
||||
version: "0.2.15"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.15"
|
||||
version: "0.3.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -725,6 +767,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -29,7 +29,7 @@ dependencies:
|
||||
url: https://gitlab.com/famedly/famedlysdk.git
|
||||
ref: 28dee0e2e3dc2fdde64b29d0a65028b49b4c4dc7
|
||||
|
||||
localstorage: ^3.0.1+4
|
||||
cross_local_storage: ^1.1.1
|
||||
bubble: ^1.1.9+1
|
||||
file_picker: ^1.4.3+2
|
||||
image_picker: ^0.6.2+3
|
||||
@ -54,6 +54,7 @@ dependencies:
|
||||
open_file: ^3.0.1
|
||||
mime_type: ^0.2.7
|
||||
flutter_styled_toast: ^1.2.1
|
||||
system: ^0.2.0
|
||||
|
||||
intl: ^0.16.0
|
||||
intl_translation: ^0.17.9
|
||||
|
Loading…
Reference in New Issue
Block a user