Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
Release 0.7.0
  • Loading branch information
TNorbury committed Jan 22, 2023
2 parents 1101ddf + ef1c549 commit 1095d42
Show file tree
Hide file tree
Showing 8 changed files with 331 additions and 93 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
with:
path: /opt/hostedtoolcache/flutter
key: ${{ github.ref }}-${{ env.flutter_version }}
- uses: subosito/flutter-action@v1
- uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.flutter_version }}
- name: Install Dependencies
Expand All @@ -53,7 +53,7 @@ jobs:
with:
path: /opt/hostedtoolcache/flutter
key: ${{ github.ref }}-${{ env.flutter_version }}
- uses: subosito/flutter-action@v1
- uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.flutter_version }}
- name: Install Dependencies
Expand Down
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.7.0 - 2023-01-22
### Added
- Scroll to highlighted action

### Changed
- default item builder is now fixed height

## 0.6.1 - 2022-12-15
### Added
- Added `CommandPaletteStyle.barrierFilter`, which is an optional `ImageFilter` which can be used to add an effect (usually a blurring) behind the command palette when it's open
Expand All @@ -17,7 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## 0.6.0 - 2022-12-10
### Fixed
- Semi-Breaking: Changed the type of `CommandPaletteConfig.openKeySet` and `CommandPaletteConfig.closeKeySet` from `LogicalKeySet` to `ShortcutActivator` (note: `LogicalKeySet` already implements `ShortcutActivator`, so existing custom shortcuts should still work, but a proposed solution is discussed below). This was done to fix an issue on Web builds for MacOS (discussed [here](https://github.com/TNorbury/command_palette/issues/22)). If you don't set custom values for the open and close key sets (or if you're not targeting Web), then no change will be required on your part. But if you are, the following change is suggested to make sure everything works well: If you're opening the palette with a keyboard shortcut, such as CTRL/CMD+U, then you could go from `LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyU)`/`LogicalKeySet(LogicalKeyboardKey.meta, LogicalKeyboardKey.keyU)` to `SingleActivator(LogicalKeyboardKey.keyU, control: true)`/`SingleActivator(LogicalKeyboardKey.keyU, meta: true)`. This also changes how the command palette control shortcuts (Up/down/enter/backspace) are handled (from `LogicalKeySet` to `SingleActivator`). This should make things a bit cleaner on my end, and more stable going forward.
- Escape query correctly so that single a '\\' don't cause filtering to crash
- Escape query correctly so that single a backslash doesn't cause filtering to crash

## 0.5.1 - 2022-12-02
### Added
Expand Down
4 changes: 3 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:math';
import 'package:command_palette/command_palette.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_lorem/flutter_lorem.dart';

void main() {
runApp(const MyApp());
Expand Down Expand Up @@ -145,8 +146,9 @@ class _MyHomePageState extends State<MyHomePage> {
});
},
),
// for (int i = 0; i < 10; i++)
// for (int i = 0; i < 1000; i++)
// CommandPaletteAction(
// leading: Text("$i"),
// label: lorem(paragraphs: 1, words: 3),
// actionType: CommandPaletteActionType.single,
// onSelect: () {},
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.6.1"
version: "0.7.0"
fake_async:
dependency: transitive
description:
Expand Down
252 changes: 166 additions & 86 deletions lib/src/widgets/options/command_palette_body.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,65 @@ import 'package:command_palette/src/widgets/options/option_highlighter.dart';
import 'package:flutter/material.dart';
import 'package:substring_highlight/substring_highlight.dart';

const double itemHeight = 52;

/// Displays all the available [CommandPaletteAction] options based upon various
/// filtering criteria.
/// Also displays [CommandPaletteInstructions] if that's enabled
class CommandPaletteBody extends StatelessWidget {
class CommandPaletteBody extends StatefulWidget {
const CommandPaletteBody({
Key? key,
}) : super(key: key);

@override
State<CommandPaletteBody> createState() => _CommandPaletteBodyState();
}

class _CommandPaletteBodyState extends State<CommandPaletteBody> {
final ScrollController _scrollController = ScrollController();

@override
void didChangeDependencies() {
super.didChangeDependencies();

final idx = CommandPaletteControllerProvider.of(context).highlightedAction;
if (_scrollController.hasClients) {
final scrollViewHeight = _scrollController.position.viewportDimension;
final scrollViewTopOffset = _scrollController.offset;
final scrollViewBottomOffset = scrollViewTopOffset + scrollViewHeight;

final selectedItemTop = idx * itemHeight;
final selectedItemBottom = selectedItemTop + itemHeight;

double posToScrollTo = -1;
if (selectedItemTop < scrollViewTopOffset) {
posToScrollTo = selectedItemTop;
} else if (selectedItemBottom > scrollViewBottomOffset) {
// align bottom of item to bottom
posToScrollTo = selectedItemBottom - scrollViewHeight;
}

if (posToScrollTo != -1) {
_scrollController.jumpTo(posToScrollTo);
}
}
}

@override
void dispose() {
_scrollController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
CommandPaletteController controller =
CommandPaletteControllerProvider.of(context);
List<CommandPaletteAction> actions = controller.getFilteredActions();
List<CommandPaletteAction> filteredActions =
controller.getFilteredActions();
final borderRadius =
controller.style.borderRadius.resolve(Directionality.of(context));

return Material(
elevation: controller.style.elevation,
borderRadius: BorderRadius.only(
Expand All @@ -32,11 +76,12 @@ class CommandPaletteBody extends StatelessWidget {
children: [
Flexible(
child: ListView.builder(
controller: _scrollController,
shrinkWrap: true,
padding: const EdgeInsets.all(0),
itemCount: actions.length,
itemCount: filteredActions.length,
itemBuilder: (context, index) {
final CommandPaletteAction item = actions[index];
final CommandPaletteAction item = filteredActions[index];

return controller.config.builder(
context,
Expand All @@ -57,77 +102,86 @@ class CommandPaletteBody extends StatelessWidget {
}
}

/// Default builder of Actions.
/// Uses all the parameters, so this is a good place to look if you're wanting
/// to create your our custom builder
// ignore: prefer_function_declarations_over_variables
final ActionBuilder kDefaultBuilder = (
BuildContext context,
CommandPaletteStyle style,
CommandPaletteAction action,
bool isHighlighted,
VoidCallback onSelected,
List<String> searchTerms,
) {
Widget label;

// if highlighting the search substring is enabled, then we'll use one of the
// two widgets for that
if (style.highlightSearchSubstring) {
// if the action is a MatchedCommandPaletteAction, then we'll use our
// own highlighter here.
if (action is MatchedCommandPaletteAction && action.matches != null) {
label = OptionHighlighter(
action: action,
textStyle: style.actionLabelTextStyle!,
textAlign: style.actionLabelTextAlign,
textStyleHighlight: style.highlightedLabelTextStyle!,
);
class _DefaultItem extends StatelessWidget {
final CommandPaletteStyle style;
final CommandPaletteAction action;
final bool isHighlighted;
final VoidCallback onSelected;
final List<String> searchTerms;
const _DefaultItem({
Key? key,
required this.style,
required this.action,
required this.isHighlighted,
required this.onSelected,
required this.searchTerms,
}) : super(key: key);

@override
Widget build(BuildContext context) {
Widget label;

// if highlighting the search substring is enabled, then we'll use one of the
// two widgets for that
if (style.highlightSearchSubstring) {
// if the action is a MatchedCommandPaletteAction, then we'll use our
// own highlighter here.
if (action is MatchedCommandPaletteAction &&
(action as MatchedCommandPaletteAction).matches != null) {
label = OptionHighlighter(
action: (action as MatchedCommandPaletteAction),
textStyle: style.actionLabelTextStyle!,
textAlign: style.actionLabelTextAlign,
textStyleHighlight: style.highlightedLabelTextStyle!,
);
}
// if it's just a generic action, then we'll use the 3rd party highlighter.
// This likely means that the user made their own filtering solution.
else {
label = SubstringHighlight(
text: action.label,
textAlign: style.actionLabelTextAlign,
terms: searchTerms,
textStyle: style.actionLabelTextStyle!,
textStyleHighlight: style.highlightedLabelTextStyle!,
);
}
}
// if it's just a generic action, then we'll use the 3rd party highlighter.
// This likely means that the user made their own filtering solution.
// otherwise, just use a plain ol' text widget
else {
label = SubstringHighlight(
text: action.label,
label = Text(
action.label,
textAlign: style.actionLabelTextAlign,
terms: searchTerms,
textStyle: style.actionLabelTextStyle!,
textStyleHighlight: style.highlightedLabelTextStyle!,
style: style.actionLabelTextStyle!,
);
}
}
// otherwise, just use a plain ol' text widget
else {
label = Text(
action.label,
textAlign: style.actionLabelTextAlign,
style: style.actionLabelTextStyle!,
);
}

return Material(
color: isHighlighted ? style.selectedColor : style.actionColor,
child: InkWell(
onTap: onSelected,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: LayoutBuilder(
builder: (context, c) {
Widget? shortcuts;
if (action.shortcut != null) {
shortcuts = Wrap(
alignment: WrapAlignment.end,
children: action.shortcut!
.map<Widget>(
(e) => KeyboardKeyIcon(
iconString: e,
),
)
.toList(),
);
}
return Row(
Widget? shortcuts;
if (action.shortcut != null) {
shortcuts = Wrap(
alignment: WrapAlignment.end,
children: action.shortcut!
.map<Widget>(
(e) => KeyboardKeyIcon(
iconString: e,
),
)
.toList(),
);
}

final bool hasDescription = action.description != null;
return Material(
color: isHighlighted ? style.selectedColor : style.actionColor,
child: SizedBox(
height: itemHeight,
child: InkWell(
onTap: onSelected,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (action.leading != null)
Padding(
Expand All @@ -137,23 +191,29 @@ final ActionBuilder kDefaultBuilder = (
Flexible(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Expanded(child: label),
],
),
if (action.description != null)
Row(
Flexible(
child: Row(
children: [
Expanded(
child: Text(
action.description!,
textAlign: style.actionLabelTextAlign,
),
),
Expanded(child: label),
],
),
),
if (hasDescription)
Flexible(
child: Row(
children: [
Expanded(
child: Text(
action.description!,
textAlign: style.actionLabelTextAlign,
overflow: TextOverflow.fade,
),
),
],
),
),
],
),
),
Expand All @@ -163,10 +223,30 @@ final ActionBuilder kDefaultBuilder = (
child: shortcuts,
),
],
);
},
),
),
),
),
),
);
};
);
}
}

/// Default builder of Actions.
/// Uses all the parameters, so this is a good place to look if you're wanting
/// to create your our custom builder
// ignore: prefer_function_declarations_over_variables
final ActionBuilder kDefaultBuilder = (
BuildContext context,
CommandPaletteStyle style,
CommandPaletteAction action,
bool isHighlighted,
VoidCallback onSelected,
List<String> searchTerms,
) =>
_DefaultItem(
action: action,
style: style,
isHighlighted: isHighlighted,
onSelected: onSelected,
searchTerms: searchTerms,
);
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: command_palette
description: Flutter implementation of the Command Palette. Can be brought up via a keyboard shortcut.
version: 0.6.1
version: 0.7.0
homepage: https://github.com/TNorbury/command_palette
issue_tracker: https://github.com/TNorbury/command_palette/issues
repository: https://github.com/TNorbury/command_palette
Expand Down
2 changes: 1 addition & 1 deletion test/command_palette_keyboard_shortcuts_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ void main() {
(WidgetTester tester) async {
await tester.pumpWidget(
MyApp(
closeKeySet: SingleActivator(
closeKeySet: const SingleActivator(
LogicalKeyboardKey.keyJ,
alt: true,
),
Expand Down
Loading

0 comments on commit 1095d42

Please sign in to comment.