Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

files: Implement selections using shift key #17

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
83 changes: 83 additions & 0 deletions lib/backend/entity_selector.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import 'package:files/backend/entity_info.dart';
import 'package:files/backend/workspace.dart';
import 'package:flutter/services.dart';

enum EntitySelectionMode {
single,
multiple,
none,
mixed;

factory EntitySelectionMode.fromKeys(Set<LogicalKeyboardKey> keys) {
final hasShiftKey = keys.contains(LogicalKeyboardKey.shiftLeft) ||
keys.contains(LogicalKeyboardKey.shiftRight);
final hasControlKey = keys.contains(LogicalKeyboardKey.controlLeft) ||
keys.contains(LogicalKeyboardKey.controlRight);

if (hasShiftKey && hasControlKey) {
return mixed;
}

if (hasControlKey) {
return single;
}

if (hasShiftKey) {
return multiple;
}

return none;
}
}

class EntitySelector {
final WorkspaceController _controller;
final EntityInfo _entity;
final EntitySelectionMode _mode;

EntitySelector(this._controller, this._entity, this._mode);

void perform() {
switch (_mode) {
case EntitySelectionMode.single:
_toggleEntitySelection();
_controller.lastClickedEntityIndex = _getEntityIndex();
break;
case EntitySelectionMode.multiple:
_controller.clearSelectedItems();
_extendSelectionToEntity();
break;
case EntitySelectionMode.mixed:
_extendSelectionToEntity();
break;
default:
_controller.clearSelectedItems();
_controller.addSelectedItem(_entity);
_controller.lastClickedEntityIndex = _getEntityIndex();
}
}

void _toggleEntitySelection() {
if (_controller.selectedItems.contains(_entity)) {
_controller.removeSelectedItem(_entity);
} else {
_controller.addSelectedItem(_entity);
}
}

void _extendSelectionToEntity() {
final entityIndex = _getEntityIndex();
final lastSelectedEntityIndex = _controller.lastClickedEntityIndex;
final entities = entityIndex < lastSelectedEntityIndex
? _controller.currentInfo!
.sublist(entityIndex, lastSelectedEntityIndex + 1)
: _controller.currentInfo!
.sublist(lastSelectedEntityIndex, entityIndex + 1);

_controller.addSelectedItems(entities);
}

int _getEntityIndex() {
return _controller.currentInfo!.indexOf(_entity);
}
}
14 changes: 13 additions & 1 deletion lib/backend/workspace.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class WorkspaceController with ChangeNotifier {
SortType _sortType = SortType.name;
WorkspaceView _view = WorkspaceView.table; // save on SharedPreferences?
final List<EntityInfo> _selectedItems = [];
int lastClickedEntityIndex = 0;

// States
late TableViewState _tableState;
Expand Down Expand Up @@ -130,6 +131,11 @@ class WorkspaceController with ChangeNotifier {
notifyListeners();
}

void addSelectedItems(Iterable<EntityInfo> infos) {
_selectedItems.addAll(infos);
notifyListeners();
}

void removeSelectedItem(EntityInfo info) {
_selectedItems.remove(info);
notifyListeners();
Expand All @@ -140,6 +146,12 @@ class WorkspaceController with ChangeNotifier {
notifyListeners();
}

void resetSelection() {
lastClickedEntityIndex = 0;
_selectedItems.clear();
notifyListeners();
}

List<String> get history => List.from(_history);
int get historyOffset => _historyOffset;

Expand All @@ -163,7 +175,7 @@ class WorkspaceController with ChangeNotifier {
}

clearCurrentInfo();
clearSelectedItems();
resetSelection();
await _directoryStream?.cancel();
await getInfoForDir(Directory(newDir));
_directoryStream =
Expand Down
2 changes: 1 addition & 1 deletion lib/widgets/grid.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class _FilesGridState extends State<FilesGrid> {
final WorkspaceController controller = WorkspaceController.of(context);

return GestureDetector(
onTap: controller.clearSelectedItems,
onTap: controller.resetSelection,
child: Scrollbar(
controller: scrollController,
child: GridView.builder(
Expand Down
2 changes: 1 addition & 1 deletion lib/widgets/table.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class FilesTable extends StatelessWidget {
return LayoutBuilder(
builder: (context, constraints) {
return GestureDetector(
onTap: () => controller.clearSelectedItems(),
onTap: () => controller.resetSelection(),
child: DoubleScrollbars(
horizontalController: horizontalController,
verticalController: verticalController,
Expand Down
31 changes: 11 additions & 20 deletions lib/widgets/workspace.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:io';

import 'package:collection/collection.dart';
import 'package:files/backend/entity_info.dart';
import 'package:files/backend/entity_selector.dart';
import 'package:files/backend/fetch.dart';
import 'package:files/backend/path_parts.dart';
import 'package:files/backend/utils.dart';
Expand Down Expand Up @@ -135,25 +136,15 @@ class _FilesWorkspaceState extends State<FilesWorkspace> {
}

void _onEntityTap(EntityInfo entity) {
final bool selected = controller.selectedItems.contains(entity);
final Set<LogicalKeyboardKey> keysPressed =
RawKeyboard.instance.keysPressed;
final bool multiSelect = keysPressed.contains(
LogicalKeyboardKey.controlLeft,
) ||
keysPressed.contains(
LogicalKeyboardKey.controlRight,
);

if (!multiSelect) controller.clearSelectedItems();
final selectionMode = EntitySelectionMode.fromKeys(
HardwareKeyboard.instance.logicalKeysPressed,
);

if (!selected && multiSelect) {
controller.addSelectedItem(entity);
} else if (selected && multiSelect) {
controller.removeSelectedItem(entity);
} else {
controller.addSelectedItem(entity);
}
EntitySelector(
controller,
entity,
selectionMode,
).perform();

setState(() {});
}
Expand Down Expand Up @@ -263,7 +254,7 @@ class _FilesWorkspaceState extends State<FilesWorkspace> {
SizedBox(
height: 32,
child: Material(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
Expand Down Expand Up @@ -299,7 +290,7 @@ class _FilesWorkspaceState extends State<FilesWorkspace> {
Text(
"This Folder is Empty",
style: TextStyle(fontSize: 17),
)
),
],
),
);
Expand Down
14 changes: 7 additions & 7 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,10 @@ packages:
dependency: "direct main"
description:
name: collection
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.17.1"
version: "1.18.0"
convert:
dependency: transitive
description:
Expand Down Expand Up @@ -343,10 +343,10 @@ packages:
dependency: transitive
description:
name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "0.8.0"
material_design_icons_flutter:
dependency: "direct main"
description:
Expand All @@ -359,10 +359,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: "12307e7f0605ce3da64cf0db90e5fcab0869f3ca03f76be6bb2991ce0a55e82b"
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
version: "1.12.0"
mime:
dependency: "direct main"
description:
Expand Down Expand Up @@ -746,5 +746,5 @@ packages:
source: hosted
version: "3.1.1"
sdks:
dart: ">=3.0.0-134.0.dev <4.0.0"
dart: ">=3.3.0-0 <4.0.0"
flutter: ">=3.3.0"