Skip to content

Commit

Permalink
Sticky actions bar for code snippets
Browse files Browse the repository at this point in the history
  • Loading branch information
WilliamKarolDiCioccio committed Sep 18, 2024
1 parent 07d4c2d commit aff3b0f
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 74 deletions.
5 changes: 4 additions & 1 deletion app/lib/frontend/widgets/chat_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ import 'package:unicons/unicons.dart';

class ChatMessageWidget extends StatefulWidget {
final ChatMessageWrapper message;
final ScrollController scrollController;

const ChatMessageWidget(
this.message, {
this.message,
this.scrollController, {
super.key,
});

Expand Down Expand Up @@ -238,6 +240,7 @@ class _ChatMessageWidgetState extends State<ChatMessageWidget> {
if (!_showEditWidget && widget.message.text.isNotEmpty)
MarkdownBodyWidget(
widget.message.text,
widget.scrollController,
),
if (context.watch<ChatProvider>().isChatShowStatistics &&
widget.message.text.isNotEmpty &&
Expand Down
1 change: 1 addition & 0 deletions app/lib/frontend/widgets/chat_message_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class _ChatMessageListState extends State<ChatMessageList> {
return ChatMessageWidget(
key: Key(message.uuid),
message,
_scrollController,
).animate().fadeIn(duration: 300.ms).move(
begin: const Offset(-16, 0),
curve: Curves.easeOutQuad,
Expand Down
6 changes: 5 additions & 1 deletion app/lib/frontend/widgets/markdown_body.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import 'package:url_launcher/url_launcher.dart';

class MarkdownBodyWidget extends StatelessWidget {
final String message;
final ScrollController scrollController;

const MarkdownBodyWidget(
this.message, {
this.message,
this.scrollController, {
super.key,
});

Expand All @@ -37,6 +39,7 @@ class MarkdownBodyWidget extends StatelessWidget {
child,
code,
language,
scrollController,
),
)
: const PreConfig().copy(
Expand All @@ -46,6 +49,7 @@ class MarkdownBodyWidget extends StatelessWidget {
child,
code,
language,
scrollController,
),
),
LinkConfig(
Expand Down
128 changes: 56 additions & 72 deletions app/lib/frontend/widgets/markdown_code_wrapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:gap/gap.dart';
import 'package:open_local_ui/core/asset.dart';
import 'package:open_local_ui/core/snackbar.dart';
import 'package:unicons/unicons.dart';
import 'package:flutter_sticky_widgets/flutter_sticky_widgets.dart';

Map<String, String> languageToAsset = {
'apache': 'assets/graphics/logos/apache.svg',
Expand Down Expand Up @@ -70,11 +71,13 @@ class MarkdownCodeWrapperWidget extends StatefulWidget {
final Widget child;
final String text;
final String language;
final ScrollController scrollController;

const MarkdownCodeWrapperWidget(
this.child,
this.text,
this.language, {
this.language,
this.scrollController, {
super.key,
});

Expand Down Expand Up @@ -108,7 +111,8 @@ class _CodeWrapperState extends State<MarkdownCodeWrapperWidget> {
Future<void> _saveFile() async {
setState(() => _isSaved = true);

final String? selectedDirectory = await FilePicker.platform.getDirectoryPath();
final String? selectedDirectory =
await FilePicker.platform.getDirectoryPath();

if (selectedDirectory != null) {
const String fileName = 'code_snippet.txt';
Expand Down Expand Up @@ -136,86 +140,66 @@ class _CodeWrapperState extends State<MarkdownCodeWrapperWidget> {
});
}

Size _getMarkdownBodySize(BuildContext context) {
final RenderBox renderBox =
context.findAncestorRenderObjectOfType() as RenderBox;

return renderBox.size;
}

@override
Widget build(BuildContext context) {
return Stack(
children: [
widget.child,
Align(
alignment: Alignment.topRight,
child: Padding(
padding: const EdgeInsets.only(
top: 16,
right: 8,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.language.isNotEmpty)
if (languageToAsset.containsKey(widget.language))
Tooltip(
message: widget.language.toUpperCase(),
child: SvgPicture.memory(
AssetManager.getAsset(
languageToAsset[widget.language]!,
type: AssetType.binary,
),
width: 20,
height: 20,
// ignore: deprecated_member_use
color: AdaptiveTheme.of(context).mode.isDark
? Colors.white
: Colors.black,
),
),
if (widget.language.isNotEmpty)
if (!languageToAsset.containsKey(widget.language))
SelectionContainer.disabled(
child: Text(
widget.language.toUpperCase(),
style: const TextStyle(
fontWeight: FontWeight.bold,
),
StickyWidget(
initialPosition: StickyPosition(top: 16, right: 16),
finalPosition: StickyPosition(
top: _getMarkdownBodySize(context).height - 56,
right: 16,
),
controller: widget.scrollController,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.language.isNotEmpty)
if (languageToAsset.containsKey(widget.language))
Tooltip(
message: widget.language.toUpperCase(),
child: SvgPicture.memory(
AssetManager.getAsset(
languageToAsset[widget.language]!,
type: AssetType.binary,
),
),
const Gap(16.0),
InkWell(
onTap: () => _copyMessage(),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
transitionBuilder: (
Widget child,
Animation<double> animation,
) {
return ScaleTransition(scale: animation, child: child);
},
child: Icon(
_isCopied ? UniconsLine.check : UniconsLine.copy,
key: ValueKey<bool>(_isCopied),
size: 24,
width: 20,
height: 20,
// ignore: deprecated_member_use
color: AdaptiveTheme.of(context).mode.isDark
? Colors.white
: Colors.black,
),
),
),
const Gap(16.0),
InkWell(
onTap: () => _saveFile(),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
transitionBuilder: (
Widget child,
Animation<double> animation,
) {
return ScaleTransition(scale: animation, child: child);
},
child: Icon(
_isSaved ? UniconsLine.check : UniconsLine.save,
key: ValueKey<bool>(_isSaved),
size: 24,
if (widget.language.isNotEmpty)
if (!languageToAsset.containsKey(widget.language))
SelectionContainer.disabled(
child: Text(
widget.language.toUpperCase(),
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
),
),
],
),
const Gap(24.0),
IconButton(
onPressed: () => _copyMessage(),
icon: Icon(_isCopied ? UniconsLine.check : UniconsLine.copy),
),
const Gap(16.0),
IconButton(
onPressed: () => _saveFile(),
icon: Icon(_isSaved ? UniconsLine.check : UniconsLine.save),
),
],
),
),
],
Expand Down
8 changes: 8 additions & 0 deletions app/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.2.1"
flutter_sticky_widgets:
dependency: "direct main"
description:
name: flutter_sticky_widgets
sha256: d0624d3aec3f6acc25993515073c82233efcd658fa5a94818a212da97ee02c6f
url: "https://pub.dev"
source: hosted
version: "0.0.3"
flutter_svg:
dependency: "direct main"
description:
Expand Down
1 change: 1 addition & 0 deletions app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ dependencies:

# Dependency Injection
get_it: ^7.7.0
flutter_sticky_widgets: ^0.0.3

dev_dependencies:
flutter_test:
Expand Down

0 comments on commit aff3b0f

Please sign in to comment.