mirror of
https://github.com/krille-chan/fluffychat
synced 2024-09-10 11:45:10 +00:00
Merge branch 'braid/windows' into 'main'
chore: Windows support See merge request famedly/fluffychat!949
This commit is contained in:
commit
99cc9f068b
23 changed files with 308 additions and 148 deletions
|
@ -391,9 +391,11 @@ upload-windows:
|
|||
image: alpine:latest
|
||||
script:
|
||||
- apk add --no-cache curl zip
|
||||
- mv build/windows/runner/Release/fluffychat.msix fluffychat.msix
|
||||
- cd build/windows/runner/Release; zip -r ../../../../package.zip . ; cd -
|
||||
- |
|
||||
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.zip ${PACKAGE_REGISTRY_URL}/fluffychat-windows.zip
|
||||
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file fluffychat.msix ${PACKAGE_REGISTRY_URL}/fluffychat-windows.msix
|
||||
|
||||
upload-playstore:
|
||||
stage: release
|
||||
|
@ -416,6 +418,7 @@ release:
|
|||
--assets-link "{\"name\":\"fluffychat-linux-x86.tar.gz\",\"url\":\"${PACKAGE_REGISTRY_URL}/fluffychat-linux-x86.tar.gz\"}" \
|
||||
--assets-link "{\"name\":\"fluffychat-linux-arm64.tar.gz\",\"url\":\"${PACKAGE_REGISTRY_URL}/fluffychat-linux-arm64.tar.gz\"}" \
|
||||
--assets-link "{\"name\":\"fluffychat-windows.zip\",\"url\":\"${PACKAGE_REGISTRY_URL}/fluffychat-windows.zip\"}" \
|
||||
--assets-link "{\"name\":\"fluffychat-windows.msix\",\"url\":\"${PACKAGE_REGISTRY_URL}/fluffychat-windows.msix\"}" \
|
||||
--assets-link "{\"name\":\"fluffychat-web.tar.gz\",\"url\":\"${PACKAGE_REGISTRY_URL}/fluffychat-web.tar.gz\"}"
|
||||
--assets-link "{\"name\":\"FluffyChat-x86_64.AppImage\",\"url\":\"${PACKAGE_REGISTRY_URL}/FluffyChat-x86_64.AppImage\",\"filepath\":\"/FluffyChat-x86_64.AppImage\"}"
|
||||
--assets-link "{\"name\":\"FluffyChat-x86_64.AppImage.zsync\",\"url\":\"${PACKAGE_REGISTRY_URL}/FluffyChat-x86_64.AppImage.zsync\",\"filepath\":\"/FluffyChat-x86_64.AppImage.zsync\"}"
|
||||
|
|
15
.metadata
15
.metadata
|
@ -15,21 +15,6 @@ migration:
|
|||
- platform: root
|
||||
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
- platform: android
|
||||
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
- platform: ios
|
||||
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
- platform: linux
|
||||
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
- platform: macos
|
||||
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
- platform: web
|
||||
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
- platform: windows
|
||||
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"updateAvailable": "FluffyChat update available",
|
||||
"updateNow": "Start update in background",
|
||||
"accept": "Accept",
|
||||
"@accept": {
|
||||
"type": "text",
|
||||
|
|
116
lib/utils/update_checker_no_store.dart
Normal file
116
lib/utils/update_checker_no_store.dart
Normal file
|
@ -0,0 +1,116 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import 'platform_infos.dart';
|
||||
|
||||
/// helper class checking for updates on platforms without store release
|
||||
///
|
||||
/// Currently, this is only Windows
|
||||
class UpdateCheckerNoStore {
|
||||
static const gitLabProjectId = '16112282';
|
||||
static const gitLabHost = 'gitlab.com';
|
||||
|
||||
static Uri get tagsUri => Uri.parse(
|
||||
'https://$gitLabHost/projects/$gitLabProjectId/repository/tags');
|
||||
|
||||
final BuildContext context;
|
||||
|
||||
const UpdateCheckerNoStore(this.context);
|
||||
|
||||
Future<void> checkUpdate() async {
|
||||
// platform-specific implementations
|
||||
try {
|
||||
if (PlatformInfos.isWindows) {
|
||||
final response = await get(tagsUri);
|
||||
if (response.statusCode == 200) {
|
||||
final json = jsonDecode(response.body);
|
||||
var latestTag = json[0]['name'] as String;
|
||||
var currentVersion = await PlatformInfos.getVersion();
|
||||
|
||||
if (latestTag.startsWith('v')) {
|
||||
latestTag = latestTag.substring(1);
|
||||
}
|
||||
if (currentVersion.startsWith('v')) {
|
||||
currentVersion = currentVersion.substring(1);
|
||||
}
|
||||
if (latestTag != currentVersion) {
|
||||
final metadata = UpdateMetadata(latestTag);
|
||||
await showUpdateDialog(metadata);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
throw response;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
Logs().i('Could not look for updates:', e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Uri downloadUri(UpdateMetadata metadata) {
|
||||
// platform specific
|
||||
if (PlatformInfos.isWindows) {
|
||||
return Uri.parse('https://$gitLabHost/famedly/fluffychat/-'
|
||||
'/jobs/artifacts/$metadata/raw/'
|
||||
'build/windows/runner/Release/fluffychat.msix?job=build_windows');
|
||||
} else {
|
||||
throw UnimplementedError('No download URI available for this platform.');
|
||||
}
|
||||
}
|
||||
|
||||
/// launches an app update
|
||||
///
|
||||
/// Either uses the operating systems package or app management to perform
|
||||
/// an update or launches a custom installer
|
||||
Future<void> launchUpdater(UpdateMetadata metadata) async {
|
||||
// platform specific
|
||||
try {
|
||||
if (kIsWeb) return;
|
||||
if (PlatformInfos.isWindows) {
|
||||
final dir = await getTemporaryDirectory();
|
||||
final response = await get(downloadUri(metadata));
|
||||
if (response.statusCode == 200) {
|
||||
final file = File(dir.path + '/fluffychat.msix');
|
||||
await file.writeAsBytes(response.bodyBytes);
|
||||
Process.start(file.path, [], runInShell: true);
|
||||
} else {
|
||||
throw response;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
Logs().w('Error launching th update:', e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showUpdateDialog(UpdateMetadata metadata) async {
|
||||
final result = await showOkCancelAlertDialog(
|
||||
title: L10n.of(context)!.updateAvailable,
|
||||
message: L10n.of(context)!.updateNow,
|
||||
context: context,
|
||||
);
|
||||
if (result == OkCancelResult.ok) {
|
||||
await launchUpdater(metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UpdateMetadata {
|
||||
final String version;
|
||||
|
||||
const UpdateMetadata(this.version);
|
||||
|
||||
@override
|
||||
String toString() => 'v$version';
|
||||
}
|
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:matrix/matrix.dart';
|
||||
import 'package:vrouter/vrouter.dart';
|
||||
|
||||
import 'package:fluffychat/utils/update_checker_no_store.dart';
|
||||
import 'package:fluffychat/widgets/layouts/empty_page.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
|
@ -12,13 +13,16 @@ class LoadingView extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) => VRouter.of(context).to(
|
||||
Matrix.of(context).widget.clients.any((client) =>
|
||||
client.onLoginStateChanged.value == LoginState.loggedIn)
|
||||
? '/rooms'
|
||||
: '/home',
|
||||
queryParameters: VRouter.of(context).queryParameters,
|
||||
),
|
||||
(_) async {
|
||||
await UpdateCheckerNoStore(context).checkUpdate();
|
||||
VRouter.of(context).to(
|
||||
Matrix.of(context).widget.clients.any((client) =>
|
||||
client.onLoginStateChanged.value == LoginState.loggedIn)
|
||||
? '/rooms'
|
||||
: '/home',
|
||||
queryParameters: VRouter.of(context).queryParameters,
|
||||
);
|
||||
},
|
||||
);
|
||||
return const EmptyPage(loading: true);
|
||||
}
|
||||
|
|
40
pubspec.lock
40
pubspec.lock
|
@ -162,6 +162,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
cli_dialog:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_dialog
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
cli_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -276,6 +283,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.12.0"
|
||||
dart_console:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_console
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -684,11 +698,13 @@ packages:
|
|||
source: hosted
|
||||
version: "1.0.2"
|
||||
flutter_secure_storage_windows:
|
||||
dependency: transitive
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: flutter_secure_storage_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: "3751da0df5eede20d64816ceb79ca78ace7389b3"
|
||||
url: "https://gitlab.com/TheOneWithTheBraid/flutter_secure_storage_windows.git"
|
||||
source: git
|
||||
version: "1.1.2"
|
||||
flutter_slidable:
|
||||
dependency: "direct main"
|
||||
|
@ -789,6 +805,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.6"
|
||||
get_it:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: get_it
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "7.2.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -839,7 +862,7 @@ packages:
|
|||
source: hosted
|
||||
version: "2.0.0"
|
||||
http:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
url: "https://pub.dartlang.org"
|
||||
|
@ -1090,6 +1113,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
msix:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: msix
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.6.2"
|
||||
native_imaging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
22
pubspec.yaml
22
pubspec.yaml
|
@ -53,6 +53,7 @@ dependencies:
|
|||
geolocator: ^7.6.2
|
||||
handy_window: ^0.1.6
|
||||
hive_flutter: ^1.1.0
|
||||
http: ^0.13.4
|
||||
image: ^3.1.1
|
||||
image_picker: ^0.8.4+8
|
||||
intl: any
|
||||
|
@ -96,10 +97,10 @@ dev_dependencies:
|
|||
flutter_native_splash: ^2.0.3+1
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
http: ^0.13.4
|
||||
import_sorter: ^4.6.0
|
||||
integration_test:
|
||||
sdk: flutter
|
||||
msix: ^3.6.2
|
||||
|
||||
flutter_native_splash:
|
||||
color: "#ffffff"
|
||||
|
@ -127,6 +128,19 @@ flutter:
|
|||
fonts:
|
||||
- asset: fonts/NotoEmoji/NotoColorEmoji.ttf
|
||||
|
||||
msix_config:
|
||||
display_name: FluffyChat
|
||||
publisher_display_name: FluffyChat
|
||||
publisher: CN=FluffyChat, O=Head of bad integration tests, L=Matrix, S=Internet, C=EU
|
||||
identity_name: chat.fluffy.fluffychat
|
||||
logo_path: assets\logo.png
|
||||
capabilities: internetClient, location, microphone, webcam
|
||||
protocol_activation: https
|
||||
app_uri_handler_hosts: fluffychat.im, matrix.to
|
||||
execution_alias: fluffychat
|
||||
sign_msix: false
|
||||
install_certificate: false
|
||||
|
||||
dependency_overrides:
|
||||
# Necessary for webRTC on web.
|
||||
# Fix for stream fallback for unsupported browsers:
|
||||
|
@ -136,6 +150,12 @@ dependency_overrides:
|
|||
url: https://github.com/TheOneWithTheBraid/plus_plugins.git
|
||||
ref: a04401cb48abe92d138c0e9288b360739994a9e9
|
||||
path: packages/connectivity_plus/connectivity_plus_web
|
||||
# fake secure storage plugin for Windows
|
||||
# See: https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues/15161
|
||||
flutter_secure_storage_windows:
|
||||
git:
|
||||
url: https://gitlab.com/TheOneWithTheBraid/flutter_secure_storage_windows.git
|
||||
ref: main
|
||||
geolocator_android:
|
||||
hosted:
|
||||
name: geolocator_android
|
||||
|
|
|
@ -2,4 +2,11 @@ flutter doctor
|
|||
flutter config --enable-windows-desktop
|
||||
flutter clean
|
||||
flutter pub get
|
||||
flutter build windows --release -v
|
||||
|
||||
Write-Output "$WINDOWN_PFX"
|
||||
Move-Item -Path $WINDOWS_PFX -Destination fluffychat.pem
|
||||
certutil -decode fluffychat.pem fluffychat.pfx
|
||||
|
||||
flutter build windows --release -v
|
||||
|
||||
flutter pub run msix:create -c fluffychat.pfx -p $WINDOWS_PFX_PASS --sign-msix true --install-certificate false
|
|
@ -1,3 +1,5 @@
|
|||
choco install flutter -y
|
||||
Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
||||
refreshenv
|
||||
refreshenv
|
||||
|
||||
flutter config --no-analytics
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
# Project-level configuration.
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(fluffychat LANGUAGES CXX)
|
||||
|
||||
# The name of the executable created for the application. Change this to change
|
||||
# the on-disk name of your application.
|
||||
set(BINARY_NAME "fluffychat")
|
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||
# versions of CMake.
|
||||
cmake_policy(SET CMP0063 NEW)
|
||||
|
||||
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
|
||||
|
||||
# Configure build options.
|
||||
# Define build configuration option.
|
||||
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(IS_MULTICONFIG)
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
|
||||
|
@ -20,7 +23,7 @@ else()
|
|||
"Debug" "Profile" "Release")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Define settings for the Profile build mode.
|
||||
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
|
||||
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
|
||||
|
@ -30,6 +33,10 @@ set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
|
|||
add_definitions(-DUNICODE -D_UNICODE)
|
||||
|
||||
# Compilation settings that should be applied to most targets.
|
||||
#
|
||||
# Be cautious about adding new options here, as plugins use this function by
|
||||
# default. In most cases, you should add new options to specific targets instead
|
||||
# of modifying this function.
|
||||
function(APPLY_STANDARD_SETTINGS TARGET)
|
||||
target_compile_features(${TARGET} PUBLIC cxx_std_17)
|
||||
target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
|
||||
|
@ -38,12 +45,11 @@ function(APPLY_STANDARD_SETTINGS TARGET)
|
|||
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
|
||||
endfunction()
|
||||
|
||||
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
||||
|
||||
# Flutter library and tool build rules.
|
||||
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
||||
add_subdirectory(${FLUTTER_MANAGED_DIR})
|
||||
|
||||
# Application build
|
||||
# Application build; see runner/CMakeLists.txt.
|
||||
add_subdirectory("runner")
|
||||
|
||||
# Generated plugin build rules, which manage building the plugins and adding
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
# This file controls Flutter-level build steps. It should not be edited.
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
|
||||
|
||||
|
@ -23,6 +24,7 @@ list(APPEND FLUTTER_LIBRARY_HEADERS
|
|||
"flutter_windows.h"
|
||||
"flutter_messenger.h"
|
||||
"flutter_plugin_registrar.h"
|
||||
"flutter_texture_registrar.h"
|
||||
)
|
||||
list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
|
||||
add_library(flutter INTERFACE)
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include <connectivity_plus_windows/connectivity_plus_windows_plugin.h>
|
||||
#include <desktop_drop/desktop_drop_plugin.h>
|
||||
#include <desktop_lifecycle/desktop_lifecycle_plugin.h>
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
#include <flutter_webrtc/flutter_web_r_t_c_plugin.h>
|
||||
#include <record_windows/record_windows_plugin_c_api.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
@ -21,8 +20,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||
registry->GetRegistrarForPlugin("DesktopDropPlugin"));
|
||||
DesktopLifecyclePluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("DesktopLifecyclePlugin"));
|
||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||
FlutterWebRTCPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterWebRTCPlugin"));
|
||||
RecordWindowsPluginCApiRegisterWithRegistrar(
|
||||
|
|
|
@ -6,7 +6,6 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||
connectivity_plus_windows
|
||||
desktop_drop
|
||||
desktop_lifecycle
|
||||
flutter_secure_storage_windows
|
||||
flutter_webrtc
|
||||
record_windows
|
||||
url_launcher_windows
|
||||
|
|
|
@ -1,18 +1,32 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(runner LANGUAGES CXX)
|
||||
|
||||
# Define the application target. To change its name, change BINARY_NAME in the
|
||||
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
|
||||
# work.
|
||||
#
|
||||
# Any new source files that you add to the application should be added here.
|
||||
add_executable(${BINARY_NAME} WIN32
|
||||
"flutter_window.cpp"
|
||||
"main.cpp"
|
||||
"run_loop.cpp"
|
||||
"utils.cpp"
|
||||
"win32_window.cpp"
|
||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
||||
"Runner.rc"
|
||||
"runner.exe.manifest"
|
||||
)
|
||||
|
||||
# Apply the standard set of build settings. This can be removed for applications
|
||||
# that need different build settings.
|
||||
apply_standard_settings(${BINARY_NAME})
|
||||
|
||||
# Disable Windows macros that collide with C++ standard library functions.
|
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
|
||||
|
||||
# Add dependency libraries and include directories. Add any application-specific
|
||||
# dependencies here.
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
|
||||
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
# Run the Flutter tool portions of the build. This must not be removed.
|
||||
add_dependencies(${BINARY_NAME} flutter_assemble)
|
||||
|
|
|
@ -90,12 +90,12 @@ BEGIN
|
|||
BLOCK "040904e4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "chat.fluffy" "\0"
|
||||
VALUE "FileDescription", "A new Flutter project." "\0"
|
||||
VALUE "FileDescription", "fluffychat" "\0"
|
||||
VALUE "FileVersion", VERSION_AS_STRING "\0"
|
||||
VALUE "InternalName", "FluffyChat" "\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2020 chat.fluffy. All rights reserved." "\0"
|
||||
VALUE "InternalName", "fluffychat" "\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2022 chat.fluffy. All rights reserved." "\0"
|
||||
VALUE "OriginalFilename", "fluffychat.exe" "\0"
|
||||
VALUE "ProductName", "FluffyChat" "\0"
|
||||
VALUE "ProductName", "fluffychat" "\0"
|
||||
VALUE "ProductVersion", VERSION_AS_STRING "\0"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
|
||||
#include "flutter/generated_plugin_registrant.h"
|
||||
|
||||
FlutterWindow::FlutterWindow(RunLoop* run_loop,
|
||||
const flutter::DartProject& project)
|
||||
: run_loop_(run_loop), project_(project) {}
|
||||
FlutterWindow::FlutterWindow(const flutter::DartProject& project)
|
||||
: project_(project) {}
|
||||
|
||||
FlutterWindow::~FlutterWindow() {}
|
||||
|
||||
|
@ -26,14 +25,12 @@ bool FlutterWindow::OnCreate() {
|
|||
return false;
|
||||
}
|
||||
RegisterPlugins(flutter_controller_->engine());
|
||||
run_loop_->RegisterFlutterInstance(flutter_controller_->engine());
|
||||
SetChildContent(flutter_controller_->view()->GetNativeWindow());
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlutterWindow::OnDestroy() {
|
||||
if (flutter_controller_) {
|
||||
run_loop_->UnregisterFlutterInstance(flutter_controller_->engine());
|
||||
flutter_controller_ = nullptr;
|
||||
}
|
||||
|
||||
|
@ -44,7 +41,7 @@ LRESULT
|
|||
FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
|
||||
WPARAM const wparam,
|
||||
LPARAM const lparam) noexcept {
|
||||
// Give Flutter, including plugins, an opporutunity to handle window messages.
|
||||
// Give Flutter, including plugins, an opportunity to handle window messages.
|
||||
if (flutter_controller_) {
|
||||
std::optional<LRESULT> result =
|
||||
flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
|
||||
|
|
|
@ -6,16 +6,13 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "run_loop.h"
|
||||
#include "win32_window.h"
|
||||
|
||||
// A window that does nothing but host a Flutter view.
|
||||
class FlutterWindow : public Win32Window {
|
||||
public:
|
||||
// Creates a new FlutterWindow driven by the |run_loop|, hosting a
|
||||
// Flutter view running |project|.
|
||||
explicit FlutterWindow(RunLoop* run_loop,
|
||||
const flutter::DartProject& project);
|
||||
// Creates a new FlutterWindow hosting a Flutter view running |project|.
|
||||
explicit FlutterWindow(const flutter::DartProject& project);
|
||||
virtual ~FlutterWindow();
|
||||
|
||||
protected:
|
||||
|
@ -26,9 +23,6 @@ class FlutterWindow : public Win32Window {
|
|||
LPARAM const lparam) noexcept override;
|
||||
|
||||
private:
|
||||
// The run loop driving events for this window.
|
||||
RunLoop* run_loop_;
|
||||
|
||||
// The project to run.
|
||||
flutter::DartProject project_;
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include "flutter_window.h"
|
||||
#include "run_loop.h"
|
||||
#include "utils.h"
|
||||
|
||||
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
||||
|
@ -18,10 +17,14 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
|||
// plugins.
|
||||
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
|
||||
RunLoop run_loop;
|
||||
|
||||
flutter::DartProject project(L"data");
|
||||
FlutterWindow window(&run_loop, project);
|
||||
|
||||
std::vector<std::string> command_line_arguments =
|
||||
GetCommandLineArguments();
|
||||
|
||||
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
|
||||
|
||||
FlutterWindow window(project);
|
||||
Win32Window::Point origin(10, 10);
|
||||
Win32Window::Size size(1280, 720);
|
||||
if (!window.CreateAndShow(L"FluffyChat", origin, size)) {
|
||||
|
@ -29,7 +32,11 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
|||
}
|
||||
window.SetQuitOnClose(true);
|
||||
|
||||
run_loop.Run();
|
||||
::MSG msg;
|
||||
while (::GetMessage(&msg, nullptr, 0, 0)) {
|
||||
::TranslateMessage(&msg);
|
||||
::DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
::CoUninitialize();
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
#include "run_loop.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
RunLoop::RunLoop() {}
|
||||
|
||||
RunLoop::~RunLoop() {}
|
||||
|
||||
void RunLoop::Run() {
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, nullptr, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
void RunLoop::RegisterFlutterInstance(
|
||||
flutter::FlutterEngine* flutter_instance) {
|
||||
flutter_instances_.insert(flutter_instance);
|
||||
}
|
||||
|
||||
void RunLoop::UnregisterFlutterInstance(
|
||||
flutter::FlutterEngine* flutter_instance) {
|
||||
flutter_instances_.erase(flutter_instance);
|
||||
}
|
||||
|
||||
RunLoop::TimePoint RunLoop::ProcessFlutterMessages() {
|
||||
TimePoint next_event_time = TimePoint::max();
|
||||
for (auto instance : flutter_instances_) {
|
||||
std::chrono::nanoseconds wait_duration = instance->ProcessMessages();
|
||||
if (wait_duration != std::chrono::nanoseconds::max()) {
|
||||
next_event_time =
|
||||
std::min(next_event_time, TimePoint::clock::now() + wait_duration);
|
||||
}
|
||||
}
|
||||
return next_event_time;
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
#ifndef RUNNER_RUN_LOOP_H_
|
||||
#define RUNNER_RUN_LOOP_H_
|
||||
|
||||
#include <flutter/flutter_engine.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <set>
|
||||
|
||||
// A runloop that will service events for Flutter instances as well
|
||||
// as native messages.
|
||||
class RunLoop {
|
||||
public:
|
||||
RunLoop();
|
||||
~RunLoop();
|
||||
|
||||
// Prevent copying
|
||||
RunLoop(RunLoop const&) = delete;
|
||||
RunLoop& operator=(RunLoop const&) = delete;
|
||||
|
||||
// Runs the run loop until the application quits.
|
||||
void Run();
|
||||
|
||||
// Registers the given Flutter instance for event servicing.
|
||||
void RegisterFlutterInstance(
|
||||
flutter::FlutterEngine* flutter_instance);
|
||||
|
||||
// Unregisters the given Flutter instance from event servicing.
|
||||
void UnregisterFlutterInstance(
|
||||
flutter::FlutterEngine* flutter_instance);
|
||||
|
||||
private:
|
||||
using TimePoint = std::chrono::steady_clock::time_point;
|
||||
|
||||
// Processes all currently pending messages for registered Flutter instances.
|
||||
TimePoint ProcessFlutterMessages();
|
||||
|
||||
std::set<flutter::FlutterEngine*> flutter_instances_;
|
||||
};
|
||||
|
||||
#endif // RUNNER_RUN_LOOP_H_
|
|
@ -20,3 +20,45 @@ void CreateAndAttachConsole() {
|
|||
FlutterDesktopResyncOutputStreams();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> GetCommandLineArguments() {
|
||||
// Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
|
||||
int argc;
|
||||
wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
||||
if (argv == nullptr) {
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
std::vector<std::string> command_line_arguments;
|
||||
|
||||
// Skip the first argument as it's the binary name.
|
||||
for (int i = 1; i < argc; i++) {
|
||||
command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
|
||||
}
|
||||
|
||||
::LocalFree(argv);
|
||||
|
||||
return command_line_arguments;
|
||||
}
|
||||
|
||||
std::string Utf8FromUtf16(const wchar_t* utf16_string) {
|
||||
if (utf16_string == nullptr) {
|
||||
return std::string();
|
||||
}
|
||||
int target_length = ::WideCharToMultiByte(
|
||||
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
|
||||
-1, nullptr, 0, nullptr, nullptr);
|
||||
std::string utf8_string;
|
||||
if (target_length == 0 || target_length > utf8_string.max_size()) {
|
||||
return utf8_string;
|
||||
}
|
||||
utf8_string.resize(target_length);
|
||||
int converted_length = ::WideCharToMultiByte(
|
||||
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
|
||||
-1, utf8_string.data(),
|
||||
target_length, nullptr, nullptr);
|
||||
if (converted_length == 0) {
|
||||
return std::string();
|
||||
}
|
||||
return utf8_string;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
#ifndef RUNNER_UTILS_H_
|
||||
#define RUNNER_UTILS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Creates a console for the process, and redirects stdout and stderr to
|
||||
// it for both the runner and the Flutter library.
|
||||
void CreateAndAttachConsole();
|
||||
|
||||
// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
|
||||
// encoded in UTF-8. Returns an empty std::string on failure.
|
||||
std::string Utf8FromUtf16(const wchar_t* utf16_string);
|
||||
|
||||
// Gets the command line arguments passed in as a std::vector<std::string>,
|
||||
// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.
|
||||
std::vector<std::string> GetCommandLineArguments();
|
||||
|
||||
#endif // RUNNER_UTILS_H_
|
||||
|
|
|
@ -173,7 +173,7 @@ Win32Window::MessageHandler(HWND hwnd,
|
|||
|
||||
return 0;
|
||||
}
|
||||
case WM_SIZE:
|
||||
case WM_SIZE: {
|
||||
RECT rect = GetClientArea();
|
||||
if (child_content_ != nullptr) {
|
||||
// Size and position the child window.
|
||||
|
@ -181,6 +181,7 @@ Win32Window::MessageHandler(HWND hwnd,
|
|||
rect.bottom - rect.top, TRUE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_ACTIVATE:
|
||||
if (child_content_ != nullptr) {
|
||||
|
|
Loading…
Reference in a new issue