Skip to content
Merged
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
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ Thanks to the people who have contributed fixes, testing, and improvements to Co
- [dorokuma](https://github.com/dorokuma)
- Fixed Android on-screen keyboard behavior for TUI apps in `conduit_vt`.
- Fixed terminal layout distortion on app resume.
- Added optional terminal mouse tap forwarding.
- Added README.zh.md, translation of README.md.
- Updated Readme.zh.md to include acknowledgments etc.
3 changes: 3 additions & 0 deletions fastlane/metadata/android/en-US/changelogs/391.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Terminal: optional mouse tap forwarding can now be enabled from Appearance for terminal apps that use mouse tracking.
Terminal: choose whether Enter sends CR, LF, or CRLF from Appearance.
Terminal: fixed fish prompt underline artifacts and clear-screen spacing.
3 changes: 3 additions & 0 deletions fastlane/metadata/android/en-US/changelogs/392.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Terminal: optional mouse tap forwarding can now be enabled from Appearance for terminal apps that use mouse tracking.
Terminal: choose whether Enter sends CR, LF, or CRLF from Appearance.
Terminal: fixed fish prompt underline artifacts and clear-screen spacing.
3 changes: 3 additions & 0 deletions fastlane/metadata/android/en-US/changelogs/393.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Terminal: optional mouse tap forwarding can now be enabled from Appearance for terminal apps that use mouse tracking.
Terminal: choose whether Enter sends CR, LF, or CRLF from Appearance.
Terminal: fixed fish prompt underline artifacts and clear-screen spacing.
69 changes: 69 additions & 0 deletions lib/core/presentation/theme_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,75 @@ class _TerminalAppearanceControls extends StatelessWidget {
),
),
const SizedBox(height: 14),
Material(
color: colorScheme.surface,
shape: RoundedRectangleBorder(
side: BorderSide(color: colorScheme.outlineVariant),
borderRadius: BorderRadius.circular(14),
),
clipBehavior: Clip.antiAlias,
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 14, 16, 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.keyboard_return_rounded, size: 20),
const SizedBox(width: 10),
Text('Enter sends', style: theme.textTheme.titleSmall),
],
),
const SizedBox(height: 6),
Text(
controller.terminalEnterSequence.description,
style: theme.textTheme.bodySmall?.copyWith(
color: colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: SegmentedButton<TerminalEnterSequence>(
segments: [
for (final sequence in TerminalEnterSequence.values)
ButtonSegment<TerminalEnterSequence>(
value: sequence,
label: Text(sequence.label),
),
],
selected: {controller.terminalEnterSequence},
onSelectionChanged: (selection) {
controller.setTerminalEnterSequence(selection.single);
},
),
),
],
),
),
),
const SizedBox(height: 14),
Material(
color: colorScheme.surface,
shape: RoundedRectangleBorder(
side: BorderSide(color: colorScheme.outlineVariant),
borderRadius: BorderRadius.circular(14),
),
clipBehavior: Clip.antiAlias,
child: SwitchListTile(
secondary: const Icon(Icons.mouse_rounded),
title: const Text('Send mouse taps'),
subtitle: Text(
'Forward terminal taps as mouse clicks when apps enable mouse tracking.',
style: theme.textTheme.bodySmall?.copyWith(
color: colorScheme.onSurfaceVariant,
),
),
value: controller.terminalMouseInput,
onChanged: controller.setTerminalMouseInput,
),
),
const SizedBox(height: 14),
Container(
padding: const EdgeInsets.fromLTRB(14, 12, 14, 12),
decoration: BoxDecoration(
Expand Down
22 changes: 22 additions & 0 deletions lib/core/theme/terminal_appearance.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
enum TerminalFontOption { systemMonospace, atkynsonNerdFont }

enum TerminalEnterSequence { cr, lf, crlf }

const terminalFontSizeDefault = 13.5;
const terminalFontSizeMin = 4.0;
const terminalFontSizeMax = 30.0;
Expand Down Expand Up @@ -28,6 +30,26 @@ extension TerminalFontOptionDetails on TerminalFontOption {
};
}

extension TerminalEnterSequenceDetails on TerminalEnterSequence {
String get label => switch (this) {
TerminalEnterSequence.cr => 'CR',
TerminalEnterSequence.lf => 'LF',
TerminalEnterSequence.crlf => 'CRLF',
};

String get description => switch (this) {
TerminalEnterSequence.cr => 'Carriage return',
TerminalEnterSequence.lf => 'Line feed',
TerminalEnterSequence.crlf => 'Carriage return + line feed',
};

String get value => switch (this) {
TerminalEnterSequence.cr => '\r',
TerminalEnterSequence.lf => '\n',
TerminalEnterSequence.crlf => '\r\n',
};
}

enum TerminalKeyboardAction {
escape,
control,
Expand Down
26 changes: 26 additions & 0 deletions lib/core/theme/theme_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ class ThemeController extends ChangeNotifier {
List<TerminalKeyboardRow> _terminalKeyboardRows = defaultTerminalKeyboardRows;
List<TerminalSnippet> _terminalSnippets = const [];
bool _showLocalShell = true;
bool _terminalMouseInput = false;
TerminalEnterSequence _terminalEnterSequence = TerminalEnterSequence.cr;

ThemeMode get themeMode => _themeMode;
AppPalette get palette => _palette;
Expand All @@ -26,6 +28,8 @@ class ThemeController extends ChangeNotifier {
List<TerminalSnippet> get terminalSnippets =>
List.unmodifiable(_terminalSnippets);
bool get showLocalShell => _showLocalShell;
bool get terminalMouseInput => _terminalMouseInput;
TerminalEnterSequence get terminalEnterSequence => _terminalEnterSequence;

Future<void> load() async {
final preferences = await _repository.load();
Expand All @@ -36,6 +40,8 @@ class ThemeController extends ChangeNotifier {
_terminalKeyboardRows = List.of(preferences.terminalKeyboardRows);
_terminalSnippets = List.of(preferences.terminalSnippets);
_showLocalShell = preferences.showLocalShell;
_terminalMouseInput = preferences.terminalMouseInput;
_terminalEnterSequence = preferences.terminalEnterSequence;
notifyListeners();
}

Expand Down Expand Up @@ -140,6 +146,24 @@ class ThemeController extends ChangeNotifier {
await _save();
}

Future<void> setTerminalMouseInput(bool enabled) async {
if (_terminalMouseInput == enabled) {
return;
}
_terminalMouseInput = enabled;
notifyListeners();
await _save();
}

Future<void> setTerminalEnterSequence(TerminalEnterSequence sequence) async {
if (_terminalEnterSequence == sequence) {
return;
}
_terminalEnterSequence = sequence;
notifyListeners();
await _save();
}

Future<void> _save() {
return _repository.save(
ThemePreferences(
Expand All @@ -150,6 +174,8 @@ class ThemeController extends ChangeNotifier {
terminalKeyboardRows: _terminalKeyboardRows,
terminalSnippets: _terminalSnippets,
showLocalShell: _showLocalShell,
terminalMouseInput: _terminalMouseInput,
terminalEnterSequence: _terminalEnterSequence,
),
);
}
Expand Down
25 changes: 25 additions & 0 deletions lib/core/theme/theme_preferences_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class ThemePreferences {
this.terminalKeyboardRows = defaultTerminalKeyboardRows,
this.terminalSnippets = const [],
this.showLocalShell = true,
this.terminalMouseInput = false,
this.terminalEnterSequence = TerminalEnterSequence.cr,
});

final ThemeMode themeMode;
Expand All @@ -24,6 +26,8 @@ class ThemePreferences {
final List<TerminalKeyboardRow> terminalKeyboardRows;
final List<TerminalSnippet> terminalSnippets;
final bool showLocalShell;
final bool terminalMouseInput;
final TerminalEnterSequence terminalEnterSequence;
}

class ThemePreferencesRepository {
Expand All @@ -40,6 +44,8 @@ class ThemePreferencesRepository {
'conduit.terminal_keyboard_seen_actions.v1';
static const _terminalSnippetsKey = 'conduit.terminal_snippets.v1';
static const _showLocalShellKey = 'conduit.show_local_shell.v1';
static const _terminalMouseInputKey = 'conduit.terminal_mouse_input.v1';
static const _terminalEnterSequenceKey = 'conduit.terminal_enter_sequence.v1';

final FlutterSecureStorage _storage;

Expand All @@ -59,6 +65,12 @@ class ThemePreferencesRepository {
);
final rawTerminalSnippets = await _storage.read(key: _terminalSnippetsKey);
final rawShowLocalShell = await _storage.read(key: _showLocalShellKey);
final rawTerminalMouseInput = await _storage.read(
key: _terminalMouseInputKey,
);
final rawTerminalEnterSequence = await _storage.read(
key: _terminalEnterSequenceKey,
);
final terminalFontSize = double.tryParse(rawTerminalFontSize ?? '');
final terminalKeyboardRows = _appendUnseenBuiltIns(
_parseTerminalKeyboardRows(
Expand Down Expand Up @@ -87,6 +99,11 @@ class ThemePreferencesRepository {
terminalKeyboardRows: terminalKeyboardRows,
terminalSnippets: _parseTerminalSnippets(rawTerminalSnippets),
showLocalShell: rawShowLocalShell == null || rawShowLocalShell == 'true',
terminalMouseInput: rawTerminalMouseInput == 'true',
terminalEnterSequence: TerminalEnterSequence.values.firstWhere(
(sequence) => sequence.name == rawTerminalEnterSequence,
orElse: () => TerminalEnterSequence.cr,
),
);
}

Expand Down Expand Up @@ -129,6 +146,14 @@ class ThemePreferencesRepository {
key: _showLocalShellKey,
value: preferences.showLocalShell.toString(),
);
await _storage.write(
key: _terminalMouseInputKey,
value: preferences.terminalMouseInput.toString(),
);
await _storage.write(
key: _terminalEnterSequenceKey,
value: preferences.terminalEnterSequence.name,
);
}

List<TerminalSnippet> _parseTerminalSnippets(String? raw) {
Expand Down
12 changes: 12 additions & 0 deletions lib/features/backup/data/app_backup_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ class AppBackupService {
(includeSecrets ? snippet : _snippetForBackup(snippet)).toJson(),
],
'showLocalShell': _themeController.showLocalShell,
'terminalMouseInput': _themeController.terminalMouseInput,
'terminalEnterSequence': _themeController.terminalEnterSequence.name,
};
}

Expand Down Expand Up @@ -189,6 +191,16 @@ class AppBackupService {
if (showLocalShell is bool) {
await _themeController.setShowLocalShell(showLocalShell);
}
final terminalMouseInput = json['terminalMouseInput'];
if (terminalMouseInput is bool) {
await _themeController.setTerminalMouseInput(terminalMouseInput);
}
await _themeController.setTerminalEnterSequence(
TerminalEnterSequence.values.firstWhere(
(sequence) => sequence.name == json['terminalEnterSequence'],
orElse: () => _themeController.terminalEnterSequence,
),
);
}

Map<String, Object?> _decodeDocument(Uint8List bytes) {
Expand Down
4 changes: 2 additions & 2 deletions lib/features/hosts/domain/saved_host.dart
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,10 @@ class SavedHost {
this.isLocal = false,
});

factory SavedHost.localShell({required String id}) {
factory SavedHost.localShell({required String id, required String name}) {
return SavedHost(
id: id,
name: 'Arch Linux',
name: name,
host: 'localhost',
port: 0,
username: 'root',
Expand Down
Loading