feat: implement retreiving widgets

- display a bottom sheet with widgets
- open widgets in a browser
- fixes in .gitignore
- Windows UWP build files

Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
This commit is contained in:
TheOneWithTheBraid 2022-02-02 14:31:15 +01:00
parent 159231a0f8
commit 60f6f15f2e
74 changed files with 1370 additions and 334 deletions

8
.gitignore vendored
View File

@ -55,4 +55,10 @@ android/keys.json
android/Gemfile.lock
lib/l10n_old
ios/Flutter/.last_build_id
ios/Podfile.lock
ios/Podfile.lock
/windows/out
/winuwp/out
/linux/out
/macos/out
.vs

10
.metadata Normal file
View File

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 657830b4c77aecfd0e32ec6504c859213dded97a
channel: master
project_type: app

View File

@ -2709,5 +2709,10 @@
"@iUnderstand": {},
"openChat": "Open Chat",
"markAsRead": "Mark as read",
"reportUser": "Report user"
"reportUser": "Report user",
"dismiss": "Dismiss",
"markAsRead": "Mark as read",
"matrixWidgets": "Matrix Widgets",
"integrationsNotImplemented": "Editing widgets and integrations is not possible yet.",
"editIntegrations": "Edit widgets and integrations"
}

View File

@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
@ -19,8 +20,10 @@ import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/chat/chat_view.dart';
import 'package:fluffychat/pages/chat/cupertino_widgets_bottom_sheet.dart';
import 'package:fluffychat/pages/chat/event_info_dialog.dart';
import 'package:fluffychat/pages/chat/recording_dialog.dart';
import 'package:fluffychat/pages/chat/widgets_bottom_sheet.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions.dart/event_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions.dart/ios_badge_client_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions.dart/matrix_locals.dart';
@ -63,7 +66,9 @@ class ChatController extends State<Chat> {
bool dragging = false;
void onDragEntered(_) => setState(() => dragging = true);
void onDragExited(_) => setState(() => dragging = false);
void onDragDone(DropDoneDetails details) async {
setState(() => dragging = false);
for (final xfile in details.files) {
@ -563,6 +568,17 @@ class ChatController extends State<Chat> {
.any((cl) => selectedEvents.first.senderId == cl!.userID);
}
void showWidgetsSheet() => [TargetPlatform.iOS, TargetPlatform.macOS]
.contains(Theme.of(context).platform)
? showCupertinoModalPopup(
context: context,
builder: (context) => CupertinoWidgetsBottomSheet(room: room!),
)
: showModalBottomSheet(
context: context,
builder: (context) => WidgetsBottomSheet(room: room!),
);
void forwardEventsAction() async {
if (selectedEvents.length == 1) {
Matrix.of(context).shareContent = selectedEvents.first.content;

View File

@ -36,77 +36,87 @@ class ChatView extends StatelessWidget {
const ChatView(this.controller, {Key? key}) : super(key: key);
List<Widget> _appBarActions(BuildContext context) => controller.selectMode
? [
if (controller.canEditSelectedEvents)
IconButton(
icon: const Icon(Icons.edit_outlined),
tooltip: L10n.of(context)!.edit,
onPressed: controller.editSelectedEventAction,
),
List<Widget> _appBarActions(BuildContext context) {
if (controller.selectMode) {
return [
if (controller.canEditSelectedEvents)
IconButton(
icon: const Icon(Icons.copy_outlined),
tooltip: L10n.of(context)!.copy,
onPressed: controller.copyEventsAction,
icon: const Icon(Icons.edit_outlined),
tooltip: L10n.of(context)!.edit,
onPressed: controller.editSelectedEventAction,
),
if (controller.canSaveSelectedEvent)
IconButton(
icon: Icon(Icons.adaptive.share),
tooltip: L10n.of(context)!.share,
onPressed: controller.saveSelectedEvent,
),
if (controller.canRedactSelectedEvents)
IconButton(
icon: const Icon(Icons.delete_outlined),
tooltip: L10n.of(context)!.redactMessage,
onPressed: controller.redactEventsAction,
),
if (controller.selectedEvents.length == 1)
PopupMenuButton<_EventContextAction>(
onSelected: (action) {
switch (action) {
case _EventContextAction.info:
controller.showEventInfo();
controller.clearSelectedEvents();
break;
case _EventContextAction.report:
controller.reportEventAction();
break;
}
},
itemBuilder: (context) => [
PopupMenuItem(
value: _EventContextAction.info,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.info_outlined),
const SizedBox(width: 12),
Text(L10n.of(context)!.messageInfo),
],
),
IconButton(
icon: const Icon(Icons.copy_outlined),
tooltip: L10n.of(context)!.copy,
onPressed: controller.copyEventsAction,
),
if (controller.canSaveSelectedEvent)
IconButton(
icon: Icon(Icons.adaptive.share),
tooltip: L10n.of(context)!.share,
onPressed: controller.saveSelectedEvent,
),
if (controller.canRedactSelectedEvents)
IconButton(
icon: const Icon(Icons.delete_outlined),
tooltip: L10n.of(context)!.redactMessage,
onPressed: controller.redactEventsAction,
),
if (controller.selectedEvents.length == 1)
PopupMenuButton<_EventContextAction>(
onSelected: (action) {
switch (action) {
case _EventContextAction.info:
controller.showEventInfo();
controller.clearSelectedEvents();
break;
case _EventContextAction.report:
controller.reportEventAction();
break;
}
},
itemBuilder: (context) => [
PopupMenuItem(
value: _EventContextAction.info,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.info_outlined),
const SizedBox(width: 12),
Text(L10n.of(context)!.messageInfo),
],
),
PopupMenuItem(
value: _EventContextAction.report,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.shield_outlined,
color: Colors.red,
),
const SizedBox(width: 12),
Text(L10n.of(context)!.reportMessage),
],
),
),
PopupMenuItem(
value: _EventContextAction.report,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.shield_outlined,
color: Colors.red,
),
const SizedBox(width: 12),
Text(L10n.of(context)!.reportMessage),
],
),
],
),
]
: [
ChatSettingsPopupMenu(
controller.room!, !controller.room!.isDirectChat),
];
),
],
),
];
} else {
final widgets = controller.room?.widgets ?? [];
return [
if (widgets.isNotEmpty)
IconButton(
onPressed: controller.showWidgetsSheet,
icon: const Icon(Icons.widgets),
tooltip: L10n.of(context)!.matrixWidgets,
),
ChatSettingsPopupMenu(controller.room!, !controller.room!.isDirectChat),
];
}
}
@override
Widget build(BuildContext context) {
@ -142,271 +152,291 @@ class ChatView extends StatelessWidget {
child: StreamBuilder(
stream: controller.room!.onUpdate.stream
.rateLimit(const Duration(milliseconds: 250)),
builder: (context, snapshot) => Scaffold(
appBar: AppBar(
actionsIconTheme: IconThemeData(
color: controller.selectedEvents.isEmpty
? null
: Theme.of(context).colorScheme.primary,
),
leading: controller.selectMode
? IconButton(
icon: const Icon(Icons.close),
onPressed: controller.clearSelectedEvents,
tooltip: L10n.of(context)!.close,
color: Theme.of(context).colorScheme.primary,
)
: UnreadBadgeBackButton(roomId: controller.roomId!),
titleSpacing: 0,
title: ChatAppBarTitle(controller),
actions: _appBarActions(context),
),
floatingActionButton: controller.showScrollDownButton &&
controller.selectedEvents.isEmpty
? Padding(
padding: const EdgeInsets.only(bottom: 56.0),
child: FloatingActionButton(
onPressed: controller.scrollDown,
foregroundColor:
Theme.of(context).textTheme.bodyText2!.color,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
mini: true,
child: Icon(Icons.arrow_downward_outlined,
color: Theme.of(context).primaryColor),
),
)
: null,
backgroundColor: Theme.of(context).colorScheme.surface,
body: DropTarget(
onDragDone: controller.onDragDone,
onDragEntered: controller.onDragEntered,
onDragExited: controller.onDragExited,
child: Stack(
children: <Widget>[
if (Matrix.of(context).wallpaper != null)
Image.file(
Matrix.of(context).wallpaper!,
width: double.infinity,
height: double.infinity,
fit: BoxFit.cover,
),
SafeArea(
child: Column(
children: <Widget>[
TombstoneDisplay(controller),
Expanded(
child: GestureDetector(
onTap: controller.clearSingleSelectedEvent,
child: FutureBuilder<bool>(
future: controller.getTimeline(),
builder: (BuildContext context, snapshot) {
if (snapshot.hasError) {
SentryController.captureException(
snapshot.error,
StackTrace.current,
);
}
if (controller.timeline == null) {
return const Center(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2),
);
}
// create a map of eventId --> index to greatly improve performance of
// ListView's findChildIndexCallback
final thisEventsKeyMap = <String, int>{};
for (var i = 0;
i < controller.filteredEvents.length;
i++) {
thisEventsKeyMap[
controller.filteredEvents[i].eventId] = i;
}
return ListView.custom(
padding: EdgeInsets.only(
top: 16,
bottom: 4,
left: horizontalPadding,
right: horizontalPadding,
),
reverse: true,
controller: controller.scrollController,
keyboardDismissBehavior: PlatformInfos.isIOS
? ScrollViewKeyboardDismissBehavior.onDrag
: ScrollViewKeyboardDismissBehavior
.manual,
childrenDelegate: SliverChildBuilderDelegate(
(BuildContext context, int i) {
return i ==
controller.filteredEvents.length +
1
? controller
.timeline!.isRequestingHistory
? const Center(
child:
CircularProgressIndicator
.adaptive(
strokeWidth: 2),
)
: controller.canLoadMore
? Center(
child: OutlinedButton(
style: OutlinedButton
.styleFrom(
backgroundColor: Theme
.of(context)
.scaffoldBackgroundColor,
),
onPressed: controller
.requestHistory,
child: Text(
L10n.of(context)!
.loadMore),
),
)
: Container()
: i == 0
? Column(
mainAxisSize:
MainAxisSize.min,
children: [
SeenByRow(controller),
TypingIndicators(
controller),
],
)
: AutoScrollTag(
key: ValueKey(controller
.filteredEvents[i - 1]
.eventId),
index: i - 1,
controller: controller
.scrollController,
child: Swipeable(
key: ValueKey(controller
.filteredEvents[i - 1]
.eventId),
background: const Padding(
padding:
EdgeInsets.symmetric(
horizontal: 12.0),
child: Center(
child: Icon(Icons
.reply_outlined),
),
),
direction: SwipeDirection
.endToStart,
onSwipe: (direction) =>
controller.replyAction(
replyTo: controller
.filteredEvents[
i - 1]),
child: Message(
controller.filteredEvents[
i - 1],
onInfoTab: controller
.showEventInfo,
onAvatarTab: (Event event) =>
showModalBottomSheet(
context: context,
builder: (c) =>
UserBottomSheet(
user: event
.sender,
outerContext:
context,
onMention: () => controller
.sendController
.text +=
'${event.sender.mention} ',
),
),
unfold:
controller.unfold,
onSelect: controller
.onSelectMessage,
scrollToEventId:
(String eventId) =>
controller
.scrollToEventId(
eventId),
longPressSelect:
controller
.selectedEvents
.isEmpty,
selected: controller
.selectedEvents
.any((e) => e.eventId == controller.filteredEvents[i - 1].eventId),
timeline: controller.timeline!,
nextEvent: i < controller.filteredEvents.length ? controller.filteredEvents[i] : null),
),
);
},
childCount:
controller.filteredEvents.length + 2,
findChildIndexCallback: (key) =>
controller.findChildIndexCallback(
key, thisEventsKeyMap),
),
);
},
)),
),
if (controller.room!.canSendDefaultMessages &&
controller.room!.membership == Membership.join)
Container(
margin: EdgeInsets.only(
bottom: bottomSheetPadding,
left: bottomSheetPadding,
right: bottomSheetPadding,
),
constraints: const BoxConstraints(
maxWidth: FluffyThemes.columnWidth * 2.5),
alignment: Alignment.center,
child: Material(
borderRadius: const BorderRadius.only(
bottomLeft:
Radius.circular(AppConfig.borderRadius),
bottomRight:
Radius.circular(AppConfig.borderRadius),
),
elevation: 6,
shadowColor: Theme.of(context)
.secondaryHeaderColor
.withAlpha(100),
clipBehavior: Clip.hardEdge,
color:
Theme.of(context).appBarTheme.backgroundColor,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const ConnectionStatusHeader(),
ReactionsPicker(controller),
ReplyDisplay(controller),
ChatInputRow(controller),
ChatEmojiPicker(controller),
],
),
),
),
],
),
builder: (context, snapshot) => FutureBuilder<bool>(
future: controller.getTimeline(),
builder: (BuildContext context, snapshot) {
return Scaffold(
appBar: AppBar(
actionsIconTheme: IconThemeData(
color: controller.selectedEvents.isEmpty
? null
: Theme.of(context).colorScheme.primary,
),
if (controller.dragging)
Container(
color: Theme.of(context)
.scaffoldBackgroundColor
.withOpacity(0.9),
alignment: Alignment.center,
child: const Icon(
Icons.upload_outlined,
size: 100,
leading: controller.selectMode
? IconButton(
icon: const Icon(Icons.close),
onPressed: controller.clearSelectedEvents,
tooltip: L10n.of(context)!.close,
color: Theme.of(context).colorScheme.primary,
)
: UnreadBadgeBackButton(roomId: controller.roomId!),
titleSpacing: 0,
title: ChatAppBarTitle(controller),
actions: _appBarActions(context),
),
floatingActionButton: controller.showScrollDownButton &&
controller.selectedEvents.isEmpty
? Padding(
padding: const EdgeInsets.only(bottom: 56.0),
child: FloatingActionButton(
onPressed: controller.scrollDown,
foregroundColor:
Theme.of(context).textTheme.bodyText2!.color,
backgroundColor:
Theme.of(context).scaffoldBackgroundColor,
mini: true,
child: Icon(Icons.arrow_downward_outlined,
color: Theme.of(context).primaryColor),
),
)
: null,
backgroundColor: Theme.of(context).colorScheme.surface,
body: DropTarget(
onDragDone: controller.onDragDone,
onDragEntered: controller.onDragEntered,
onDragExited: controller.onDragExited,
child: Stack(
children: <Widget>[
if (Matrix.of(context).wallpaper != null)
Image.file(
Matrix.of(context).wallpaper!,
width: double.infinity,
height: double.infinity,
fit: BoxFit.cover,
),
SafeArea(
child: Column(
children: <Widget>[
TombstoneDisplay(controller),
Expanded(
child: GestureDetector(
onTap: controller.clearSingleSelectedEvent,
child: Builder(
builder: (context) {
if (snapshot.hasError) {
SentryController.captureException(
snapshot.error,
StackTrace.current,
);
}
if (controller.timeline == null) {
return const Center(
child:
CircularProgressIndicator.adaptive(
strokeWidth: 2),
);
}
// create a map of eventId --> index to greatly improve performance of
// ListView's findChildIndexCallback
final thisEventsKeyMap = <String, int>{};
for (var i = 0;
i < controller.filteredEvents.length;
i++) {
thisEventsKeyMap[controller
.filteredEvents[i].eventId] = i;
}
return ListView.custom(
padding: EdgeInsets.only(
top: 16,
bottom: 4,
left: horizontalPadding,
right: horizontalPadding,
),
reverse: true,
controller: controller.scrollController,
keyboardDismissBehavior: PlatformInfos
.isIOS
? ScrollViewKeyboardDismissBehavior
.onDrag
: ScrollViewKeyboardDismissBehavior
.manual,
childrenDelegate:
SliverChildBuilderDelegate(
(BuildContext context, int i) {
return i ==
controller.filteredEvents
.length +
1
? controller.timeline!
.isRequestingHistory
? const Center(
child:
CircularProgressIndicator
.adaptive(
strokeWidth:
2),
)
: controller.canLoadMore
? Center(
child: OutlinedButton(
style:
OutlinedButton
.styleFrom(
backgroundColor:
Theme.of(
context)
.scaffoldBackgroundColor,
),
onPressed: controller
.requestHistory,
child: Text(L10n.of(
context)!
.loadMore),
),
)
: Container()
: i == 0
? Column(
mainAxisSize:
MainAxisSize.min,
children: [
SeenByRow(controller),
TypingIndicators(
controller),
],
)
: AutoScrollTag(
key: ValueKey(controller
.filteredEvents[i - 1]
.eventId),
index: i - 1,
controller: controller
.scrollController,
child: Swipeable(
key: ValueKey(controller
.filteredEvents[
i - 1]
.eventId),
background:
const Padding(
padding: EdgeInsets
.symmetric(
horizontal:
12.0),
child: Center(
child: Icon(Icons
.reply_outlined),
),
),
direction:
SwipeDirection
.endToStart,
onSwipe: (direction) =>
controller.replyAction(
replyTo: controller
.filteredEvents[
i - 1]),
child: Message(
controller.filteredEvents[
i - 1],
onInfoTab: controller
.showEventInfo,
onAvatarTab:
(Event event) =>
showModalBottomSheet(
context:
context,
builder:
(c) =>
UserBottomSheet(
user: event
.sender,
outerContext:
context,
onMention: () => controller
.sendController
.text += '${event.sender.mention} ',
),
),
unfold: controller
.unfold,
onSelect: controller
.onSelectMessage,
scrollToEventId:
(String eventId) =>
controller.scrollToEventId(
eventId),
longPressSelect:
controller
.selectedEvents
.isEmpty,
selected: controller
.selectedEvents
.any((e) => e.eventId == controller.filteredEvents[i - 1].eventId),
timeline: controller.timeline!,
nextEvent: i < controller.filteredEvents.length ? controller.filteredEvents[i] : null),
),
);
},
childCount:
controller.filteredEvents.length +
2,
findChildIndexCallback: (key) =>
controller.findChildIndexCallback(
key, thisEventsKeyMap),
),
);
},
)),
),
if (controller.room!.canSendDefaultMessages &&
controller.room!.membership == Membership.join)
Container(
margin: EdgeInsets.only(
bottom: bottomSheetPadding,
left: bottomSheetPadding,
right: bottomSheetPadding,
),
constraints: const BoxConstraints(
maxWidth: FluffyThemes.columnWidth * 2.5),
alignment: Alignment.center,
child: Material(
borderRadius: const BorderRadius.only(
bottomLeft:
Radius.circular(AppConfig.borderRadius),
bottomRight:
Radius.circular(AppConfig.borderRadius),
),
elevation: 6,
shadowColor: Theme.of(context)
.secondaryHeaderColor
.withAlpha(100),
clipBehavior: Clip.hardEdge,
color: Theme.of(context)
.appBarTheme
.backgroundColor,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const ConnectionStatusHeader(),
ReactionsPicker(controller),
ReplyDisplay(controller),
ChatInputRow(controller),
ChatEmojiPicker(controller),
],
),
),
),
],
),
),
),
],
),
),
if (controller.dragging)
Container(
color: Theme.of(context)
.scaffoldBackgroundColor
.withOpacity(0.9),
alignment: Alignment.center,
child: const Icon(
Icons.upload_outlined,
size: 100,
),
),
],
),
),
);
},
),
),
);

View File

@ -0,0 +1,40 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:url_launcher/link.dart';
class CupertinoWidgetsBottomSheet extends StatelessWidget {
final Room room;
const CupertinoWidgetsBottomSheet({Key? key, required this.room})
: super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoActionSheet(
title: Text(L10n.of(context)!.matrixWidgets),
actions: [
...room.widgets.map(
(widget) => Link(
builder: (context, callback) {
return CupertinoActionSheetAction(
child: Text(widget.name),
onPressed: callback ?? () {},
);
},
target: LinkTarget.blank,
uri: Uri.parse(widget.url),
),
),
CupertinoActionSheetAction(
child: Text(L10n.of(context)!.integrationsNotImplemented),
onPressed: () {},
),
CupertinoActionSheetAction(
child: Text(L10n.of(context)!.cancel),
onPressed: Navigator.of(context).pop,
),
],
);
}
}

View File

@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:url_launcher/link.dart';
class WidgetsBottomSheet extends StatelessWidget {
final Room room;
const WidgetsBottomSheet({Key? key, required this.room}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) {
if (index == room.widgets.length) {
return ListTile(
title: Text(L10n.of(context)!.integrationsNotImplemented),
leading: const Icon(Icons.info),
);
}
final widget = room.widgets[index];
return Link(
builder: (context, callback) {
return ListTile(
title: Text(widget.name),
subtitle: Text(widget.type),
onTap: callback,
);
},
target: LinkTarget.blank,
uri: Uri.parse(widget.url),
);
},
itemCount: room.widgets.length + 1,
);
}
}

View File

@ -17,6 +17,7 @@ import path_provider_macos
import shared_preferences_macos
import sqflite
import url_launcher_macos
import video_compress
import wakelock_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
@ -32,5 +33,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
VideoCompressPlugin.register(with: registry.registrar(forPlugin: "VideoCompressPlugin"))
WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin"))
}

View File

@ -1572,7 +1572,7 @@ packages:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
version: "2.0.6"
url_launcher_windows:
dependency: transitive
description:
@ -1757,4 +1757,4 @@ packages:
version: "3.1.0"
sdks:
dart: ">=2.15.1 <3.0.0"
flutter: ">=2.10.0"
flutter: ">=2.8.0"

View File

@ -91,6 +91,7 @@ add_custom_command(
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
windows-x64 $<CONFIG>
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"

View File

@ -9,6 +9,9 @@ list(APPEND FLUTTER_PLUGIN_LIST
url_launcher_windows
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@ -17,3 +20,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)

17
winuwp/.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
flutter/ephemeral/
# Visual Studio user-specific files.
*.suo
*.user
*.userosscache
*.sln.docstates
# Visual Studio build-related files.
x64/
x86/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

64
winuwp/CMakeLists.txt Normal file
View File

@ -0,0 +1,64 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.8)
set(CMAKE_SYSTEM_NAME WindowsStore)
set(CMAKE_SYSTEM_VERSION 10.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
project(fluffychat LANGUAGES CXX)
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(SET CMP0079 NEW)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "fluffychat")
# Define build configuration options.
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(IS_MULTICONFIG)
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
CACHE STRING "" FORCE)
else()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"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}")
set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
# Use Unicode for all projects.
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" /await)
target_compile_options(${TARGET} PRIVATE /EHsc)
target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
target_compile_definitions(${TARGET} PRIVATE WINUWP)
set_target_properties(${TARGET} PROPERTIES VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION 10.0.18362.0)
endfunction()
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
# Flutter library and tool build rules.
add_subdirectory(${FLUTTER_MANAGED_DIR})
# Application build; see runner/CMakeLists.txt.
add_subdirectory("runner_uwp")
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)

View File

@ -0,0 +1,92 @@
# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.8)
set(CMAKE_SYSTEM_NAME WindowsStore)
set(CMAKE_SYSTEM_VERSION 10.0)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
include(CMakePrintHelpers)
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
# === Flutter Library ===
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows_winuwp.dll")
# === Assets ===
set(CMAKE_INSTALL_MANIFEST "${EPHEMERAL_DIR}/install_manifest")
file(STRINGS ${CMAKE_INSTALL_MANIFEST} INSTALL_MANIFEST_CONTENT)
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(INSTALL_MANIFEST_CONTENT ${INSTALL_MANIFEST_CONTENT} PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"flutter_export.h"
"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)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
add_dependencies(flutter flutter_assemble)
# === Wrapper ===
list(APPEND CPP_WRAPPER_SOURCES_CORE
"core_implementations.cc"
"standard_codec.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
"plugin_registrar.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_APP
"flutter_engine.cc"
"flutter_view_controller.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
# Wrapper sources needed for a plugin.
add_library(flutter_wrapper_plugin STATIC
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN}
)
apply_standard_settings(flutter_wrapper_plugin)
set_target_properties(flutter_wrapper_plugin PROPERTIES
POSITION_INDEPENDENT_CODE ON)
set_target_properties(flutter_wrapper_plugin PROPERTIES
CXX_VISIBILITY_PRESET hidden)
target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
target_include_directories(flutter_wrapper_plugin PUBLIC
"${WRAPPER_ROOT}/include"
)
add_dependencies(flutter_wrapper_plugin flutter_assemble)
# Wrapper sources needed for the runner.
add_library(flutter_wrapper_app STATIC
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_APP}
)
apply_standard_settings(flutter_wrapper_app)
target_link_libraries(flutter_wrapper_app PUBLIC flutter)
target_include_directories(flutter_wrapper_app PUBLIC
"${WRAPPER_ROOT}/include"
)
add_dependencies(flutter_wrapper_app flutter_assemble)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP}
)

View File

@ -0,0 +1,270 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_PUBLIC_FLUTTER_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_PUBLIC_FLUTTER_H_
#include <stddef.h>
#include <stdint.h>
#include <windows.h>
#include "flutter_export.h"
#include "flutter_messenger.h"
#include "flutter_plugin_registrar.h"
#ifdef WINUWP
#include <windows.applicationmodel.activation.h>
#include <windows.ui.core.h>
#endif
#if defined(__cplusplus)
extern "C" {
#endif
// Opaque reference to a Flutter window controller.
typedef struct FlutterDesktopViewControllerState*
FlutterDesktopViewControllerRef;
// Opaque reference to a Flutter window.
struct FlutterDesktopView;
typedef struct FlutterDesktopView* FlutterDesktopViewRef;
// Opaque reference to a Flutter engine instance.
struct FlutterDesktopEngine;
typedef struct FlutterDesktopEngine* FlutterDesktopEngineRef;
// Properties for configuring a Flutter engine instance.
typedef struct {
// The path to the flutter_assets folder for the application to be run.
// This can either be an absolute path or a path relative to the directory
// containing the executable.
const wchar_t* assets_path;
// The path to the icudtl.dat file for the version of Flutter you are using.
// This can either be an absolute path or a path relative to the directory
// containing the executable.
const wchar_t* icu_data_path;
// The path to the AOT library file for your application, if any.
// This can either be an absolute path or a path relative to the directory
// containing the executable. This can be nullptr for a non-AOT build, as
// it will be ignored in that case.
const wchar_t* aot_library_path;
// Number of elements in the array passed in as dart_entrypoint_argv.
int dart_entrypoint_argc;
// Array of Dart entrypoint arguments. This is deep copied during the call
// to FlutterDesktopEngineCreate.
const char** dart_entrypoint_argv;
} FlutterDesktopEngineProperties;
// ========== View Controller ==========
// Creates a view that hosts and displays the given engine instance.
//
// This takes ownership of |engine|, so FlutterDesktopEngineDestroy should no
// longer be called on it, as it will be called internally when the view
// controller is destroyed. If creating the view controller fails, the engine
// will be destroyed immediately.
//
// If |engine| is not already running, the view controller will start running
// it automatically before displaying the window.
//
// The caller owns the returned reference, and is responsible for calling
// FlutterDesktopViewControllerDestroy. Returns a null pointer in the event of
// an error.
#ifdef WINUWP
// The CoreApplicationView implementation accepts a pointer to the host
// CoreApplicationView and view hookup is performed in the construction path.
FLUTTER_EXPORT FlutterDesktopViewControllerRef
FlutterDesktopViewControllerCreateFromCoreApplicationView(
ABI::Windows::ApplicationModel::Core::CoreApplicationView* window,
ABI::Windows::ApplicationModel::Activation::IActivatedEventArgs* args,
FlutterDesktopEngineRef engine);
#else //! WINUWP
// The Win32 implementation accepts width, height
// with view hookup explicitly performed using the caller using HWND parenting.
FLUTTER_EXPORT FlutterDesktopViewControllerRef
FlutterDesktopViewControllerCreate(int width,
int height,
FlutterDesktopEngineRef engine);
#endif
// Shuts down the engine instance associated with |controller|, and cleans up
// associated state.
//
// |controller| is no longer valid after this call.
FLUTTER_EXPORT void FlutterDesktopViewControllerDestroy(
FlutterDesktopViewControllerRef controller);
// Returns the handle for the engine running in FlutterDesktopViewControllerRef.
//
// Its lifetime is the same as the |controller|'s.
FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine(
FlutterDesktopViewControllerRef controller);
// Returns the view managed by the given controller.
FLUTTER_EXPORT FlutterDesktopViewRef
FlutterDesktopViewControllerGetView(FlutterDesktopViewControllerRef controller);
// Requests new frame from engine and repaints the view
FLUTTER_EXPORT void FlutterDesktopViewControllerForceRedraw(
FlutterDesktopViewControllerRef controller);
#ifndef WINUWP
// Allows the Flutter engine and any interested plugins an opportunity to
// handle the given message.
//
// If the WindowProc was handled and further handling should stop, this returns
// true and |result| will be populated. |result| is not set if returning false.
FLUTTER_EXPORT bool FlutterDesktopViewControllerHandleTopLevelWindowProc(
FlutterDesktopViewControllerRef controller,
HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam,
LRESULT* result);
#endif
// ========== Engine ==========
// Creates a Flutter engine with the given properties.
//
// The caller owns the returned reference, and is responsible for calling
// FlutterDesktopEngineDestroy. The lifetime of |engine_properties| is required
// to extend only until the end of this call.
FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopEngineCreate(
const FlutterDesktopEngineProperties* engine_properties);
// Shuts down and destroys the given engine instance. Returns true if the
// shutdown was successful, or if the engine was not running.
//
// |engine| is no longer valid after this call.
FLUTTER_EXPORT bool FlutterDesktopEngineDestroy(FlutterDesktopEngineRef engine);
// Starts running the given engine instance and optional entry point in the Dart
// project. If the entry point is null, defaults to main().
//
// If provided, entry_point must be the name of a top-level function from the
// same Dart library that contains the app's main() function, and must be
// decorated with `@pragma(vm:entry-point)` to ensure the method is not
// tree-shaken by the Dart compiler.
//
// Returns false if running the engine failed.
FLUTTER_EXPORT bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine,
const char* entry_point);
#ifndef WINUWP
// DEPRECATED: This is no longer necessary to call, Flutter will take care of
// processing engine messages transparently through DispatchMessage.
//
// Processes any pending events in the Flutter engine, and returns the
// number of nanoseconds until the next scheduled event (or max, if none).
//
// This should be called on every run of the application-level runloop, and
// a wait for native events in the runloop should never be longer than the
// last return value from this function.
FLUTTER_EXPORT uint64_t
FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine);
#endif
FLUTTER_EXPORT void FlutterDesktopEngineReloadSystemFonts(
FlutterDesktopEngineRef engine);
FLUTTER_EXPORT void FlutterDesktopEngineReloadPlatformBrightness(
FlutterDesktopEngineRef engine);
// Returns the plugin registrar handle for the plugin with the given name.
//
// The name must be unique across the application.
FLUTTER_EXPORT FlutterDesktopPluginRegistrarRef
FlutterDesktopEngineGetPluginRegistrar(FlutterDesktopEngineRef engine,
const char* plugin_name);
// Returns the messenger associated with the engine.
FLUTTER_EXPORT FlutterDesktopMessengerRef
FlutterDesktopEngineGetMessenger(FlutterDesktopEngineRef engine);
// Returns the texture registrar associated with the engine.
FLUTTER_EXPORT FlutterDesktopTextureRegistrarRef
FlutterDesktopEngineGetTextureRegistrar(
FlutterDesktopTextureRegistrarRef texture_registrar);
// ========== View ==========
#ifdef WINUWP
// Return backing CoreApplicationView for manipulation of CoreWindow and
// CoreTitleBar in host application.
FLUTTER_EXPORT ABI::Windows::ApplicationModel::Core::CoreApplicationView*
FlutterDesktopViewGetCoreApplicationView(FlutterDesktopViewRef view);
#else
// Return backing HWND for manipulation in host application.
FLUTTER_EXPORT HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view);
#endif
// ========== Plugin Registrar (extensions) ==========
// These are Windows-specific extensions to flutter_plugin_registrar.h
// Function pointer type for top level WindowProc delegate registration.
//
// The user data will be whatever was passed to
// FlutterDesktopRegisterTopLevelWindowProcHandler.
//
// Implementations should populate |result| and return true if the WindowProc
// was handled and further handling should stop. |result| is ignored if the
// function returns false.
typedef bool (*FlutterDesktopWindowProcCallback)(HWND /* hwnd */,
UINT /* uMsg */,
WPARAM /*wParam*/,
LPARAM /* lParam*/,
void* /* user data */,
LRESULT* result);
// Returns the view associated with this registrar's engine instance.
FLUTTER_EXPORT FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView(
FlutterDesktopPluginRegistrarRef registrar);
#ifndef WINUWP
FLUTTER_EXPORT void
FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate(
FlutterDesktopPluginRegistrarRef registrar,
FlutterDesktopWindowProcCallback delegate,
void* user_data);
FLUTTER_EXPORT void
FlutterDesktopPluginRegistrarUnregisterTopLevelWindowProcDelegate(
FlutterDesktopPluginRegistrarRef registrar,
FlutterDesktopWindowProcCallback delegate);
#endif
// ========== Freestanding Utilities ==========
// Gets the DPI for a given |hwnd|, depending on the supported APIs per
// windows version and DPI awareness mode. If nullptr is passed, returns the DPI
// of the primary monitor.
//
// This uses the same logic and fallback for older Windows versions that is used
// internally by Flutter to determine the DPI to use for displaying Flutter
// content, so should be used by any code (e.g., in plugins) that translates
// between Windows and Dart sizes/offsets.
FLUTTER_EXPORT UINT FlutterDesktopGetDpiForHWND(HWND hwnd);
// Gets the DPI for a given |monitor|. If the API is not available, a default
// DPI of 96 is returned.
//
// See FlutterDesktopGetDpiForHWND for more information.
FLUTTER_EXPORT UINT FlutterDesktopGetDpiForMonitor(HMONITOR monitor);
// Reopens stdout and stderr and resysncs the standard library output streams.
// Should be called if output is being directed somewhere in the runner process
// (e.g., after an AllocConsole call).
FLUTTER_EXPORT void FlutterDesktopResyncOutputStreams();
#if defined(__cplusplus)
} // extern "C"
#endif
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_PUBLIC_FLUTTER_WINDOWS_H_

View File

@ -0,0 +1,11 @@
//
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
void RegisterPlugins(flutter::PluginRegistry* registry) {
}

View File

@ -0,0 +1,15 @@
//
// Generated file. Do not edit.
//
// clang-format off
#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_

View File

@ -0,0 +1,15 @@
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)

1
winuwp/project_version Normal file
View File

@ -0,0 +1 @@
0

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,141 @@
cmake_minimum_required (VERSION 3.8)
set(CMAKE_SYSTEM_NAME WindowsStore)
set(CMAKE_SYSTEM_VERSION 10.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
include(CMakePrintHelpers)
project (runner LANGUAGES CXX)
# UWP tile and icon assets.
set(ASSET_FILES ${ASSET_FILES}
Assets/LargeTile.scale-100.png
Assets/LargeTile.scale-125.png
Assets/LargeTile.scale-150.png
Assets/LargeTile.scale-200.png
Assets/LargeTile.scale-400.png
Assets/LockScreenLogo.scale-200.png
Assets/SmallTile.scale-100.png
Assets/SmallTile.scale-125.png
Assets/SmallTile.scale-150.png
Assets/SmallTile.scale-200.png
Assets/SmallTile.scale-400.png
Assets/SplashScreen.scale-100.png
Assets/SplashScreen.scale-125.png
Assets/SplashScreen.scale-150.png
Assets/SplashScreen.scale-200.png
Assets/SplashScreen.scale-400.png
Assets/Square44x44Logo.altform-unplated_targetsize-16.png
Assets/Square44x44Logo.altform-unplated_targetsize-32.png
Assets/Square44x44Logo.altform-unplated_targetsize-48.png
Assets/Square44x44Logo.altform-unplated_targetsize-256.png
Assets/Square44x44Logo.scale-100.png
Assets/Square44x44Logo.scale-125.png
Assets/Square44x44Logo.scale-150.png
Assets/Square44x44Logo.scale-200.png
Assets/Square44x44Logo.scale-400.png
Assets/Square44x44Logo.targetsize-16.png
Assets/Square44x44Logo.targetsize-24.png
Assets/Square44x44Logo.targetsize-24_altform-unplated.png
Assets/Square44x44Logo.targetsize-32.png
Assets/Square44x44Logo.targetsize-48.png
Assets/Square44x44Logo.targetsize-256.png
Assets/Square150x150Logo.scale-100.png
Assets/Square150x150Logo.scale-125.png
Assets/Square150x150Logo.scale-150.png
Assets/Square150x150Logo.scale-200.png
Assets/Square150x150Logo.scale-400.png
Assets/StoreLogo.png
Assets/StoreLogo.scale-100.png
Assets/StoreLogo.scale-125.png
Assets/StoreLogo.scale-150.png
Assets/StoreLogo.scale-200.png
Assets/StoreLogo.scale-400.png
Assets/Wide310x150Logo.scale-200.png
Assets/WideTile.scale-100.png
Assets/WideTile.scale-125.png
Assets/WideTile.scale-150.png
Assets/WideTile.scale-200.png
Assets/WideTile.scale-400.png
)
# Configure package manifest file.
set(APP_MANIFEST_NAME Package.appxmanifest)
set(APP_MANIFEST_TARGET_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${APP_MANIFEST_NAME})
set(SHORT_NAME ${BINARY_NAME})
set(PACKAGE_GUID "086F9B60-CB52-4D0B-9B4E-AE891E7859D1")
configure_file(
appxmanifest.in
${APP_MANIFEST_TARGET_LOCATION}
@ONLY)
set(CONTENT_FILES ${APP_MANIFEST_TARGET_LOCATION})
# Configure package content files.
set_property(SOURCE ${CONTENT_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1)
set(RESOURCE_FILES ${ASSET_FILES} ${CONTENT_FILES} Windows_TemporaryKey.pfx)
set_property(SOURCE ${ASSET_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1)
set_property(SOURCE ${ASSET_FILES} PROPERTY VS_DEPLOYMENT_LOCATION "Assets")
set(STRING_FILES Resources.pri)
set_property(SOURCE ${STRING_FILES} PROPERTY VS_TOOL_OVERRIDE "PRIResource")
source_group("Resource Files" FILES ${RESOURCE_FILES} ${CONTENT_FILES} ${STRING_FILES})
# Configure Flutter assets using tool generated install manifest
foreach(ITEM ${INSTALL_MANIFEST_CONTENT})
get_filename_component(ITEM_REL ${CMAKE_BINARY_DIR} DIRECTORY)
file(RELATIVE_PATH RELPATH ${ITEM_REL} ${ITEM})
get_filename_component(RELPATH ${RELPATH} DIRECTORY)
get_filename_component(ITEMEXT ${ITEM} LAST_EXT)
if("${ITEMEXT}" STREQUAL ".dll" OR "${ITEMEXT}" STREQUAL ".pdb")
string(CONCAT RELPATH "")
elseif ("${ITEMEXT}" STREQUAL ".so")
file(RELATIVE_PATH RELPATH "${ITEM_REL}/winuwp" ${ITEM})
string(REGEX REPLACE "/" "\\\\" RELPATH ${RELPATH})
string(CONCAT RELPATH "Assets\\Data")
elseif("${ITEMEXT}" STREQUAL ".dat")
string(CONCAT RELPATH "Assets\\Data")
else()
string(REGEX REPLACE "/" "\\\\" RELPATH ${RELPATH})
string(CONCAT RELPATH "Assets\\Data\\" ${RELPATH})
endif()
cmake_print_variables(${RELPATH})
set_property(SOURCE ${ITEM} PROPERTY VS_DEPLOYMENT_CONTENT 1)
set_property(SOURCE ${ITEM} PROPERTY VS_DEPLOYMENT_LOCATION ${RELPATH})
endforeach()
# 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
main.cpp
flutter_frameworkview.cpp
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
${RESOURCE_FILES}
${INSTALL_MANIFEST_CONTENT}
)
# 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 WindowsApp 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)

View File

@ -0,0 +1,27 @@
{
// See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.
"configurations": [
{
"name": "Debug",
"generator": "Visual Studio 15 2017 Win64",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
},
{
"name": "Release",
"generator": "Visual Studio 15 2017 Win64",
"configurationType": "Release",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
}
]
}

Binary file not shown.

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
IgnorableNamespaces="uap mp">
<Identity Name="@PACKAGE_GUID@" Publisher="CN=CMake Test Cert" Version="1.1.0.0" />
<mp:PhoneIdentity PhoneProductId="@PACKAGE_GUID@" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>@SHORT_NAME@</DisplayName>
<PublisherDisplayName>CMake Test Cert</PublisherDisplayName>
<Logo>Assets/StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.65535.65535" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="@SHORT_NAME@.App">
<uap:VisualElements
DisplayName="@SHORT_NAME@"
Description="@SHORT_NAME@"
BackgroundColor="#336699"
Square150x150Logo="Assets/Square150x150Logo.png"
Square44x44Logo="Assets/Square44x44Logo.png"
>
<uap:SplashScreen Image="Assets/SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClientServer"/>
<Capability Name="internetClient"/>
<Capability Name="privateNetworkClientServer"/>
<Capability Name="codeGeneration"/></Capabilities>
</Package>

View File

@ -0,0 +1,155 @@
#include "winrt/Windows.ApplicationModel.Core.h"
#include "winrt/Windows.Foundation.h"
#include "winrt/Windows.System.Profile.h"
#include "winrt/Windows.System.Threading.h"
#include "winrt/Windows.UI.Core.h"
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Graphics.Display.h>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.UI.Popups.h>
#include <winrt/Windows.UI.ViewManagement.Core.h>
#include <winrt/Windows.UI.ViewManagement.h>
#include <chrono>
#include <memory>
#include <thread>
#include <flutter/flutter_view_controller.h>
#include <flutter/flutter_windows.h>
#include <flutter/generated_plugin_registrant.h>
#include <flutter/plugin_registry.h>
struct FlutterFrameworkView
: winrt::implements<
FlutterFrameworkView,
winrt::Windows::ApplicationModel::Core::IFrameworkView> {
// |winrt::Windows::ApplicationModel::Core::IFrameworkView|
void
Initialize(winrt::Windows::ApplicationModel::Core::CoreApplicationView const
&applicationView) {
// Layout scaling must be disabled in the appinitialization phase in order
// to take effect correctly.
if (winrt::Windows::System::Profile::AnalyticsInfo::VersionInfo()
.DeviceFamily() == L"Windows.Xbox") {
bool result = winrt::Windows::UI::ViewManagement::ApplicationViewScaling::
TrySetDisableLayoutScaling(true);
if (!result) {
OutputDebugString(L"Couldn't disable layout scaling");
}
}
main_view_ = applicationView;
main_view_.Activated({this, &FlutterFrameworkView::OnActivated});
}
// |winrt::Windows::ApplicationModel::Core::IFrameworkView|
void Uninitialize() {
main_view_.Activated(nullptr);
main_view_ = nullptr;
}
// |winrt::Windows::ApplicationModel::Core::IFrameworkView|
void Load(winrt::hstring const &) {}
// |winrt::Windows::ApplicationModel::Core::IFrameworkView|
void Run() {
winrt::Windows::UI::Core::CoreWindow window =
winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread();
winrt::Windows::UI::Core::CoreDispatcher dispatcher = window.Dispatcher();
dispatcher.ProcessEvents(
winrt::Windows::UI::Core::CoreProcessEventsOption::ProcessUntilQuit);
}
// |winrt::Windows::ApplicationModel::Core::IFrameworkView|
winrt::Windows::Foundation::IAsyncAction
SetWindow(winrt::Windows::UI::Core::CoreWindow const &window) {
// Capture reference to window.
window_ = window;
// Lay out the window's content within the region occupied by the
// CoreWindow.
auto appView = winrt::Windows::UI::ViewManagement::ApplicationView::
GetForCurrentView();
appView.SetDesiredBoundsMode(winrt::Windows::UI::ViewManagement::
ApplicationViewBoundsMode::UseCoreWindow);
// Configure folder paths.
try {
winrt::Windows::Storage::StorageFolder folder =
winrt::Windows::ApplicationModel::Package::Current()
.InstalledLocation();
winrt::Windows::Storage::StorageFolder assets =
co_await folder.GetFolderAsync(L"Assets");
winrt::Windows::Storage::StorageFolder data =
co_await assets.GetFolderAsync(L"data");
winrt::Windows::Storage::StorageFolder flutter_assets =
co_await data.GetFolderAsync(L"flutter_assets");
winrt::Windows::Storage::StorageFile icu_data =
co_await data.GetFileAsync(L"icudtl.dat");
#if NDEBUG
winrt::Windows::Storage::StorageFile aot_data =
co_await data.GetFileAsync(L"app.so");
#endif
std::wstring flutter_assets_path{flutter_assets.Path()};
std::wstring icu_data_path{icu_data.Path()};
std::wstring aot_data_path {
#if NDEBUG
aot_data.Path()
#endif
};
flutter::DartProject project(flutter_assets_path, icu_data_path,
aot_data_path);
// Construct viewcontroller using the Window and project
flutter_view_controller_ = std::make_unique<flutter::FlutterViewController>(
static_cast<ABI::Windows::ApplicationModel::Core::CoreApplicationView*>(winrt::get_abi(main_view_)),
static_cast<ABI::Windows::ApplicationModel::Activation::IActivatedEventArgs*>(winrt::get_abi(launch_args_)),
project);
// If plugins present, register them.
RegisterPlugins(flutter_view_controller_.get()->engine());
} catch (winrt::hresult_error &err) {
winrt::Windows::UI::Popups::MessageDialog md =
winrt::Windows::UI::Popups::MessageDialog::MessageDialog(
L"There was a problem starting the engine: " + err.message());
md.ShowAsync();
}
}
void OnActivated(
winrt::Windows::ApplicationModel::Core::CoreApplicationView const
&applicationView,
winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs const
&args) {
// Activate the application window, making it visible and enabling it to
// receive events.
applicationView.CoreWindow().Activate();
// Capture launch args to later pass to Flutter.
launch_args_ = args;
}
// Current CoreApplicationView.
winrt::Windows::ApplicationModel::Core::CoreApplicationView main_view_{
nullptr};
// Current CoreWindow.
winrt::Windows::UI::Core::CoreWindow window_{nullptr};
// Current FlutterViewController.
std::unique_ptr<flutter::FlutterViewController> flutter_view_controller_{
nullptr};
// Launch args that were passed in on activation.
winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs
launch_args_;
};

View File

@ -0,0 +1,30 @@
#include <windows.h>
#include "winrt/Windows.ApplicationModel.Core.h"
#include "winrt/Windows.Foundation.h"
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.UI.ViewManagement.Core.h>
#include <winrt/Windows.UI.ViewManagement.h>
#include <memory>
#include "flutter_frameworkview.cpp"
struct App
: winrt::implements<
App, winrt::Windows::ApplicationModel::Core::IFrameworkViewSource> {
App() { view_ = winrt::make_self<FlutterFrameworkView>(); }
// |winrt::Windows::ApplicationModel::Core::IFrameworkViewSource|
winrt::Windows::ApplicationModel::Core::IFrameworkView CreateView() {
return view_.as<winrt::Windows::ApplicationModel::Core::IFrameworkView>();
}
winrt::com_ptr<FlutterFrameworkView> view_;
};
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) {
winrt::Windows::ApplicationModel::Core::CoreApplication::Run(
winrt::make<App>());
}

Binary file not shown.