From b17c22321eacb2ea4607ec244ec1df8582aa63c8 Mon Sep 17 00:00:00 2001 From: Welton Moura Date: Mon, 14 Sep 2026 13:47:16 -0300 Subject: [PATCH] largura imagem mural, comentarios --- lib/pages/mural/mural_chat_page.dart | 764 ++++++++++++++++++++------- windows/flutter/CMakeLists.txt | 7 +- windows/runner/CMakeLists.txt | 7 + windows/runner/Runner.rc | 10 +- 4 files changed, 604 insertions(+), 184 deletions(-) diff --git a/lib/pages/mural/mural_chat_page.dart b/lib/pages/mural/mural_chat_page.dart index 86e7645..d71b22d 100644 --- a/lib/pages/mural/mural_chat_page.dart +++ b/lib/pages/mural/mural_chat_page.dart @@ -16,6 +16,7 @@ import 'package:tatchat/pages/chat/sticker_picker_dialog.dart'; import 'package:tatchat/pages/image_viewer/video_player.dart'; import 'package:tatchat/utils/adaptive_bottom_sheet.dart'; import 'package:tatchat/utils/matrix_sdk_extensions/matrix_locals.dart'; +import 'package:tatchat/utils/show_scaffold_dialog.dart'; import 'package:tatchat/utils/stream_extension.dart'; import 'package:tatchat/utils/url_launcher.dart'; import 'package:tatchat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; @@ -24,6 +25,7 @@ import 'package:tatchat/widgets/adaptive_dialogs/user_dialog.dart'; import 'package:tatchat/widgets/avatar.dart'; import 'package:tatchat/widgets/matrix.dart'; import 'package:tatchat/widgets/mxc_image.dart'; +import 'package:tatchat/widgets/share_scaffold_dialog.dart'; const _muralMediaTypes = { MessageTypes.Image, @@ -654,9 +656,16 @@ class _PostViewer extends StatefulWidget { State<_PostViewer> createState() => _PostViewerState(); } +class _CommentNode { + final Event event; + final List<_CommentNode> replies; + _CommentNode(this.event) : replies = []; +} + class _PostViewerState extends State<_PostViewer> { final TextEditingController _commentController = TextEditingController(); bool _sending = false; + Event? _replyingTo; Event get event => widget.event; @@ -702,6 +711,123 @@ class _PostViewerState extends State<_PostViewer> { } } + Future _forwardPost() async { + await showScaffoldDialog( + context: context, + builder: (context) => ShareScaffoldDialog( + items: [ContentShareItem(event.content.copy())], + ), + ); + } + + Future _toggleCommentReaction(Event comment, String key) async { + final reactions = comment.aggregatedEvents( + widget.timeline, + RelationshipTypes.reaction, + ); + for (final r in reactions) { + if (r.senderId != widget.room.client.userID) continue; + final rKey = r.content + .tryGetMap('m.relates_to') + ?.tryGet('key'); + if (rKey == key) { + await r.redactEvent(); + return; + } + } + await widget.room.sendReaction(comment.eventId, key); + } + + Future _showCommentReactionPicker(Event comment) async { + final theme = Theme.of(context); + await showModalBottomSheet( + context: context, + useSafeArea: true, + backgroundColor: theme.colorScheme.surface, + builder: (context) => SizedBox( + height: MediaQuery.sizeOf(context).height * 0.5, + child: EmojiPicker( + onEmojiSelected: (_, emoji) { + Navigator.of(context).pop(); + _toggleCommentReaction(comment, emoji.emoji); + }, + config: Config( + locale: Localizations.localeOf(context), + emojiViewConfig: EmojiViewConfig( + backgroundColor: theme.colorScheme.onInverseSurface, + ), + bottomActionBarConfig: const BottomActionBarConfig(enabled: false), + categoryViewConfig: CategoryViewConfig( + backspaceColor: theme.colorScheme.primary, + iconColor: theme.colorScheme.primary.withAlpha(128), + iconColorSelected: theme.colorScheme.primary, + indicatorColor: theme.colorScheme.primary, + backgroundColor: theme.colorScheme.surface, + ), + skinToneConfig: const SkinToneConfig(indicatorColor: Colors.grey), + ), + ), + ), + ); + } + + List<_CommentNode> _buildCommentTree() { + final allComments = widget.timeline.events + .where( + (e) => + !e.redacted && + e.relationshipType == RelationshipTypes.thread && + e.relationshipEventId == event.eventId, + ) + .toList(); + allComments.sort( + (a, b) => a.originServerTs.compareTo(b.originServerTs), + ); + + final nodeMap = {}; + final roots = <_CommentNode>[]; + + for (final comment in allComments) { + nodeMap[comment.eventId] = _CommentNode(comment); + } + + String? resolveRoot(String? id) { + var current = id; + final visited = {}; + while (current != null && + current != event.eventId && + nodeMap.containsKey(current)) { + if (!visited.add(current)) break; + final node = nodeMap[current]!; + final parentId = + node.event.inReplyToEventId(includingFallback: false); + if (parentId == null || + parentId == event.eventId || + !nodeMap.containsKey(parentId)) { + return current; + } + current = parentId; + } + return null; + } + + for (final comment in allComments) { + final replyToId = comment.inReplyToEventId(includingFallback: false); + final node = nodeMap[comment.eventId]!; + if (replyToId != null && + replyToId != event.eventId && + nodeMap.containsKey(replyToId)) { + final rootId = resolveRoot(replyToId); + if (rootId != null && rootId != comment.eventId) { + nodeMap[rootId]!.replies.add(node); + continue; + } + } + roots.add(node); + } + return roots; + } + Future _editCaption() async { final l10n = L10n.of(context); final currentBody = event.getDisplayEvent(widget.timeline).body.trim(); @@ -766,13 +892,62 @@ class _PostViewerState extends State<_PostViewer> { ).showSnackBar(SnackBar(content: Text(l10n.contentHasBeenReported))); } + Future _deleteComment(Event comment) async { + final l10n = L10n.of(context); + final delete = await showOkCancelAlertDialog( + context: context, + title: l10n.areYouSure, + message: l10n.areYouSureDeletePost, + okLabel: l10n.delete, + cancelLabel: l10n.cancel, + ); + if (delete != OkCancelResult.ok || !mounted) return; + try { + await comment.redactEvent(); + } catch (e) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(L10n.of(context).oopsSomethingWentWrong)), + ); + } + } + + Future _reportComment(Event comment) async { + final l10n = L10n.of(context); + final reason = await showTextInputDialog( + context: context, + title: l10n.whyDoYouWantToReportThis, + okLabel: l10n.report, + cancelLabel: l10n.cancel, + hintText: l10n.reason, + ); + if (reason == null || reason.isEmpty || !mounted) return; + await widget.room.client.reportEvent( + widget.room.id, + comment.eventId, + reason: reason, + ); + if (!mounted) return; + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(l10n.contentHasBeenReported))); + } + Future _sendComment() async { final text = _commentController.text.trim(); if (text.isEmpty || _sending) return; _commentController.clear(); - setState(() => _sending = true); + final replyTo = _replyingTo; + setState(() { + _sending = true; + _replyingTo = null; + }); try { - await widget.room.sendTextEvent(text, threadRootEventId: event.eventId); + await widget.room.sendTextEvent( + text, + threadRootEventId: event.eventId, + inReplyTo: replyTo, + ); } finally { if (mounted) setState(() => _sending = false); } @@ -858,19 +1033,6 @@ class _PostViewerState extends State<_PostViewer> { ); } - List _comments() { - final comments = widget.timeline.events - .where( - (e) => - !e.redacted && - e.relationshipType == RelationshipTypes.thread && - e.relationshipEventId == event.eventId, - ) - .toList(); - comments.sort((a, b) => a.originServerTs.compareTo(b.originServerTs)); - return comments; - } - void _openProfile(Event comment) { final sender = comment.senderFromMemoryOrFallback; UserDialog.show( @@ -889,12 +1051,18 @@ class _PostViewerState extends State<_PostViewer> { final l10n = L10n.of(context); final isVideo = event.messageType == MessageTypes.Video; + final imageInfo = event.content.tryGetMap('info'); + final imgW = imageInfo?.tryGet('w')?.toDouble(); + final imgH = imageInfo?.tryGet('h')?.toDouble(); + final hasImageDimensions = + imgW != null && imgH != null && imgW > 0 && imgH > 0; + return StreamBuilder( stream: widget.room.client.onSync.stream .where((syncUpdate) => syncUpdate.hasRoomUpdate) .rateLimit(const Duration(seconds: 1)), builder: (context, snapshots) { - final comments = _comments(); + final commentTree = _buildCommentTree(); final caption = event.getDisplayEvent(widget.timeline).body.trim(); final liked = _myReaction() != null; @@ -939,181 +1107,174 @@ class _PostViewerState extends State<_PostViewer> { ), ), Expanded( - flex: 5, - child: Container( - color: theme.colorScheme.surfaceContainerHighest, - width: double.infinity, - child: isVideo - ? EventVideoPlayer(event) - : MxcImage( - key: ValueKey(event.eventId), - event: event, - fit: BoxFit.contain, - isThumbnail: false, - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, + child: ListView( + padding: EdgeInsets.zero, children: [ - IconButton( - tooltip: liked ? l10n.unlike : l10n.like, - icon: Icon( - liked ? Icons.favorite : Icons.favorite_border, - color: liked ? Colors.redAccent : null, - ), - onPressed: _toggleLike, + Container( + color: theme.colorScheme.surfaceContainerHighest, + width: double.infinity, + child: isVideo + ? EventVideoPlayer(event) + : hasImageDimensions + ? AspectRatio( + aspectRatio: imgW / imgH, + child: MxcImage( + key: ValueKey(event.eventId), + event: event, + fit: BoxFit.cover, + isThumbnail: false, + ), + ) + : MxcImage( + key: ValueKey(event.eventId), + event: event, + width: double.infinity, + fit: BoxFit.contain, + isThumbnail: false, + ), ), - if (_likeCount > 0) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + IconButton( + tooltip: liked ? l10n.unlike : l10n.like, + icon: Icon( + liked ? Icons.favorite : Icons.favorite_border, + color: liked ? Colors.redAccent : null, + ), + onPressed: _toggleLike, + ), + if (_likeCount > 0) + Padding( + padding: const EdgeInsets.only(bottom: 10), + child: Text( + '$_likeCount', + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ), + IconButton( + tooltip: l10n.forward, + icon: Icon(Icons.adaptive.share_outlined), + onPressed: _forwardPost, + ), + const Spacer(), + PopupMenuButton( + tooltip: l10n.more, + onSelected: (action) async { + switch (action) { + case 'edit': + await _editCaption(); + case 'delete': + await _deletePost(); + case 'report': + await _reportPost(); + } + }, + itemBuilder: (context) => [ + PopupMenuItem( + value: 'edit', + child: ListTile( + leading: const Icon(Icons.edit_outlined), + title: Text(l10n.editCaption), + contentPadding: EdgeInsets.zero, + ), + ), + PopupMenuItem( + value: 'delete', + child: ListTile( + leading: const Icon(Icons.delete_outline), + title: Text(l10n.delete), + contentPadding: EdgeInsets.zero, + ), + ), + PopupMenuItem( + value: 'report', + child: ListTile( + leading: const Icon(Icons.flag_outlined), + title: Text(l10n.report), + contentPadding: EdgeInsets.zero, + ), + ), + ], + icon: const Icon(Icons.more_vert), + ), + ], + ), + ), + if (caption.trim().isNotEmpty) Padding( - padding: const EdgeInsets.only(bottom: 10), + padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), child: Text( - '$_likeCount', - style: theme.textTheme.bodyMedium?.copyWith( + caption.trim(), + style: theme.textTheme.bodyMedium, + ), + ), + const Divider(height: 1), + if (commentTree.isEmpty) + Padding( + padding: const EdgeInsets.all(16), + child: Text( + l10n.noCommentsYet, + textAlign: TextAlign.center, + style: TextStyle( color: theme.colorScheme.onSurfaceVariant, ), ), - ), - const Spacer(), - PopupMenuButton( - tooltip: l10n.more, - onSelected: (action) async { - switch (action) { - case 'edit': - await _editCaption(); - case 'delete': - await _deletePost(); - case 'report': - await _reportPost(); - } - }, - itemBuilder: (context) => [ - PopupMenuItem( - value: 'edit', - child: ListTile( - leading: const Icon(Icons.edit_outlined), - title: Text(l10n.editCaption), - contentPadding: EdgeInsets.zero, - ), - ), - PopupMenuItem( - value: 'delete', - child: ListTile( - leading: const Icon(Icons.delete_outline), - title: Text(l10n.delete), - contentPadding: EdgeInsets.zero, - ), - ), - PopupMenuItem( - value: 'report', - child: ListTile( - leading: const Icon(Icons.flag_outlined), - title: Text(l10n.report), - contentPadding: EdgeInsets.zero, - ), - ), - ], - icon: const Icon(Icons.more_vert), - ), + ) + else + ...commentTree.map((node) => _CommentTile( + node: node, + depth: 0, + timeline: widget.timeline, + currentUserId: widget.room.client.userID, + onReply: (comment) => setState( + () => _replyingTo = comment, + ), + onToggleReaction: _toggleCommentReaction, + onShowReactionPicker: _showCommentReactionPicker, + onOpenProfile: _openProfile, + onDelete: _deleteComment, + onReport: _reportComment, + )), ], ), ), - if (caption.trim().isNotEmpty) - Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), - child: Text( - caption.trim(), - style: theme.textTheme.bodyMedium, + if (_replyingTo != null) + Container( + color: theme.colorScheme.secondaryContainer.withValues( + alpha: 0.5, ), - ), - const Divider(height: 1), - Expanded( - flex: 3, - child: comments.isEmpty - ? Center( - child: Padding( - padding: const EdgeInsets.all(16), - child: Text( - l10n.noCommentsYet, - textAlign: TextAlign.center, - style: TextStyle( - color: theme.colorScheme.onSurfaceVariant, - ), + padding: const EdgeInsets.fromLTRB(16, 6, 8, 6), + child: Row( + children: [ + Icon( + Icons.reply, + size: 16, + color: theme.colorScheme.primary, + ), + const SizedBox(width: 4), + Expanded( + child: Text( + '${l10n.reply} ${_replyingTo!.senderFromMemoryOrFallback.calcDisplayname()}', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.primary, ), ), - ) - : ListView.builder( - padding: const EdgeInsets.symmetric(vertical: 4), - itemCount: comments.length, - itemBuilder: (context, i) { - final comment = comments[i]; - final isSticker = - comment.messageType == MessageTypes.Sticker; - final sender = comment.senderFromMemoryOrFallback; - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 6, - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - GestureDetector( - onTap: () => _openProfile(comment), - child: Avatar( - mxContent: sender.avatarUrl, - name: sender.calcDisplayname(), - size: 32, - client: widget.room.client, - ), - ), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - GestureDetector( - onTap: () => _openProfile(comment), - child: Text( - sender.calcDisplayname(), - style: theme.textTheme.labelMedium - ?.copyWith( - fontWeight: FontWeight.bold, - ), - ), - ), - const SizedBox(height: 2), - if (isSticker) - MxcImage( - key: ValueKey(comment.eventId), - event: comment, - fit: BoxFit.contain, - isThumbnail: false, - width: double.infinity, - ) - else - Text( - comment - .getDisplayEvent(widget.timeline) - .calcLocalizedBodyFallback( - MatrixLocals(l10n), - withSenderNamePrefix: false, - hideReply: true, - ), - style: theme.textTheme.bodyMedium, - ), - ], - ), - ), - ], - ), - ); - }, ), - ), + IconButton( + visualDensity: VisualDensity.compact, + icon: const Icon(Icons.close, size: 18), + onPressed: () => setState(() => _replyingTo = null), + ), + ], + ), + ), Padding( padding: const EdgeInsets.fromLTRB(8, 4, 8, 8), child: Row( @@ -1134,7 +1295,9 @@ class _PostViewerState extends State<_PostViewer> { textInputAction: TextInputAction.send, onSubmitted: (_) => _sendComment(), decoration: InputDecoration( - hintText: l10n.optionalMessage, + hintText: _replyingTo != null + ? '${l10n.reply} ${_replyingTo!.senderFromMemoryOrFallback.calcDisplayname()}' + : l10n.optionalMessage, isDense: true, border: InputBorder.none, ), @@ -1155,3 +1318,248 @@ class _PostViewerState extends State<_PostViewer> { ); } } + +class _CommentTile extends StatelessWidget { + final _CommentNode node; + final int depth; + final Timeline timeline; + final String? currentUserId; + final ValueChanged onReply; + final void Function(Event comment, String key) onToggleReaction; + final ValueChanged onShowReactionPicker; + final ValueChanged onOpenProfile; + final ValueChanged onDelete; + final ValueChanged onReport; + + const _CommentTile({ + required this.node, + required this.depth, + required this.timeline, + required this.currentUserId, + required this.onReply, + required this.onToggleReaction, + required this.onShowReactionPicker, + required this.onOpenProfile, + required this.onDelete, + required this.onReport, + }); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final l10n = L10n.of(context); + final comment = node.event; + final isSticker = comment.messageType == MessageTypes.Sticker; + final sender = comment.senderFromMemoryOrFallback; + final indent = depth * 32.0; + + final reactions = comment.aggregatedEvents( + timeline, + RelationshipTypes.reaction, + ); + + final reactionCounts = {}; + for (final r in reactions) { + final key = r.content + .tryGetMap('m.relates_to') + ?.tryGet('key'); + if (key != null) { + reactionCounts[key] = (reactionCounts[key] ?? 0) + 1; + } + } + + final myUserId = comment.room.client.userID; + + return Padding( + padding: EdgeInsets.only( + left: 16.0 + indent, + right: 16, + top: depth == 0 ? 8 : 2, + bottom: 2, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GestureDetector( + onTap: () => onOpenProfile(comment), + child: Avatar( + mxContent: sender.avatarUrl, + name: sender.calcDisplayname(), + size: depth == 0 ? 32 : 24, + client: comment.room.client, + ), + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GestureDetector( + onTap: () => onOpenProfile(comment), + child: Text( + sender.calcDisplayname(), + style: theme.textTheme.labelMedium?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 2), + if (isSticker) + MxcImage( + key: ValueKey(comment.eventId), + event: comment, + fit: BoxFit.contain, + isThumbnail: false, + width: 200, + ) + else + Text( + comment + .getDisplayEvent(timeline) + .calcLocalizedBodyFallback( + MatrixLocals(l10n), + withSenderNamePrefix: false, + hideReply: true, + ), + style: theme.textTheme.bodyMedium, + ), + const SizedBox(height: 4), + Row( + children: [ + if (depth == 0) + GestureDetector( + onTap: () => onReply(comment), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Text( + l10n.reply, + style: theme.textTheme.labelSmall?.copyWith( + color: theme.colorScheme.primary, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + if (depth == 0) const SizedBox(width: 12), + ...reactionCounts.entries.map((entry) { + final isMyReaction = reactions.any( + (r) => + r.senderId == myUserId && + r.content + .tryGetMap( + 'm.relates_to', + ) + ?.tryGet('key') == + entry.key, + ); + return Padding( + padding: const EdgeInsets.only(right: 4), + child: GestureDetector( + onTap: () => + onToggleReaction(comment, entry.key), + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, + vertical: 2, + ), + decoration: BoxDecoration( + color: isMyReaction + ? theme.colorScheme.primaryContainer + : theme + .colorScheme + .surfaceContainerHighest, + borderRadius: BorderRadius.circular(12), + border: isMyReaction + ? Border.all( + color: + theme.colorScheme.primary, + width: 1, + ) + : null, + ), + child: Text( + '${entry.key} ${entry.value}', + style: theme.textTheme.labelSmall, + ), + ), + ), + ); + }), + GestureDetector( + onTap: () => onShowReactionPicker(comment), + child: Padding( + padding: const EdgeInsets.all(2), + child: Icon( + Icons.add_reaction_outlined, + size: 18, + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ), + const Spacer(), + PopupMenuButton( + tooltip: l10n.more, + padding: EdgeInsets.zero, + color: theme.colorScheme.surface, + onSelected: (action) async { + switch (action) { + case 'delete': + onDelete(comment); + case 'report': + onReport(comment); + } + }, + itemBuilder: (context) => [ + if (comment.senderId == currentUserId) + PopupMenuItem( + value: 'delete', + child: ListTile( + leading: const Icon(Icons.delete_outline), + title: Text(l10n.deleteMessage), + contentPadding: EdgeInsets.zero, + ), + ), + PopupMenuItem( + value: 'report', + child: ListTile( + leading: const Icon(Icons.flag_outlined), + title: Text(l10n.reportMessage), + contentPadding: EdgeInsets.zero, + ), + ), + ], + icon: Icon( + Icons.more_vert, + size: 18, + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ], + ), + ), + ], + ), + ...node.replies.map( + (reply) => _CommentTile( + node: reply, + depth: depth + 1, + timeline: timeline, + currentUserId: currentUserId, + onReply: onReply, + onToggleReaction: onToggleReaction, + onShowReactionPicker: onShowReactionPicker, + onOpenProfile: onOpenProfile, + onDelete: onDelete, + onReport: onReport, + ), + ), + ], + ), + ); + } +} diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt index 930d207..903f489 100644 --- a/windows/flutter/CMakeLists.txt +++ b/windows/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt index b9e550f..17411a8 100644 --- a/windows/runner/CMakeLists.txt +++ b/windows/runner/CMakeLists.txt @@ -20,6 +20,13 @@ add_executable(${BINARY_NAME} WIN32 # that need different build settings. apply_standard_settings(${BINARY_NAME}) +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + # Disable Windows macros that collide with C++ standard library functions. target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index eb68f44..0bac3c3 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -60,14 +60,14 @@ IDI_APP_ICON ICON "resources\\app_icon.ico" // Version // -#ifdef FLUTTER_BUILD_NUMBER -#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #else -#define VERSION_AS_NUMBER 1,0,0 +#define VERSION_AS_NUMBER 1,0,0,0 #endif -#ifdef FLUTTER_BUILD_NAME -#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION #else #define VERSION_AS_STRING "1.0.0" #endif