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
2 changes: 1 addition & 1 deletion api/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ dependencies:
archive: ^4.0.0
collection: ^1.18.0
freezed_annotation: ^3.0.0
json_annotation: ^4.11.0
json_annotation: ^4.12.0
replay_bloc: ^0.3.0
rxdart: ^0.28.0
uuid: ^4.4.0
Expand Down
138 changes: 94 additions & 44 deletions app/lib/bloc/document_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,25 @@ Future<(NoteData, List<PadElement>)> importAssetsAsync(
}
}

List<Renderer<PadElement>> orderRenderersByPage(
DocumentPage page,
Iterable<Renderer<PadElement>> renderers,
) {
final renderersById = {
for (final renderer in renderers)
if (renderer.element.id != null)
(renderer.element.id, renderer.layer): renderer,
};
return page.layers
.expand(
(layer) => layer.content.map(
(element) => renderersById[(element.id, layer.id)],
),
)
.nonNulls
.toList();
}

Selection? _updateSelection(
Selection? selection,
dynamic oldElement,
Expand Down Expand Up @@ -473,7 +492,7 @@ class DocumentBloc extends ReplayBloc<DocumentEvent, DocumentState> {
return _saveState(
emit,
state: current.copyWith(page: newPage, data: data),
replacedElements: renderers,
replacedElements: orderRenderersByPage(newPage, renderers),
shouldRefresh: () => replacedRenderers.entries
.map(
(element) => cubit.getHandler().onRendererUpdated(
Expand All @@ -492,6 +511,56 @@ class DocumentBloc extends ReplayBloc<DocumentEvent, DocumentState> {
final renderers = List<Renderer<PadElement>>.from(
currentIndexCubit.renderers,
);
void insertElement(
List<PadElement> content,
PadElement element,
int index,
) {
if (index >= 0) {
content.insert(index, element);
} else {
content.add(element);
}
}

void insertRenderer(Renderer<PadElement>? renderer, int index) {
if (renderer == null) return;
if (index >= 0) {
renderers.insert(index, renderer);
} else {
renderers.add(renderer);
}
}

if (event.arrangement == Arrangement.front ||
event.arrangement == Arrangement.back) {
final moveToFront = event.arrangement == Arrangement.front;
final newPage = current.page.mapLayers((e) {
final content = List<PadElement>.from(e.content);
for (final id in event.elements) {
final index = content.indexWhere((element) => element.id == id);
if (index == -1) continue;
final element = content.removeAt(index);
var newRendererIndex = renderers.indexWhere(
(e) => e.element == element,
);
final renderer = newRendererIndex >= 0
? renderers.removeAt(newRendererIndex)
: null;
final newIndex = moveToFront ? content.length : 0;
newRendererIndex = moveToFront ? renderers.length : 0;
insertElement(content, element, newIndex);
insertRenderer(renderer, newRendererIndex);
}
return e.copyWith(content: content);
});
return _saveState(
emit,
state: current.copyWith(page: newPage),
replacedElements: renderers,
);
}

final newPage = await current.page.mapLayersAsync((e) async {
final content = List<PadElement>.from(e.content);
for (final id in event.elements) {
Expand All @@ -505,59 +574,40 @@ class DocumentBloc extends ReplayBloc<DocumentEvent, DocumentState> {
final renderer = newRendererIndex >= 0
? renderers.removeAt(newRendererIndex)
: null;
if (event.arrangement == Arrangement.front) {
newIndex = content.length;
newRendererIndex = renderers.length;
} else if (event.arrangement == Arrangement.back) {
newIndex = 0;
newRendererIndex = 0;
} else {
final rect = renderer?.rect;
if (rect != null) {
final hits = (await rayCastRect(
rect,
)).map((e) => e.element).toList();
final hitIndex = hits.indexOf(renderer!.element);
if (hitIndex != -1) {
if (event.arrangement == Arrangement.backward &&
hitIndex != 0) {
newIndex = content.indexOf(hits[hitIndex - 1]);
} else if (event.arrangement == Arrangement.forward &&
hitIndex != hits.length - 1) {
newIndex = content.indexOf(hits[hitIndex + 1]) + 1;
}
if (newIndex >= 0) {
final element = newIndex < content.length
? content[newIndex]
: null;
newRendererIndex = element == null
? renderers.length
: renderers.indexWhere((e) => e.element == element);
}
}
final rect = renderer?.rect;
if (rect != null) {
final hits = (await rayCastRect(
rect,
hitElementMode: HitElementMode.touchAnywhere,
)).map((e) => e.element).toList();
final hitIndex = hits.indexOf(renderer!.element);
if (event.arrangement == Arrangement.backward && hitIndex > 0) {
newIndex = content.indexOf(hits[hitIndex - 1]);
} else if (event.arrangement == Arrangement.forward &&
hitIndex >= 0 &&
hitIndex < hits.length - 1) {
newIndex = content.indexOf(hits[hitIndex + 1]) + 1;
}
}
if (newIndex >= 0) {
content.insert(newIndex, element);
} else {
content.add(element);
}
if (renderer != null) {
if (newRendererIndex >= 0) {
renderers.insert(newRendererIndex, renderer);
} else {
renderers.add(renderer);
if (newIndex >= 0) {
final element = newIndex < content.length
? content[newIndex]
: null;
newRendererIndex = element == null
? renderers.length
: renderers.indexWhere((e) => e.element == element);
}
}
insertElement(content, element, newIndex);
insertRenderer(renderer, newRendererIndex);
}
return e.copyWith(content: content);
});
_saveState(
return _saveState(
emit,
state: current.copyWith(page: newPage),
replacedElements: renderers,
);
});
}, transformer: sequential());
on<ElementsRemoved>((event, emit) async {
final current = state;
if (current is! DocumentLoadSuccess) return;
Expand Down
12 changes: 12 additions & 0 deletions app/lib/cubits/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ sealed class ButterflySettings with _$ButterflySettings, LeapSettings {
PackAssetLocation? selectedPalette,
@Default(false) bool showVerboseLogs,
@Default(true) bool showThumbnails,
@Default(false) bool bringMovedElementsToFront,
}) = _ButterflySettings;

factory ButterflySettings.fromJson(Map<String, dynamic> json) =>
Expand Down Expand Up @@ -730,6 +731,8 @@ sealed class ButterflySettings with _$ButterflySettings, LeapSettings {
showVerboseLogs: prefs.getBool('show_verbose_logs') ?? false,
hideExtension: prefs.getBool('hide_extension') ?? true,
showThumbnails: prefs.getBool('show_thumbnails') ?? true,
bringMovedElementsToFront:
prefs.getBool('bring_moved_elements_to_front') ?? false,
);
}

Expand Down Expand Up @@ -851,6 +854,10 @@ sealed class ButterflySettings with _$ButterflySettings, LeapSettings {
}
await prefs.setBool('show_verbose_logs', showVerboseLogs);
await prefs.setBool('hide_extension', hideExtension);
await prefs.setBool(
'bring_moved_elements_to_front',
bringMovedElementsToFront,
);
}

ExternalStorage? getRemote(String? identifier) {
Expand Down Expand Up @@ -1570,4 +1577,9 @@ class SettingsCubit extends Cubit<ButterflySettings>
emit(state.copyWith(limitViewportPositive: value));
return save();
}

Future<void> changeBringMovedElementsToFront(bool value) {
emit(state.copyWith(bringMovedElementsToFront: value));
return save();
}
}
31 changes: 17 additions & 14 deletions app/lib/cubits/settings.freezed.dart

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions app/lib/cubits/settings.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions app/lib/handlers/select.dart
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ class SelectHandler extends Handler<SelectTool> {
return [];
}

if (state.settingsCubit.state.bringMovedElementsToFront) {
bloc.add(
ElementsArranged(Arrangement.front, current.map((e) => e.id).toList()),
);
}
bloc.add(
ElementsChanged(
Map.fromEntries(
Expand Down
3 changes: 2 additions & 1 deletion app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1343,5 +1343,6 @@
},
"holdShortcuts": "Hold Shortcuts",
"holdShortcutsDescription": "Hold a key to temporarily switch to another tool. Releasing the key switches back to the previous tool.",
"key": "Key"
"key": "Key",
"bringMovedElementsToFront": "Bring moved elements to front"
}
53 changes: 12 additions & 41 deletions app/lib/settings/behaviors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,18 @@ class BehaviorsSettingsPage extends StatelessWidget {
onTap: () => _openRenderResolutionModal(context),
leading: const Icon(PhosphorIconsLight.sparkle),
),
SwitchListTile(
title: Text(
AppLocalizations.of(
context,
).bringMovedElementsToFront,
),
value: state.bringMovedElementsToFront,
secondary: const PhosphorIcon(PhosphorIconsLight.stack),
onChanged: (value) => context
.read<SettingsCubit>()
.changeBringMovedElementsToFront(value),
),
],
),
),
Expand Down Expand Up @@ -201,47 +213,6 @@ class BehaviorsSettingsPage extends StatelessWidget {
),
),
),
Card(
margin: settingsCardMargin,
child: Padding(
padding: settingsCardPadding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: settingsCardTitlePadding,
child: Text(
AppLocalizations.of(context).home,
style: TextTheme.of(context).headlineSmall,
),
),
const SizedBox(height: 16),
SwitchListTile(
secondary: const PhosphorIcon(PhosphorIconsLight.image),
title: Text(
AppLocalizations.of(context).showThumbnails,
),
value: state.showThumbnails,
onChanged: (value) => context
.read<SettingsCubit>()
.changeShowThumbnails(value),
),
SwitchListTile(
value: state.hideExtension,
onChanged: (value) => context
.read<SettingsCubit>()
.changeHideExtension(value),
title: Text(
AppLocalizations.of(context).hideFileExtension,
),
secondary: const PhosphorIcon(
PhosphorIconsLight.fileText,
),
),
],
),
),
),
],
);
},
Expand Down
41 changes: 41 additions & 0 deletions app/lib/settings/view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,47 @@ class ViewSettingsPage extends StatelessWidget {
),
),
),
Card(
margin: settingsCardMargin,
child: Padding(
padding: settingsCardPadding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: settingsCardTitlePadding,
child: Text(
AppLocalizations.of(context).home,
style: TextTheme.of(context).headlineSmall,
),
),
const SizedBox(height: 16),
SwitchListTile(
secondary: const PhosphorIcon(PhosphorIconsLight.image),
title: Text(
AppLocalizations.of(context).showThumbnails,
),
value: state.showThumbnails,
onChanged: (value) => context
.read<SettingsCubit>()
.changeShowThumbnails(value),
),
SwitchListTile(
value: state.hideExtension,
onChanged: (value) => context
.read<SettingsCubit>()
.changeHideExtension(value),
title: Text(
AppLocalizations.of(context).hideFileExtension,
),
secondary: const PhosphorIcon(
PhosphorIconsLight.fileText,
),
),
],
),
),
),
],
);
},
Expand Down
2 changes: 1 addition & 1 deletion app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ dependencies:
camera_windows: ^0.2.1+9
window_manager: ^0.5.0
flex_color_scheme: ^8.0.0
json_annotation: ^4.11.0
json_annotation: ^4.12.0
freezed_annotation: ^3.0.0
http: ^1.2.1
flutter_secure_storage: ^10.0.0-beta.2
Expand Down
Loading