Mathias Mogensen b4d22bab14
feat: search mvp (#5064)
* feat: implement folder indexer

* feat: sqlite search views using fts5

* feat: add view indexing to user manager

* feat: implement folder indexer

* feat: add sqlite search documents

* feat: add document indexing to user manager

* feat: add document indexing to folder indexer

* chore: update collab rev

* feat: search frontend integration

* refactor: search index

* test: add event test

* chore: fix ci

* feat: initial command palette overlay impl (#4619)

* chore: test search engine

* chore: initial structure

* chore: replace old search request

* chore: enable log for lib-dispatch

* chore: move search manager to core

* feat: move traits and responsibility to search crate

* feat: move search to search crate

* feat: replace sqlite with tantivy

* feat: deserialize tantivy documents

* chore: fixes after rebase

* chore: clean code

* feat: fetch and sort results

* fix: code review + cleaning

* feat: support custom icons

* feat: support view layout icons

* feat: rename bloc and fix indexing

* fix: prettify dialog

* feat: score results

* chore: update collab rev

* feat: add recent view history to command palette

* test: add integration_tests

* fix: clippy changes

* fix: focus traversal in cmd palette

* fix: remove file after merging main

* chore: code review and panic-safe

* feat: index all views if index does not exist

* chore: improve logic with conditional

* chore: add is_empty check

* chore: abstract logic from folder manager init

* chore: update collab rev

* chore: code review

* chore: fixes after merge + update lock file

* chore: revert cargo lock

* fix: set icon type when removing icon

* fix: code review + dependency inversion

* fix: remove icon fix for not persisting icon type

* test: simple tests manipulating views

* test: create 100 views

* fix: tauri build

* chore: create 1000 views

* chore: create util methods

* chore: test

* chore: test

* chore: remove logs

* chore: fix build.rs

* chore: export models

* chore: enable clear cache on Rust-CI

* fix: navigate to newly created views

* fix: force disable setting workspace listener on rebuilds

* fix: remove late final

* fix: missing returns

* fix: localization and minor fixes

* test: add index assert to large test

* fix: missing section param after merging main

* chore: try fix unzip file error

* chore: lower the test

* feat: show hint when result is in trash

* feat: one index_writer per index

* fix: minor changes after merge

* fix: make create_log_filter public after merge

* chore: fix test

* chore: fix test

* chore: flutter analyze

* chore: flutter analyze

* chore: fix tauri build

---------

Co-authored-by: nathan <nathan@appflowy.io>
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
2024-04-12 16:21:41 +08:00

144 lines
3.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/base/emoji/emoji_picker.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/icon.pbenum.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
extension ToProto on FlowyIconType {
ViewIconTypePB toProto() {
switch (this) {
case FlowyIconType.emoji:
return ViewIconTypePB.Emoji;
case FlowyIconType.icon:
return ViewIconTypePB.Icon;
case FlowyIconType.custom:
return ViewIconTypePB.Url;
}
}
}
enum FlowyIconType {
emoji,
icon,
custom;
}
class EmojiPickerResult {
factory EmojiPickerResult.none() =>
const EmojiPickerResult(FlowyIconType.icon, '');
factory EmojiPickerResult.emoji(String emoji) =>
EmojiPickerResult(FlowyIconType.emoji, emoji);
const EmojiPickerResult(
this.type,
this.emoji,
);
final FlowyIconType type;
final String emoji;
}
class FlowyIconPicker extends StatelessWidget {
const FlowyIconPicker({
super.key,
required this.onSelected,
});
final void Function(EmojiPickerResult result) onSelected;
@override
Widget build(BuildContext context) {
// ONLY supports emoji picker for now
return DefaultTabController(
length: 1,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
_buildTabs(context),
const Spacer(),
_RemoveIconButton(
onTap: () => onSelected(EmojiPickerResult.none()),
),
],
),
const Divider(height: 2),
Expanded(
child: TabBarView(
children: [
FlowyEmojiPicker(
emojiPerLine: _getEmojiPerLine(context),
onEmojiSelected: (_, emoji) =>
onSelected(EmojiPickerResult.emoji(emoji)),
),
],
),
),
],
),
);
}
Widget _buildTabs(BuildContext context) {
return Align(
alignment: Alignment.centerLeft,
child: TabBar(
indicatorSize: TabBarIndicatorSize.label,
isScrollable: true,
overlayColor: MaterialStatePropertyAll(
Theme.of(context).colorScheme.secondary,
),
padding: EdgeInsets.zero,
tabs: [
FlowyHover(
style: const HoverStyle(borderRadius: BorderRadius.zero),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12.0,
vertical: 8.0,
),
child: FlowyText(LocaleKeys.emoji_emojiTab.tr()),
),
),
],
),
);
}
int _getEmojiPerLine(BuildContext context) {
if (PlatformExtension.isDesktopOrWeb) {
return 9;
}
final width = MediaQuery.of(context).size.width;
return width ~/ 46.0; // the size of the emoji
}
}
class _RemoveIconButton extends StatelessWidget {
const _RemoveIconButton({required this.onTap});
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 28,
child: FlowyButton(
onTap: onTap,
useIntrinsicWidth: true,
text: FlowyText.small(
LocaleKeys.document_plugins_cover_removeIcon.tr(),
),
leftIcon: const FlowySvg(FlowySvgs.delete_s),
),
);
}
}