diff --git a/.gitignore b/.gitignore index e9c0ad2e..2f82071e 100644 --- a/.gitignore +++ b/.gitignore @@ -55,4 +55,10 @@ android/keys.json android/Gemfile.lock lib/l10n_old ios/Flutter/.last_build_id -ios/Podfile.lock \ No newline at end of file +ios/Podfile.lock + +/windows/out +/winuwp/out +/linux/out +/macos/out +.vs diff --git a/.metadata b/.metadata new file mode 100644 index 00000000..e8149129 --- /dev/null +++ b/.metadata @@ -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 diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 135fcfc4..c83a91e8 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -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" } diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index b76a4194..6cfe8ccd 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -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 { 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 { .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; diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index 9b548063..74880e50 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -36,77 +36,87 @@ class ChatView extends StatelessWidget { const ChatView(this.controller, {Key? key}) : super(key: key); - List _appBarActions(BuildContext context) => controller.selectMode - ? [ - if (controller.canEditSelectedEvents) - IconButton( - icon: const Icon(Icons.edit_outlined), - tooltip: L10n.of(context)!.edit, - onPressed: controller.editSelectedEventAction, - ), + List _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: [ - 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: [ - TombstoneDisplay(controller), - Expanded( - child: GestureDetector( - onTap: controller.clearSingleSelectedEvent, - child: FutureBuilder( - 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 = {}; - 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( + 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: [ + 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: [ + 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 = {}; + 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, + ), + ), + ], + ), + ), + ); + }, ), ), ); diff --git a/lib/pages/chat/cupertino_widgets_bottom_sheet.dart b/lib/pages/chat/cupertino_widgets_bottom_sheet.dart new file mode 100644 index 00000000..d4c320c8 --- /dev/null +++ b/lib/pages/chat/cupertino_widgets_bottom_sheet.dart @@ -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, + ), + ], + ); + } +} diff --git a/lib/pages/chat/widgets_bottom_sheet.dart b/lib/pages/chat/widgets_bottom_sheet.dart new file mode 100644 index 00000000..e05c1617 --- /dev/null +++ b/lib/pages/chat/widgets_bottom_sheet.dart @@ -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, + ); + } +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 4368a0a5..d7158b13 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -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")) } diff --git a/pubspec.lock b/pubspec.lock index 4ea0757c..4970324d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -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" diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt index c7a8c760..744f08a9 100644 --- a/windows/flutter/CMakeLists.txt +++ b/windows/flutter/CMakeLists.txt @@ -91,6 +91,7 @@ add_custom_command( ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" windows-x64 $ + VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index acf95a15..f4b94444 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -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 $) 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) diff --git a/winuwp/.gitignore b/winuwp/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/winuwp/.gitignore @@ -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/ diff --git a/winuwp/CMakeLists.txt b/winuwp/CMakeLists.txt new file mode 100644 index 00000000..7530c80c --- /dev/null +++ b/winuwp/CMakeLists.txt @@ -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 "$<$:_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) diff --git a/winuwp/flutter/CMakeLists.txt b/winuwp/flutter/CMakeLists.txt new file mode 100644 index 00000000..9adbd9dd --- /dev/null +++ b/winuwp/flutter/CMakeLists.txt @@ -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} +) diff --git a/winuwp/flutter/flutter_windows.h b/winuwp/flutter/flutter_windows.h new file mode 100644 index 00000000..0aeb6fdc --- /dev/null +++ b/winuwp/flutter/flutter_windows.h @@ -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 +#include +#include + +#include "flutter_export.h" +#include "flutter_messenger.h" +#include "flutter_plugin_registrar.h" + +#ifdef WINUWP +#include +#include +#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_ diff --git a/winuwp/flutter/generated_plugin_registrant.cc b/winuwp/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/winuwp/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/winuwp/flutter/generated_plugin_registrant.h b/winuwp/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/winuwp/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/winuwp/flutter/generated_plugins.cmake b/winuwp/flutter/generated_plugins.cmake new file mode 100644 index 00000000..4d10c251 --- /dev/null +++ b/winuwp/flutter/generated_plugins.cmake @@ -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 $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/winuwp/project_version b/winuwp/project_version new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/winuwp/project_version @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/winuwp/runner_uwp/Assets/LargeTile.scale-100.png b/winuwp/runner_uwp/Assets/LargeTile.scale-100.png new file mode 100644 index 00000000..fa651eb7 Binary files /dev/null and b/winuwp/runner_uwp/Assets/LargeTile.scale-100.png differ diff --git a/winuwp/runner_uwp/Assets/LargeTile.scale-125.png b/winuwp/runner_uwp/Assets/LargeTile.scale-125.png new file mode 100644 index 00000000..649e0769 Binary files /dev/null and b/winuwp/runner_uwp/Assets/LargeTile.scale-125.png differ diff --git a/winuwp/runner_uwp/Assets/LargeTile.scale-150.png b/winuwp/runner_uwp/Assets/LargeTile.scale-150.png new file mode 100644 index 00000000..fd14c60c Binary files /dev/null and b/winuwp/runner_uwp/Assets/LargeTile.scale-150.png differ diff --git a/winuwp/runner_uwp/Assets/LargeTile.scale-200.png b/winuwp/runner_uwp/Assets/LargeTile.scale-200.png new file mode 100644 index 00000000..873537f3 Binary files /dev/null and b/winuwp/runner_uwp/Assets/LargeTile.scale-200.png differ diff --git a/winuwp/runner_uwp/Assets/LargeTile.scale-400.png b/winuwp/runner_uwp/Assets/LargeTile.scale-400.png new file mode 100644 index 00000000..979878f7 Binary files /dev/null and b/winuwp/runner_uwp/Assets/LargeTile.scale-400.png differ diff --git a/winuwp/runner_uwp/Assets/LockScreenLogo.scale-200.png b/winuwp/runner_uwp/Assets/LockScreenLogo.scale-200.png new file mode 100644 index 00000000..735f57ad Binary files /dev/null and b/winuwp/runner_uwp/Assets/LockScreenLogo.scale-200.png differ diff --git a/winuwp/runner_uwp/Assets/SmallTile.scale-100.png b/winuwp/runner_uwp/Assets/SmallTile.scale-100.png new file mode 100644 index 00000000..35e7f624 Binary files /dev/null and b/winuwp/runner_uwp/Assets/SmallTile.scale-100.png differ diff --git a/winuwp/runner_uwp/Assets/SmallTile.scale-125.png b/winuwp/runner_uwp/Assets/SmallTile.scale-125.png new file mode 100644 index 00000000..2a74cc67 Binary files /dev/null and b/winuwp/runner_uwp/Assets/SmallTile.scale-125.png differ diff --git a/winuwp/runner_uwp/Assets/SmallTile.scale-150.png b/winuwp/runner_uwp/Assets/SmallTile.scale-150.png new file mode 100644 index 00000000..15712482 Binary files /dev/null and b/winuwp/runner_uwp/Assets/SmallTile.scale-150.png differ diff --git a/winuwp/runner_uwp/Assets/SmallTile.scale-200.png b/winuwp/runner_uwp/Assets/SmallTile.scale-200.png new file mode 100644 index 00000000..07ec2ddc Binary files /dev/null and b/winuwp/runner_uwp/Assets/SmallTile.scale-200.png differ diff --git a/winuwp/runner_uwp/Assets/SmallTile.scale-400.png b/winuwp/runner_uwp/Assets/SmallTile.scale-400.png new file mode 100644 index 00000000..c205729b Binary files /dev/null and b/winuwp/runner_uwp/Assets/SmallTile.scale-400.png differ diff --git a/winuwp/runner_uwp/Assets/SplashScreen.scale-100.png b/winuwp/runner_uwp/Assets/SplashScreen.scale-100.png new file mode 100644 index 00000000..60125798 Binary files /dev/null and b/winuwp/runner_uwp/Assets/SplashScreen.scale-100.png differ diff --git a/winuwp/runner_uwp/Assets/SplashScreen.scale-125.png b/winuwp/runner_uwp/Assets/SplashScreen.scale-125.png new file mode 100644 index 00000000..0c35be82 Binary files /dev/null and b/winuwp/runner_uwp/Assets/SplashScreen.scale-125.png differ diff --git a/winuwp/runner_uwp/Assets/SplashScreen.scale-150.png b/winuwp/runner_uwp/Assets/SplashScreen.scale-150.png new file mode 100644 index 00000000..f1e60f33 Binary files /dev/null and b/winuwp/runner_uwp/Assets/SplashScreen.scale-150.png differ diff --git a/winuwp/runner_uwp/Assets/SplashScreen.scale-200.png b/winuwp/runner_uwp/Assets/SplashScreen.scale-200.png new file mode 100644 index 00000000..73d2461c Binary files /dev/null and b/winuwp/runner_uwp/Assets/SplashScreen.scale-200.png differ diff --git a/winuwp/runner_uwp/Assets/SplashScreen.scale-400.png b/winuwp/runner_uwp/Assets/SplashScreen.scale-400.png new file mode 100644 index 00000000..b2b7ca9c Binary files /dev/null and b/winuwp/runner_uwp/Assets/SplashScreen.scale-400.png differ diff --git a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-100.png b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-100.png new file mode 100644 index 00000000..cdc3e973 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-100.png differ diff --git a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-125.png b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-125.png new file mode 100644 index 00000000..71e5a115 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-125.png differ diff --git a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-150.png b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-150.png new file mode 100644 index 00000000..60f2e182 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-150.png differ diff --git a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-200.png b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-200.png new file mode 100644 index 00000000..20814081 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-200.png differ diff --git a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-400.png b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-400.png new file mode 100644 index 00000000..605aacb0 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-400.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-16.png b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-16.png new file mode 100644 index 00000000..1c78d96b Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-16.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-256.png b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-256.png new file mode 100644 index 00000000..d49d3d89 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-256.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-32.png b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-32.png new file mode 100644 index 00000000..88962246 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-32.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-48.png b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-48.png new file mode 100644 index 00000000..6389ede5 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-48.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-100.png b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-100.png new file mode 100644 index 00000000..47e3cd29 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-100.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-125.png b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-125.png new file mode 100644 index 00000000..50faa932 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-125.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-150.png b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-150.png new file mode 100644 index 00000000..f0293ed8 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-150.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-200.png b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-200.png new file mode 100644 index 00000000..e54a56db Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-200.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-400.png b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-400.png new file mode 100644 index 00000000..4b5fb179 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-400.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-16.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-16.png new file mode 100644 index 00000000..a1a6ec70 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-16.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24.png new file mode 100644 index 00000000..c67a8e12 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 00000000..47d36f63 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-256.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-256.png new file mode 100644 index 00000000..50efc008 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-256.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-32.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-32.png new file mode 100644 index 00000000..f86682c9 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-32.png differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-48.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-48.png new file mode 100644 index 00000000..7561269a Binary files /dev/null and b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-48.png differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.png b/winuwp/runner_uwp/Assets/StoreLogo.png new file mode 100644 index 00000000..7385b56c Binary files /dev/null and b/winuwp/runner_uwp/Assets/StoreLogo.png differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.scale-100.png b/winuwp/runner_uwp/Assets/StoreLogo.scale-100.png new file mode 100644 index 00000000..fcefe81b Binary files /dev/null and b/winuwp/runner_uwp/Assets/StoreLogo.scale-100.png differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.scale-125.png b/winuwp/runner_uwp/Assets/StoreLogo.scale-125.png new file mode 100644 index 00000000..4381be77 Binary files /dev/null and b/winuwp/runner_uwp/Assets/StoreLogo.scale-125.png differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.scale-150.png b/winuwp/runner_uwp/Assets/StoreLogo.scale-150.png new file mode 100644 index 00000000..e49390bf Binary files /dev/null and b/winuwp/runner_uwp/Assets/StoreLogo.scale-150.png differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.scale-200.png b/winuwp/runner_uwp/Assets/StoreLogo.scale-200.png new file mode 100644 index 00000000..fb740e84 Binary files /dev/null and b/winuwp/runner_uwp/Assets/StoreLogo.scale-200.png differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.scale-400.png b/winuwp/runner_uwp/Assets/StoreLogo.scale-400.png new file mode 100644 index 00000000..d1472741 Binary files /dev/null and b/winuwp/runner_uwp/Assets/StoreLogo.scale-400.png differ diff --git a/winuwp/runner_uwp/Assets/Wide310x150Logo.scale-200.png b/winuwp/runner_uwp/Assets/Wide310x150Logo.scale-200.png new file mode 100644 index 00000000..288995b3 Binary files /dev/null and b/winuwp/runner_uwp/Assets/Wide310x150Logo.scale-200.png differ diff --git a/winuwp/runner_uwp/Assets/WideTile.scale-100.png b/winuwp/runner_uwp/Assets/WideTile.scale-100.png new file mode 100644 index 00000000..1cb688c7 Binary files /dev/null and b/winuwp/runner_uwp/Assets/WideTile.scale-100.png differ diff --git a/winuwp/runner_uwp/Assets/WideTile.scale-125.png b/winuwp/runner_uwp/Assets/WideTile.scale-125.png new file mode 100644 index 00000000..72923961 Binary files /dev/null and b/winuwp/runner_uwp/Assets/WideTile.scale-125.png differ diff --git a/winuwp/runner_uwp/Assets/WideTile.scale-150.png b/winuwp/runner_uwp/Assets/WideTile.scale-150.png new file mode 100644 index 00000000..d4b275a5 Binary files /dev/null and b/winuwp/runner_uwp/Assets/WideTile.scale-150.png differ diff --git a/winuwp/runner_uwp/Assets/WideTile.scale-200.png b/winuwp/runner_uwp/Assets/WideTile.scale-200.png new file mode 100644 index 00000000..60125798 Binary files /dev/null and b/winuwp/runner_uwp/Assets/WideTile.scale-200.png differ diff --git a/winuwp/runner_uwp/Assets/WideTile.scale-400.png b/winuwp/runner_uwp/Assets/WideTile.scale-400.png new file mode 100644 index 00000000..73d2461c Binary files /dev/null and b/winuwp/runner_uwp/Assets/WideTile.scale-400.png differ diff --git a/winuwp/runner_uwp/CMakeLists.txt b/winuwp/runner_uwp/CMakeLists.txt new file mode 100644 index 00000000..b4362a4f --- /dev/null +++ b/winuwp/runner_uwp/CMakeLists.txt @@ -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) diff --git a/winuwp/runner_uwp/CMakeSettings.json b/winuwp/runner_uwp/CMakeSettings.json new file mode 100644 index 00000000..ba63a530 --- /dev/null +++ b/winuwp/runner_uwp/CMakeSettings.json @@ -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": "" + } + ] +} diff --git a/winuwp/runner_uwp/Windows_TemporaryKey.pfx b/winuwp/runner_uwp/Windows_TemporaryKey.pfx new file mode 100644 index 00000000..1cad9993 Binary files /dev/null and b/winuwp/runner_uwp/Windows_TemporaryKey.pfx differ diff --git a/winuwp/runner_uwp/appxmanifest.in b/winuwp/runner_uwp/appxmanifest.in new file mode 100644 index 00000000..570d424e --- /dev/null +++ b/winuwp/runner_uwp/appxmanifest.in @@ -0,0 +1,42 @@ + + + + + + + + @SHORT_NAME@ + CMake Test Cert + Assets/StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + diff --git a/winuwp/runner_uwp/flutter_frameworkview.cpp b/winuwp/runner_uwp/flutter_frameworkview.cpp new file mode 100644 index 00000000..bcdc73ad --- /dev/null +++ b/winuwp/runner_uwp/flutter_frameworkview.cpp @@ -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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +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( + static_cast(winrt::get_abi(main_view_)), + static_cast(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_view_controller_{ + nullptr}; + + // Launch args that were passed in on activation. + winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs + launch_args_; +}; diff --git a/winuwp/runner_uwp/main.cpp b/winuwp/runner_uwp/main.cpp new file mode 100644 index 00000000..1ce54b1f --- /dev/null +++ b/winuwp/runner_uwp/main.cpp @@ -0,0 +1,30 @@ + +#include + +#include "winrt/Windows.ApplicationModel.Core.h" +#include "winrt/Windows.Foundation.h" +#include +#include +#include + +#include + +#include "flutter_frameworkview.cpp" + +struct App + : winrt::implements< + App, winrt::Windows::ApplicationModel::Core::IFrameworkViewSource> { + App() { view_ = winrt::make_self(); } + + // |winrt::Windows::ApplicationModel::Core::IFrameworkViewSource| + winrt::Windows::ApplicationModel::Core::IFrameworkView CreateView() { + return view_.as(); + } + + winrt::com_ptr view_; +}; + +int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { + winrt::Windows::ApplicationModel::Core::CoreApplication::Run( + winrt::make()); +} diff --git a/winuwp/runner_uwp/resources.pri b/winuwp/runner_uwp/resources.pri new file mode 100644 index 00000000..7de03c9d Binary files /dev/null and b/winuwp/runner_uwp/resources.pri differ