Skip to content

Commit 959248c

Browse files
committed
Added select for multi line
1 parent ed14e03 commit 959248c

File tree

3 files changed

+71
-39
lines changed

3 files changed

+71
-39
lines changed

lib/src/modules/sandbox/components/terminal.dart lib/src/modules/sandbox/components/sandbox_terminal.dart

+40-31
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'package:flutter/cupertino.dart';
21
import 'package:flutter/material.dart';
32
import 'package:flutter/services.dart';
43
import 'package:flutter_hooks/flutter_hooks.dart';
@@ -7,15 +6,14 @@ import 'package:fvm/fvm.dart';
76
import 'package:hooks_riverpod/hooks_riverpod.dart';
87
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
98

10-
import '../../../components/atoms/typography.dart';
119
import '../../../modules/common/dto/release.dto.dart';
1210
import '../../../modules/common/utils/notify.dart';
1311
import '../sandbox.provider.dart';
1412

1513
/// Sandbox terminal
16-
class SandboxConsole extends HookWidget {
14+
class SandboxTerminal extends HookWidget {
1715
/// Constructor
18-
const SandboxConsole({
16+
const SandboxTerminal({
1917
this.project,
2018
this.release,
2119
Key key,
@@ -41,23 +39,21 @@ class SandboxConsole extends HookWidget {
4139

4240
final processing = terminalState.processing;
4341

44-
void submitCmd(
42+
void onSubmit(
4543
String value,
46-
) async {
44+
) {
4745
try {
4846
/// Don't do anything if its empty
4947
if (value.isEmpty) return;
5048
// Reset command index
5149
currentCmdIdx.value = 0;
5250
// Add to the beginning of list
5351
textController.clear();
54-
await terminal.sendIsolate(
52+
terminal.sendIsolate(
5553
value,
5654
release,
5755
project,
5856
);
59-
// Clear controller
60-
scrollController.jumpTo(0);
6157
} on Exception catch (e) {
6258
notifyError(e.toString());
6359
}
@@ -79,6 +75,20 @@ class SandboxConsole extends HookWidget {
7975
}
8076
}, [processing]);
8177

78+
useEffect(() {
79+
/// Scroll to bottom
80+
if (scrollController.hasClients) {
81+
WidgetsBinding.instance.addPostFrameCallback((_) {
82+
scrollController.animateTo(
83+
scrollController.position.maxScrollExtent,
84+
duration: Duration(milliseconds: 250),
85+
curve: Curves.ease,
86+
);
87+
});
88+
}
89+
return;
90+
}, [terminalState.lines]);
91+
8292
void moveCmdIndex(int step) {
8393
final cmds = terminalState.cmdHistory;
8494
final currentIdx = currentCmdIdx.value;
@@ -108,7 +118,7 @@ class SandboxConsole extends HookWidget {
108118
});
109119
}
110120

111-
void handleKey(RawKeyEvent key) {
121+
void handlekeyDown(RawKeyEvent key) {
112122
if (key.runtimeType.toString() == 'RawKeyDownEvent') {
113123
if (key.data.logicalKey == LogicalKeyboardKey.arrowUp) {
114124
if (terminalState.cmdHistory.length > currentCmdIdx.value) {
@@ -124,27 +134,26 @@ class SandboxConsole extends HookWidget {
124134
}
125135

126136
return Column(
137+
crossAxisAlignment: CrossAxisAlignment.stretch,
127138
children: [
128139
Expanded(
129-
child: CupertinoScrollbar(
130-
child: ListView.builder(
131-
controller: scrollController,
132-
reverse: true,
133-
padding: const EdgeInsets.fromLTRB(20, 10, 20, 10),
134-
itemCount: terminalState.lines.length,
135-
itemBuilder: (context, index) {
136-
final line = terminalState.lines[index];
137-
switch (line.type) {
138-
case OutputType.stderr:
139-
return ConsoleTextError(line.text);
140-
case OutputType.info:
141-
return ConsoleTextInfo(line.text);
142-
case OutputType.stdout:
143-
return ConsoleText(line.text);
144-
default:
145-
return Container();
146-
}
147-
},
140+
child: SingleChildScrollView(
141+
primary: false,
142+
controller: scrollController,
143+
child: Padding(
144+
padding: const EdgeInsets.all(8.0),
145+
child: SelectableText.rich(
146+
TextSpan(
147+
children: terminalState.lines
148+
.map(
149+
(e) => TextSpan(
150+
text: '${e.text}\n',
151+
style: e.style,
152+
),
153+
)
154+
.toList(),
155+
),
156+
),
148157
),
149158
),
150159
),
@@ -155,12 +164,12 @@ class SandboxConsole extends HookWidget {
155164
Expanded(
156165
child: RawKeyboardListener(
157166
focusNode: keyListenerFocus,
158-
onKey: handleKey,
167+
onKey: handlekeyDown,
159168
child: TextField(
160169
focusNode: focus,
161170
enabled: !terminalState.processing,
162171
controller: textController,
163-
onSubmitted: submitCmd,
172+
onSubmitted: onSubmit,
164173
decoration: const InputDecoration(
165174
icon: Icon(MdiIcons.chevronRight),
166175
border: InputBorder.none,

lib/src/modules/sandbox/sandbox.provider.dart

+29-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import 'dart:async';
22
import 'dart:isolate';
33

4+
import 'package:flutter/material.dart';
45
import 'package:fvm/fvm.dart';
56
import 'package:hooks_riverpod/hooks_riverpod.dart';
67

78
import '../../modules/common/dto/release.dto.dart';
89
import '../../modules/common/utils/notify.dart';
910
import 'terminal_processor.dart';
1011

12+
//TODO: Refactor file and reorganize providers and helpers
1113
/// Sandbox terminal state
1214
class TerminalState {
1315
/// Constructor
@@ -46,7 +48,7 @@ class TerminalState {
4648
}
4749

4850
void addConsoleLine(ConsoleLine line) {
49-
lines.insert(0, line);
51+
lines.add(line);
5052
}
5153

5254
void addLine(String text) {
@@ -73,7 +75,7 @@ class TerminalState {
7375

7476
TerminalState copy() {
7577
return TerminalState(
76-
lines: lines,
78+
lines: [...lines],
7779
processing: processing,
7880
cmdHistory: _cmdHistory,
7981
);
@@ -95,6 +97,27 @@ class ConsoleLine {
9597
this.text,
9698
});
9799

100+
TextStyle get style {
101+
final style = TextStyle(
102+
fontSize: 12,
103+
color: Colors.grey,
104+
);
105+
106+
if (type == OutputType.stderr) {
107+
return style.copyWith(
108+
color: Colors.deepOrange,
109+
);
110+
}
111+
112+
if (type == OutputType.info) {
113+
return style.copyWith(
114+
color: Colors.white,
115+
);
116+
}
117+
118+
return style;
119+
}
120+
98121
factory ConsoleLine.empty() {
99122
return ConsoleLine(text: '');
100123
}
@@ -204,14 +227,14 @@ class SandboxStateNotifier extends StateNotifier<TerminalState> {
204227
// Send command to terminal
205228
if (!supressCmdOutput) {
206229
// Add to command history
207-
//
230+
208231
state.addToHistory(cmd);
209232
state.addLine('\n$cmd\n');
210233
}
211234

212235
// Set to processing
213-
state.processing = true;
214236
// Notify listeners
237+
state.processing = true;
215238
_notifyListeners();
216239
// Receiver port for isolate
217240
final receivePort = ReceivePort();
@@ -235,9 +258,9 @@ class SandboxStateNotifier extends StateNotifier<TerminalState> {
235258
receivePort.close();
236259
_killIsolate();
237260
} else {
238-
state.lines = [line, ...state.lines];
239-
_notifyListeners();
261+
state.lines = [...state.lines, line];
240262
}
263+
_notifyListeners();
241264
}
242265
} on Exception catch (e) {
243266
notifyError(e.toString());

lib/src/modules/sandbox/sandbox.screen.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart
99
import '../../components/atoms/typography.dart';
1010
import '../../modules/common/dto/release.dto.dart';
1111
import '../releases/releases.provider.dart';
12-
import 'components/terminal.dart';
12+
import 'components/sandbox_terminal.dart';
1313
import 'sandbox.provider.dart';
1414

1515
/// Sandbox screen
@@ -177,7 +177,7 @@ class SandboxScreen extends HookWidget {
177177
),
178178
const Divider(height: 1),
179179
Expanded(
180-
child: SandboxConsole(
180+
child: SandboxTerminal(
181181
project: project,
182182
release: selectedRelease.value,
183183
),

0 commit comments

Comments
 (0)