Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions pkgs/dartpad_ui/lib/app/genai_editing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class EditorWithButtons extends StatefulWidget {
this.showCodeEditTool = true,
required this.appModel,
required this.appServices,
required this.onCopy,
required this.onFormat,
required this.onCompileAndRun,
required this.onCompileAndReload,
Expand All @@ -35,6 +36,7 @@ class EditorWithButtons extends StatefulWidget {
final bool showCodeEditTool;
final AppModel appModel;
final AppServices appServices;
final VoidCallback onCopy;
final VoidCallback onFormat;
final VoidCallback onCompileAndRun;
final VoidCallback onCompileAndReload;
Expand Down Expand Up @@ -127,6 +129,7 @@ class _EditorWithButtonsState extends State<EditorWithButtons> {
child: _EditingArea(
widget.appModel,
widget.appServices,
onCopy: widget.onCopy,
onFormat: widget.onFormat,
onCompileAndReload: widget.onCompileAndReload,
onCompileAndRun: widget.onCompileAndRun,
Expand Down Expand Up @@ -658,13 +661,15 @@ class _EditingArea extends StatelessWidget {
const _EditingArea(
this.appModel,
this.appServices, {
required this.onCopy,
required this.onFormat,
required this.onCompileAndReload,
required this.onCompileAndRun,
});

final AppModel appModel;
final AppServices appServices;
final VoidCallback onCopy;
final VoidCallback onFormat;
final VoidCallback onCompileAndReload;
final VoidCallback onCompileAndRun;
Expand Down Expand Up @@ -704,6 +709,16 @@ class _EditingArea extends StatelessWidget {
},
),
const SizedBox(width: denseSpacing),
// Copy button
PointerInterceptor(
child: MiniIconButton(
icon: const Icon(Icons.content_copy),
tooltip: 'Copy code to clipboard',
small: true,
onPressed: onCopy,
),
),
const SizedBox(width: denseSpacing),
// Format button
ValueListenableBuilder<bool>(
valueListenable: appModel.formattingBusy,
Expand Down
14 changes: 14 additions & 0 deletions pkgs/dartpad_ui/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'dart:async';
import 'package:dartpad_shared/services.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_web_plugins/url_strategy.dart' show usePathUrlStrategy;
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
Expand Down Expand Up @@ -358,6 +359,7 @@ class DartPadMainPageState extends State<DartPadMainPage>
final editor = EditorWithButtons(
appModel: appModel,
appServices: appServices,
onCopy: _handleCopy,
onFormat: _handleFormatting,
onCompileAndRun: appServices.performCompileAndRun,
onCompileAndReload: appServices.performCompileAndReload,
Expand Down Expand Up @@ -522,6 +524,18 @@ class DartPadMainPageState extends State<DartPadMainPage>
);
}

// TODO: Check if platform permission specific error needs to be handled.
Future<void> _handleCopy() async {
try {
final source = appModel.sourceCodeController.text;
await Clipboard.setData(ClipboardData(text: source));
appModel.editorStatus.showToast('Code copied to clipboard');
} catch (error) {
appModel.editorStatus.showToast('Error copying code');
appModel.appendError('Copy issue: $error');
}
}

Future<void> _handleFormatting() async {
try {
final source = appModel.sourceCodeController.text;
Expand Down