Merge branch 'feat/tauri-move-fields' into feat/tauri-grid

# Conflicts:
#	frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/DatePickerPopup.tsx
#	frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellWrapper.tsx
#	frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCheckboxCell.tsx
#	frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditRow.tsx
#	frontend/appflowy_tauri/src/appflowy_app/components/board/BoardCell.tsx
#	frontend/appflowy_tauri/src/appflowy_app/stores/effects/database/database_bd_svc.ts
#	frontend/appflowy_tauri/src/appflowy_app/stores/effects/database/database_controller.ts
This commit is contained in:
ascarbek 2023-04-04 17:16:05 +06:00
commit ed977868cf
107 changed files with 1462 additions and 532 deletions

View File

@ -324,6 +324,7 @@ jobs:
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ${{ env.LINUX_APP_RELEASE_PATH }}/${{ env.LINUX_PACKAGE_NAME }}
asset_name: ${{ env.LINUX_PACKAGE_NAME }}
asset_content_type: application/octet-stream
@ -352,3 +353,12 @@ jobs:
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/appflowy_client:${{ github.ref_name }}
cache-from: type=registry,ref=${{ secrets.DOCKER_HUB_USERNAME }}/af_build_cache:buildcache
cache-to: type=registry,ref=${{ secrets.DOCKER_HUB_USERNAME }}/af_build_cache:buildcache,mode=max
notify-discord:
runs-on: ubuntu-latest
needs: [build-for-linux, build-for-windows, build-for-macOS]
steps:
- name: Notify Discord
run: |
curl -H "Content-Type: application/json" -d '{"username": "release@appflowy", "content": "🎉 AppFlowy ${{ github.ref_name }} is available. https://github.com/AppFlowy-IO/AppFlowy/releases/tag/'${{ github.ref_name }}'"}' "https://discord.com/api/webhooks/${{ secrets.DISCORD }}"
shell: bash

View File

@ -1,5 +1,12 @@
# Release Notes
## Version 0.1.2 - 03/28/2023
### Bug Fixes
- Fix: update calendar selected range.
- Fix: duplicate view.
## Version 0.1.1 - 03/21/2023
### New features

View File

@ -23,7 +23,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
CARGO_MAKE_CRATE_FS_NAME = "dart_ffi"
CARGO_MAKE_CRATE_NAME = "dart-ffi"
LIB_NAME = "dart_ffi"
CURRENT_APP_VERSION = "0.1.1"
CURRENT_APP_VERSION = "0.1.2"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite"
PRODUCT_NAME = "AppFlowy"
# CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html

View File

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="16" height="16" rx="8" fill="#00BCF0"/>
<rect x="7.5" y="4" width="1" height="8" rx="0.5" fill="#131720"/>
<rect x="12" y="7.5" width="1" height="8" rx="0.5" transform="rotate(90 12 7.5)" fill="#131720"/>
</svg>

After

Width:  |  Height:  |  Size: 321 B

View File

@ -188,10 +188,10 @@
"exportDatabase": "Export database",
"selectFiles": "Select the files that need to be export",
"createNewFolder": "Create a new folder",
"createNewFolderDesc": "Tell us where you want to store your data ...",
"createNewFolderDesc": "Tell us where you want to store your data",
"open": "Open",
"openFolder": "Open an existing folder",
"openFolderDesc": "Read and write it to your existing AppFlowy folder ...",
"openFolderDesc": "Read and write it to your existing AppFlowy folder",
"folderHintText": "folder name",
"location": "Creating a new folder",
"locationDesc": "Pick a name for your AppFlowy data folder",
@ -366,6 +366,7 @@
"changeCover": "Change Cover",
"colors": "Colors",
"images": "Images",
"clearAll": "Clear All",
"abstract": "Abstract",
"addCover": "Add Cover",
"addLocalImage": "Add local image",
@ -383,7 +384,6 @@
"imageSavingFailed": "Image Saving Failed",
"addIcon": "Add Icon"
}
}
},
"board": {

View File

@ -40,6 +40,13 @@
"markdown": "Markdown",
"copyLink": "複製連結"
},
"moreAction": {
"small": "小",
"medium": "中",
"large": "大",
"fontSize": "字體大小",
"import": "匯入"
},
"disclosureAction": {
"rename": "重新命名",
"delete": "刪除",
@ -64,6 +71,7 @@
},
"dialogCreatePageNameHint": "頁面名稱",
"questionBubble": {
"shortcuts": "快捷鍵",
"whatsNew": "新功能",
"help": "幫助 & 支援",
"debug": {
@ -90,11 +98,21 @@
"inlineCode": "程式碼",
"quote": "區塊引言",
"header": "標題",
"highlight": "反白"
"highlight": "反白",
"color": "顏色"
},
"tooltip": {
"lightMode": "切換至亮色模式",
"darkMode": "切換至暗色模式"
"darkMode": "切換至暗色模式",
"openAsPage": "以頁面開啓",
"addNewRow": "新增列表",
"openMenu": "點擊開啓選單",
"viewDataBase": "查看資料庫",
"referencePage": "這個 {name} 已參照"
},
"sideBar": {
"closeSidebar": "關閉側邊欄",
"openSidebar": "開啓側邊欄"
},
"notifications": {
"export": {
@ -114,7 +132,14 @@
"signIn": "登入",
"signOut": "登出",
"complete": "完成",
"save": "儲存"
"save": "儲存",
"generate": "產生",
"esc": "離開",
"keep": "保存",
"tryAgain": "再試一次",
"discard": "放棄變更",
"replace": "取代",
"insertBelow": "在下面插入"
},
"label": {
"welcome": "歡迎!",
@ -142,22 +167,99 @@
"appearance": "外觀",
"language": "語言",
"user": "使用者",
"files": "檔案",
"open": "開啟設定"
},
"appearance": {
"themeMode": {
"label": "Theme Mode",
"label": "主題模式",
"light": "亮色模式",
"dark": "暗色模式",
"system": "Adapt to System"
}
"system": "系統設定"
},
"theme": "主題"
},
"files": {
"defaultLocation": "Appflowy 資料儲存位置",
"doubleTapToCopy": "雙擊以複製路徑",
"restoreLocation": "回復 Appflowy 預設路徑",
"customizeLocation": "開啓其他資料夾",
"restartApp": "請重新啓動以讓更動生效",
"exportDatabase": "匯出資料庫",
"selectFiles": "選擇需要匯出的檔案",
"createNewFolder": "建立新檔案",
"createNewFolderDesc": "選擇你想儲存資料的位置",
"open": "打開",
"openFolder": "開啓一個已經存在的資料夾",
"openFolderDesc": "讀寫已存在的 AppFlowy 資料夾",
"folderHintText": "資料夾名稱",
"location": "建立新資料夾",
"locationDesc": "命名 Appflowy 資料夾",
"browser": "瀏覽",
"create": "建立",
"folderPath": "儲存資料夾的路徑",
"locationCannotBeEmpty": "路徑不能爲空",
"pathCopiedSnackbar": "檔案儲存空間的路徑已被複製到剪貼簿!"
},
"user": {
"name": "名稱",
"icon": "圖標",
"selectAnIcon": "選擇圖標",
"pleaseInputYourOpenAIKey": "請輸入你的 OpenAI 密鑰"
}
},
"grid": {
"settings": {
"filter": "篩選",
"sort": "排序",
"sortBy": "排序方式",
"Properties": "內容"
"Properties": "內容",
"group": "群組",
"addFilter": "增加",
"deleteFilter": "刪除篩選器",
"filterBy": "以...篩選",
"typeAValue": "輸入一個值...",
"layout": "佈局"
},
"textFilter": {
"contains": "包含",
"doesNotContain": "不包含",
"endsWith": "以...結尾",
"startWith": "以...開頭",
"is": "是",
"isNot": "不是",
"isEmpty": "爲空",
"isNotEmpty": "不爲空",
"choicechipPrefix": {
"isNot": "不是",
"startWith": "以...開頭",
"endWith": "以...結尾",
"isEmpty": "爲空",
"isNotEmpty": "不爲空"
}
},
"checkboxFilter": {
"isChecked": "已核取",
"isUnchecked": "未核取",
"choicechipPrefix": {
"is": "是"
}
},
"checklistFilter": {
"isComplete": "已完成",
"isIncomplted": "未完成"
},
"singleSelectOptionFilter": {
"is": "是",
"isNot": "不是",
"isEmpty": "爲空",
"isNotEmpty": "不爲空"
},
"multiSelectOptionFilter": {
"contains": "包含",
"doesNotContain": "不包含",
"isEmpty": "爲空",
"isNotEmpty": "不爲空"
},
"field": {
"hide": "隱藏",
@ -172,6 +274,7 @@
"singleSelectFieldName": "單選",
"multiSelectFieldName": "多選",
"urlFieldName": "網址",
"checklistFieldName": "核取列表",
"numberFormat": "數字格式",
"dateFormat": "日期格式",
"includeTime": "包含時間",
@ -186,13 +289,23 @@
"addSelectOption": "新增選項",
"optionTitle": "選項",
"addOption": "新增選項",
"editProperty": "編輯內容"
"editProperty": "編輯內容",
"newColumn": "新欄位",
"deleteFieldPromptMessage": "你確定嗎?這個內容將被刪除"
},
"sort": {
"ascending": "升冪排序",
"descending": "降冪排序",
"deleteSort": "刪除排序",
"addSort": "新增排序"
},
"row": {
"duplicate": "複製",
"delete": "刪除",
"textPlaceholder": "空",
"copyProperty": "已將內容複製至剪貼簿"
"copyProperty": "已將內容複製至剪貼簿",
"count": "Count",
"newRow": "新列表"
},
"selectOption": {
"create": "建立",
@ -210,6 +323,9 @@
"panelTitle": "搜尋或建立選項",
"searchOption": "搜尋選項"
},
"checklist": {
"panelTitle": "新增物件"
},
"menuName": "網格"
},
"document": {
@ -217,10 +333,78 @@
"date": {
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
},
"slashMenu": {
"board": {
"selectABoardToLinkTo": "選擇要連結的看板",
"createANewBoard": "建立新的看板"
},
"grid": {
"selectAGridToLinkTo": "選擇要連結的網格",
"createANewGrid": "建立新網格"
}
},
"plugins": {
"referencedBoard": "已參照的看板",
"referencedGrid": "已參照的網格",
"autoGeneratorMenuItemName": "OpenAI 寫手",
"autoGeneratorTitleName": "OpenAI: 叫人工智慧寫下任何事情...",
"autoGeneratorLearnMore": "Learn more",
"autoGeneratorGenerate": "產生",
"autoGeneratorHintText": "問 OpenAI ...",
"autoGeneratorCantGetOpenAIKey": "無法取得 OpenAI 密鑰",
"smartEdit": "人工智慧助理",
"openAI": "OpenAI",
"smartEditFixSpelling": "修正拼寫",
"warning": "⚠️ AI 的回答可能不精確或是存在誤導",
"smartEditSummarize": "總結",
"smartEditCouldNotFetchResult": "無法取得 OpenAI 的結果",
"smartEditCouldNotFetchKey": "無法取得 OpenAI 密鑰",
"smartEditDisabled": "在設定連結 OpenAI ",
"discardResponse": "你確定放棄人工智慧的回覆?",
"cover": {
"changeCover": "更換封面",
"colors": "顏色",
"images": "圖片",
"abstract": "摘要",
"addCover": "新增封面",
"addLocalImage": "新增本機圖片",
"invalidImageUrl": "無效的圖片網址",
"failedToAddImageToGallery": "新增圖片到圖庫失敗",
"enterImageUrl": "輸入圖片網址",
"add": "Add",
"back": "Back",
"saveToGallery": "儲存到",
"removeIcon": "移除圖標",
"pasteImageUrl": "複製圖片網址",
"or": "或",
"pickFromFiles": "挑選檔案",
"couldNotFetchImage": "無法截取圖片",
"imageSavingFailed": "圖片儲存失敗",
"addIcon": "新增圖標"
}
}
},
"sideBar": {
"openSidebar": "Open sidebar",
"closeSidebar": "Close sidebar"
"board": {
"column": {
"create_new_card": "建立"
},
"menuName": "看板"
},
"calendar": {
"menuName": "日曆",
"defaultNewCalendarTitle": "未命名的",
"navigation": {
"today": "今天",
"jumpToday": "跳至今天",
"previousMonth": "上個月",
"nextMonth": "下個月"
},
"settings": {
"showWeekNumbers": "顯示星期",
"showWeekends": "顯示週末",
"firstDayOfWeek": "一週的第一天",
"layoutDateField": "排列方式"
}
}
}

View File

@ -184,7 +184,7 @@ class _BoardContentState extends State<BoardContent> {
width: 20,
child: svgWidget(
"home/add",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
onAddButtonClick: () {
@ -207,7 +207,7 @@ class _BoardContentState extends State<BoardContent> {
width: 20,
child: svgWidget(
"home/add",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
title: FlowyText.medium(

View File

@ -113,7 +113,7 @@ class _SettingItem extends StatelessWidget {
},
leftIcon: svgWidget(
action.iconName(),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
);

View File

@ -203,7 +203,7 @@ class _NewEventButton extends StatelessWidget {
iconPadding: EdgeInsets.zero,
icon: svgWidget(
"home/add",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
width: 22,
);

View File

@ -43,7 +43,7 @@ class ChoiceChipButton extends StatelessWidget {
radius: const BorderRadius.all(Radius.circular(14)),
leftIcon: svgWidget(
filterInfo.fieldInfo.fieldType.iconName(),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
rightIcon: _ChoicechipFilterDesc(filterDesc: filterDesc),
hoverColor: AFThemeExtension.of(context).lightGreyHover,

View File

@ -162,7 +162,7 @@ class _FilterPropertyCell extends StatelessWidget {
onTap: () => onTap(fieldInfo),
leftIcon: svgWidget(
fieldInfo.fieldType.iconName(),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
);
}

View File

@ -34,7 +34,7 @@ class _DisclosureButtonState extends State<DisclosureButton> {
width: 20,
icon: svgWidget(
"editor/details",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
onPressed: () => controller.show(),
);

View File

@ -76,7 +76,7 @@ class _AddFilterButtonState extends State<AddFilterButton> {
hoverColor: AFThemeExtension.of(context).lightGreyHover,
leftIcon: svgWidget(
"home/add",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
onTap: () => popoverController.show(),
),

View File

@ -19,7 +19,7 @@ class GridAddRowButton extends StatelessWidget {
onTap: () => context.read<GridBloc>().add(const GridEvent.createRow()),
leftIcon: svgWidget(
"home/add",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
);
}

View File

@ -168,7 +168,7 @@ class FieldCellButton extends StatelessWidget {
onTap: onTap,
leftIcon: svgWidget(
field.fieldType.iconName(),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
radius: BorderRadius.zero,
text: FlowyText.medium(

View File

@ -61,7 +61,7 @@ class FieldTypeCell extends StatelessWidget {
onTap: () => onSelectField(fieldType),
leftIcon: svgWidget(
fieldType.iconName(),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
);

View File

@ -116,11 +116,11 @@ class _SwitchFieldButton extends StatelessWidget {
margin: GridSize.typeOptionContentInsets,
leftIcon: svgWidget(
bloc.state.field.fieldType.iconName(),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
rightIcon: svgWidget(
"grid/more",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
);
}

View File

@ -182,7 +182,7 @@ class CreateFieldButton extends StatelessWidget {
onTap: () {},
leftIcon: svgWidget(
"home/add",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
popupBuilder: (BuildContext popover) {

View File

@ -153,7 +153,7 @@ class DateFormatButton extends StatelessWidget {
onHover: onHover,
rightIcon: svgWidget(
"grid/more",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
);
@ -184,7 +184,7 @@ class TimeFormatButton extends StatelessWidget {
onHover: onHover,
rightIcon: svgWidget(
"grid/more",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
);

View File

@ -61,7 +61,7 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
margin: GridSize.typeOptionContentInsets,
rightIcon: svgWidget(
"grid/more",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
text: Row(
children: [

View File

@ -194,7 +194,7 @@ class _OptionCellState extends State<_OptionCell> {
padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: svgWidget(
"grid/details",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
],
@ -251,7 +251,7 @@ class _AddOptionButton extends StatelessWidget {
},
leftIcon: svgWidget(
"home/add",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
),

View File

@ -106,7 +106,7 @@ class _DeleteTag extends StatelessWidget {
text: FlowyText.medium(LocaleKeys.grid_selectOption_deleteTag.tr()),
leftIcon: svgWidget(
"grid/delete",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
onTap: () {
context

View File

@ -67,7 +67,7 @@ class _ActionCell extends StatelessWidget {
},
leftIcon: svgWidget(
action.iconName(),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
);

View File

@ -161,7 +161,7 @@ class _SortPropertyCell extends StatelessWidget {
onTap: () => onTap(fieldInfo),
leftIcon: svgWidget(
fieldInfo.fieldType.iconName(),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
);
}

View File

@ -125,7 +125,7 @@ class _SortItem extends StatelessWidget {
hoverColor: AFThemeExtension.of(context).lightGreyHover,
icon: svgWidget(
"home/close",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
);
@ -187,7 +187,7 @@ class _AddSortButtonState extends State<_AddSortButton> {
onTap: () => _popoverController.show(),
leftIcon: svgWidget(
"home/add",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
),
@ -222,7 +222,7 @@ class _DeleteSortButton extends StatelessWidget {
},
leftIcon: svgWidget(
"editor/delete",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
);

View File

@ -61,7 +61,7 @@ class SortChoiceChip extends StatelessWidget {
final text = LocaleKeys.grid_settings_sort.tr();
final leftIcon = svgWidget(
"grid/setting/sort",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
);
return SizedBox(

View File

@ -82,7 +82,7 @@ class _GridGroupCell extends StatelessWidget {
text: FlowyText.medium(fieldInfo.name),
leftIcon: svgWidget(
fieldInfo.fieldType.iconName(),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
rightIcon: rightIcon,
onTap: () {

View File

@ -96,7 +96,7 @@ class _GridPropertyCellState extends State<_GridPropertyCell> {
Widget build(BuildContext context) {
final checkmark = svgWidget(
widget.fieldInfo.visibility ? 'home/show' : 'home/hide',
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
);
return SizedBox(
@ -118,7 +118,7 @@ class _GridPropertyCellState extends State<_GridPropertyCell> {
text: FlowyText.medium(widget.fieldInfo.name),
leftIcon: svgWidget(
widget.fieldInfo.fieldType.iconName(),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
rightIcon: FlowyIconButton(
hoverColor: Colors.transparent,

View File

@ -78,7 +78,7 @@ class _SettingItem extends StatelessWidget {
onTap: () => onAction(action),
leftIcon: svgWidget(
action.iconName(),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
);

View File

@ -232,7 +232,7 @@ class _CardMoreOption extends StatelessWidget with CardAccessory {
padding: const EdgeInsets.all(3.0),
child: svgWidget(
'grid/details',
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
);
}
@ -254,7 +254,7 @@ class _CardEditOption extends StatelessWidget with CardAccessory {
padding: const EdgeInsets.all(3.0),
child: svgWidget(
'editor/edit',
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
);
}

View File

@ -3,11 +3,9 @@ import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flowy_infra/size.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
import '../cell_builder.dart';
@ -69,7 +67,6 @@ class _PrimaryCellAccessoryState extends State<PrimaryCellAccessory>
Widget build(BuildContext context) {
return Tooltip(
message: LocaleKeys.tooltip_openAsPage.tr(),
textStyle: AFThemeExtension.of(context).caption.textColor(Colors.white),
child: svgWidget(
"grid/expander",
color: Theme.of(context).colorScheme.primary,
@ -125,7 +122,6 @@ class _AccessoryHoverState extends State<AccessoryHover> {
@override
Widget build(BuildContext context) {
List<Widget> children = [
const _Background(),
Padding(padding: widget.contentPadding, child: widget.child),
];
@ -173,28 +169,6 @@ class AccessoryHoverState extends ChangeNotifier {
bool get onHover => _onHover;
}
class _Background extends StatelessWidget {
const _Background({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer<AccessoryHoverState>(
builder: (context, state, child) {
if (state.onHover) {
return FlowyHoverContainer(
style: HoverStyle(
borderRadius: Corners.s6Border,
hoverColor: AFThemeExtension.of(context).lightGreyHover,
),
);
} else {
return const SizedBox();
}
},
);
}
}
class CellAccessoryContainer extends StatelessWidget {
final List<GridCellAccessoryBuilder> accessories;
const CellAccessoryContainer({required this.accessories, Key? key})

View File

@ -137,7 +137,7 @@ class _ChecklistOptionCellState extends State<_ChecklistOptionCell> {
iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2),
icon: svgWidget(
"editor/details",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
);
}

View File

@ -173,13 +173,13 @@ class _CellCalendarWidgetState extends State<_CellCalendarWidget> {
leftChevronPadding: EdgeInsets.zero,
leftChevronIcon: svgWidget(
"home/arrow_left",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
rightChevronPadding: EdgeInsets.zero,
rightChevronMargin: EdgeInsets.zero,
rightChevronIcon: svgWidget(
"home/arrow_right",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
headerMargin: const EdgeInsets.only(bottom: 8.0),
),
@ -254,7 +254,7 @@ class _IncludeTimeButton extends StatelessWidget {
children: [
svgWidget(
"grid/clock",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
const HSpace(4),
FlowyText.medium(LocaleKeys.grid_field_includeTime.tr()),
@ -387,7 +387,7 @@ class _DateTypeOptionButton extends StatelessWidget {
margin: GridSize.typeOptionContentInsets,
rightIcon: svgWidget(
"grid/more",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
),

View File

@ -116,7 +116,7 @@ class SelectOptionTag extends StatelessWidget {
hoverColor: Colors.transparent,
icon: svgWidget(
'home/close',
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
],

View File

@ -277,7 +277,7 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
iconPadding: const EdgeInsets.symmetric(horizontal: 6.0),
icon: svgWidget(
"editor/details",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
],

View File

@ -213,7 +213,7 @@ class _EditURLAccessoryState extends State<_EditURLAccessory>
offset: const Offset(0, 8),
child: svgWidget(
"editor/edit",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
popupBuilder: (BuildContext popoverContext) {
return URLEditorPopover(
@ -246,7 +246,7 @@ class _CopyURLAccessoryState extends State<_CopyURLAccessory>
Widget build(BuildContext context) {
return svgWidget(
"editor/copy",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
);
}

View File

@ -103,7 +103,7 @@ class _CloseButton extends StatelessWidget {
iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2),
icon: svgWidget(
"home/close",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
);
}

View File

@ -34,7 +34,8 @@ class DocumentBanner extends StatelessWidget {
contentPadding: EdgeInsets.zero,
bgColor: Colors.transparent,
hoverColor: Theme.of(context).colorScheme.primary,
downColor: Theme.of(context).colorScheme.primaryContainer,
highlightColor:
Theme.of(context).colorScheme.primaryContainer,
outlineColor: Colors.white,
borderRadius: Corners.s8Border,
onPressed: onRestore,
@ -50,7 +51,7 @@ class DocumentBanner extends StatelessWidget {
contentPadding: EdgeInsets.zero,
bgColor: Colors.transparent,
hoverColor: Theme.of(context).colorScheme.primaryContainer,
downColor: Theme.of(context).colorScheme.primary,
highlightColor: Theme.of(context).colorScheme.primary,
outlineColor: Colors.white,
borderRadius: Corners.s8Border,
onPressed: onDelete,

View File

@ -32,6 +32,7 @@ class _FontSizeSwitcherState extends State<FontSizeSwitcher> {
FlowyText.semibold(
LocaleKeys.moreAction_fontSize.tr(),
fontSize: 12,
color: Theme.of(context).colorScheme.tertiary,
),
const SizedBox(
height: 5,
@ -43,9 +44,8 @@ class _FontSizeSwitcherState extends State<FontSizeSwitcher> {
_updateSelectedFontSize(_fontSizes[index].item2);
},
borderRadius: const BorderRadius.all(Radius.circular(5)),
selectedBorderColor: Theme.of(context).colorScheme.primaryContainer,
selectedColor: Theme.of(context).colorScheme.onSurface,
fillColor: Theme.of(context).colorScheme.primaryContainer,
selectedColor: Theme.of(context).colorScheme.tertiary,
fillColor: Theme.of(context).colorScheme.primary,
color: Theme.of(context).hintColor,
constraints: const BoxConstraints(
minHeight: 40.0,

View File

@ -28,7 +28,7 @@ class DocumentMoreButton extends StatelessWidget {
child: svgWidget(
'editor/details',
size: const Size(18, 18),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
);
}

View File

@ -119,7 +119,7 @@ class _BuiltInPageWidgetState extends State<BuiltInPageWidget> {
iconPadding: const EdgeInsets.all(3),
icon: svgWidget(
'common/information',
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
// Name
@ -143,7 +143,7 @@ class _BuiltInPageWidgetState extends State<BuiltInPageWidget> {
iconPadding: const EdgeInsets.all(3),
icon: svgWidget(
'common/settings',
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
onPressed: () => controller.show(),
);

View File

@ -149,7 +149,7 @@ class _LinkToPageMenuState extends State<LinkToPageMenu> {
FlowyButton(
leftIcon: svgWidget(
_iconName(value),
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
text: FlowyText.regular(value.name),
onTap: () => widget.onSelected(app.value1, value),

View File

@ -18,7 +18,7 @@ SelectionMenuItem boardMenuItem = SelectionMenuItem(
);
},
// TODO(a-wallen): Translate keywords
keywords: ['referenced board', 'referenced kanban'],
keywords: ['referenced', 'board', 'kanban'],
handler: (editorState, menuService, context) {
showLinkToPageMenu(
editorState,

View File

@ -2,17 +2,20 @@ import 'dart:io';
import 'dart:ui';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/plugins/cover/change_cover_popover_bloc.dart';
import 'package:appflowy/plugins/document/presentation/plugins/cover/cover_image_picker.dart';
import 'package:appflowy/plugins/document/presentation/plugins/cover/cover_node_widget.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
const String kLocalImagesKey = 'local_images';
@ -71,31 +74,35 @@ class CoverColorPicker extends StatefulWidget {
}
class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
late Future<List<String>>? fileImages;
bool isAddingImage = false;
@override
void initState() {
super.initState();
fileImages = _getPreviouslyPickedImagePaths();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(15),
child: SingleChildScrollView(
child: isAddingImage
? CoverImagePicker(
onBackPressed: () => setState(() {
isAddingImage = false;
}),
onFileSubmit: (List<String> path) {
setState(() {
isAddingImage = false;
});
})
: _buildCoverSelection(),
return BlocProvider(
create: (context) => ChangeCoverPopoverBloc()
..add(const ChangeCoverPopoverEvent.fetchPickedImagePaths()),
child: BlocBuilder<ChangeCoverPopoverBloc, ChangeCoverPopoverState>(
builder: (context, state) {
return Padding(
padding: const EdgeInsets.all(15),
child: SingleChildScrollView(
child: isAddingImage
? CoverImagePicker(
onBackPressed: () => setState(() {
isAddingImage = false;
}),
onFileSubmit: (List<String> path) {
context.read<ChangeCoverPopoverBloc>().add(
const ChangeCoverPopoverEvent
.fetchPickedImagePaths());
setState(() {
isAddingImage = false;
});
})
: _buildCoverSelection(),
),
);
},
),
);
}
@ -104,21 +111,55 @@ class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FlowyText.semibold(LocaleKeys.document_plugins_cover_colors.tr()),
FlowyText.semibold(
LocaleKeys.document_plugins_cover_colors.tr(),
color: Theme.of(context).colorScheme.tertiary,
),
const SizedBox(height: 10),
_buildColorPickerList(),
const SizedBox(height: 10),
FlowyText.semibold(LocaleKeys.document_plugins_cover_images.tr()),
_buildImageHeader(),
const SizedBox(height: 10),
_buildFileImagePicker(),
const SizedBox(height: 10),
FlowyText.semibold(LocaleKeys.document_plugins_cover_abstract.tr()),
FlowyText.semibold(
LocaleKeys.document_plugins_cover_abstract.tr(),
color: Theme.of(context).colorScheme.tertiary,
),
const SizedBox(height: 10),
_buildAbstractImagePicker(),
],
);
}
Widget _buildImageHeader() {
return BlocBuilder<ChangeCoverPopoverBloc, ChangeCoverPopoverState>(
builder: (context, state) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
FlowyText.semibold(
LocaleKeys.document_plugins_cover_images.tr(),
color: Theme.of(context).colorScheme.tertiary,
),
FlowyTextButton(
fillColor: Theme.of(context).cardColor,
hoverColor: Theme.of(context).colorScheme.secondaryContainer,
LocaleKeys.document_plugins_cover_clearAll.tr(),
fontColor: Theme.of(context).colorScheme.tertiary,
onPressed: () {
context
.read<ChangeCoverPopoverBloc>()
.add(const ChangeCoverPopoverEvent.clearAllImages());
},
mainAxisAlignment: MainAxisAlignment.end,
),
],
);
},
);
}
Widget _buildAbstractImagePicker() {
return GridView.builder(
shrinkWrap: true,
@ -173,71 +214,59 @@ class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
}
Widget _buildFileImagePicker() {
return FutureBuilder<List<String>>(
future: _getPreviouslyPickedImagePaths(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<String> images = snapshot.data!;
return GridView.builder(
shrinkWrap: true,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1 / 0.65,
crossAxisSpacing: 7,
mainAxisSpacing: 7,
),
itemCount: images.length + 1,
itemBuilder: (BuildContext ctx, index) {
if (index == 0) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primary
.withOpacity(0.15),
border: Border.all(
color: Theme.of(context).colorScheme.primary,
),
borderRadius: Corners.s8Border,
),
child: FlowyIconButton(
iconPadding: EdgeInsets.zero,
icon: Icon(
Icons.add,
color: Theme.of(context).colorScheme.primary,
),
width: 20,
onPressed: () {
setState(() {
isAddingImage = true;
});
},
),
);
}
return InkWell(
onTap: () {
widget.onCoverChanged(
CoverSelectionType.file,
images[index - 1],
);
},
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: FileImage(File(images[index - 1])),
fit: BoxFit.cover,
),
borderRadius: Corners.s8Border,
),
return BlocBuilder<ChangeCoverPopoverBloc, ChangeCoverPopoverState>(
builder: (context, state) {
if (state is Loaded) {
List<String> images = state.imageNames;
return GridView.builder(
shrinkWrap: true,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1 / 0.65,
crossAxisSpacing: 7,
mainAxisSpacing: 7,
),
itemCount: images.length + 1,
itemBuilder: (BuildContext ctx, index) {
if (index == 0) {
return Container(
decoration: BoxDecoration(
color:
Theme.of(context).colorScheme.primary.withOpacity(0.15),
border: Border.all(
color: Theme.of(context).colorScheme.primary,
),
borderRadius: Corners.s8Border,
),
child: FlowyIconButton(
iconPadding: EdgeInsets.zero,
icon: Icon(
Icons.add,
color: Theme.of(context).colorScheme.primary,
),
width: 20,
onPressed: () {
setState(() {
isAddingImage = true;
});
},
),
);
}
return ImageGridItem(
onImageSelect: () {
widget.onCoverChanged(
CoverSelectionType.file,
images[index - 1],
);
},
imagePath: images[index - 1],
);
} else {
return Container();
}
});
},
);
}
return Container();
});
}
List<ColorOption> _generateBackgroundColorOptions(EditorState editorState) {
@ -248,19 +277,75 @@ class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
))
.toList();
}
}
Future<List<String>> _getPreviouslyPickedImagePaths() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final imageNames = prefs.getStringList(kLocalImagesKey) ?? [];
final removeNames = [];
for (final name in imageNames) {
if (!File(name).existsSync()) {
removeNames.add(name);
}
}
imageNames.removeWhere((element) => removeNames.contains(element));
prefs.setStringList(kLocalImagesKey, imageNames);
return imageNames;
class ImageGridItem extends StatefulWidget {
const ImageGridItem({
Key? key,
required this.onImageSelect,
required this.imagePath,
}) : super(key: key);
final Function() onImageSelect;
final String imagePath;
@override
State<ImageGridItem> createState() => _ImageGridItemState();
}
class _ImageGridItemState extends State<ImageGridItem> {
bool showDeleteButton = false;
@override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: (_) {
setState(() {
showDeleteButton = true;
});
},
onExit: (_) {
setState(() {
showDeleteButton = false;
});
},
child: Stack(
children: [
InkWell(
onTap: widget.onImageSelect,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: FileImage(File(widget.imagePath)),
fit: BoxFit.cover,
),
borderRadius: Corners.s8Border,
),
),
),
if (showDeleteButton)
Positioned(
right: 2,
top: 2,
child: FlowyIconButton(
fillColor:
Theme.of(context).colorScheme.surface.withOpacity(0.8),
hoverColor:
Theme.of(context).colorScheme.surface.withOpacity(0.8),
iconPadding: const EdgeInsets.all(5),
width: 28,
icon: svgWidget(
'editor/delete',
color: Theme.of(context).colorScheme.tertiary,
),
onPressed: () {
context.read<ChangeCoverPopoverBloc>().add(
ChangeCoverPopoverEvent.deleteImage(widget.imagePath));
},
),
),
],
),
);
}
}

View File

@ -0,0 +1,90 @@
import 'dart:async';
import 'dart:io';
import 'package:appflowy/plugins/document/presentation/plugins/cover/change_cover_popover.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'change_cover_popover_bloc.freezed.dart';
class ChangeCoverPopoverBloc
extends Bloc<ChangeCoverPopoverEvent, ChangeCoverPopoverState> {
late final SharedPreferences _prefs;
final _initCompleter = Completer<void>();
ChangeCoverPopoverBloc() : super(const ChangeCoverPopoverState.initial()) {
SharedPreferences.getInstance().then((prefs) {
_prefs = prefs;
_initCompleter.complete();
});
on<ChangeCoverPopoverEvent>((event, emit) async {
await event.map(
fetchPickedImagePaths:
(FetchPickedImagePaths fetchPickedImagePaths) async {
final imageNames = await _getPreviouslyPickedImagePaths();
emit(ChangeCoverPopoverState.loaded(imageNames));
},
deleteImage: (DeleteImage deleteImage) async {
final currentState = state;
if (currentState is Loaded) {
await _deleteImageInStorage(deleteImage.path);
final updateImageList = currentState.imageNames
.where((path) => path != deleteImage.path)
.toList();
await _updateImagePathsInStorage(updateImageList);
emit(Loaded(updateImageList));
}
},
clearAllImages: (ClearAllImages clearAllImages) async {
final currentState = state;
if (currentState is Loaded) {
for (final image in currentState.imageNames) {
await _deleteImageInStorage(image);
}
await _updateImagePathsInStorage([]);
emit(const Loaded([]));
}
},
);
});
}
Future<List<String>> _getPreviouslyPickedImagePaths() async {
await _initCompleter.future;
final imageNames = _prefs.getStringList(kLocalImagesKey) ?? [];
if (imageNames.isEmpty) {
return imageNames;
}
imageNames.removeWhere((name) => !File(name).existsSync());
return imageNames;
}
Future<void> _updateImagePathsInStorage(List<String> imagePaths) async {
await _initCompleter.future;
_prefs.setStringList(kLocalImagesKey, imagePaths);
return;
}
Future<void> _deleteImageInStorage(String path) async {
final imageFile = File(path);
await imageFile.delete();
}
}
@freezed
class ChangeCoverPopoverEvent with _$ChangeCoverPopoverEvent {
const factory ChangeCoverPopoverEvent.fetchPickedImagePaths() =
FetchPickedImagePaths;
const factory ChangeCoverPopoverEvent.deleteImage(String path) = DeleteImage;
const factory ChangeCoverPopoverEvent.clearAllImages() = ClearAllImages;
}
@freezed
class ChangeCoverPopoverState with _$ChangeCoverPopoverState {
const factory ChangeCoverPopoverState.initial() = Initial;
const factory ChangeCoverPopoverState.loading() = Loading;
const factory ChangeCoverPopoverState.loaded(
List<String> imageNames,
) = Loaded;
}

View File

@ -156,10 +156,7 @@ class _AddCoverButtonState extends State<_AddCoverButton> {
leftIconSize: const Size.square(18),
onTap: widget.onTap,
useIntrinsicWidth: true,
leftIcon: svgWidget(
'editor/image',
color: Theme.of(context).colorScheme.onSurface,
),
leftIcon: const FlowySvg(name: 'editor/image'),
text: FlowyText.regular(
LocaleKeys.document_plugins_cover_addCover.tr(),
),
@ -174,7 +171,7 @@ class _AddCoverButtonState extends State<_AddCoverButton> {
useIntrinsicWidth: true,
leftIcon: Icon(
Icons.emoji_emotions_outlined,
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
size: 18,
),
text: FlowyText.regular(LocaleKeys
@ -197,8 +194,7 @@ class _AddCoverButtonState extends State<_AddCoverButton> {
child: FlowyButton(
leftIconSize: const Size.square(18),
useIntrinsicWidth: true,
leftIcon: Icon(Icons.emoji_emotions_outlined,
color: Theme.of(context).colorScheme.onSurface,
leftIcon: const Icon(Icons.emoji_emotions_outlined,
size: 18),
text: FlowyText.regular(
LocaleKeys.document_plugins_cover_addIcon.tr()),
@ -400,7 +396,7 @@ class _CoverImageState extends State<_CoverImage> {
popoverController.show();
},
hoverColor: Theme.of(context).colorScheme.surface,
textColor: Theme.of(context).colorScheme.onSurface,
textColor: Theme.of(context).colorScheme.tertiary,
fillColor: Theme.of(context).colorScheme.surface.withOpacity(0.8),
width: 120,
height: 28,
@ -422,7 +418,7 @@ class _CoverImageState extends State<_CoverImage> {
width: 28,
icon: svgWidget(
'editor/delete',
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).colorScheme.tertiary,
),
onPressed: () {
widget.onCoverChanged(CoverSelectionType.initial, null);

View File

@ -17,7 +17,7 @@ SelectionMenuItem gridMenuItem = SelectionMenuItem(
: editorState.editorStyle.selectionMenuItemIconColor,
);
},
keywords: ['referenced grid'],
keywords: ['referenced', 'grid'],
handler: (editorState, menuService, context) {
showLinkToPageMenu(
editorState,

View File

@ -45,13 +45,9 @@ class MenuTrash extends StatelessWidget {
Widget _render(BuildContext context) {
return Row(
children: [
SizedBox(
width: 16,
height: 16,
child: svgWidget(
"home/trash",
color: Theme.of(context).colorScheme.onSurface,
),
const FlowySvg(
size: Size(16, 16),
name: 'home/trash',
),
const HSpace(6),
FlowyText.medium(LocaleKeys.trash_text.tr()),

View File

@ -43,7 +43,7 @@ class TrashCell extends StatelessWidget {
iconPadding: const EdgeInsets.all(5),
icon: svgWidget(
"editor/restore",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
const HSpace(20),
@ -53,7 +53,7 @@ class TrashCell extends StatelessWidget {
iconPadding: const EdgeInsets.all(5),
icon: svgWidget(
"editor/delete",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
],

View File

@ -90,6 +90,7 @@ class _TrashPageState extends State<TrashPage> {
FlowyText.semibold(
LocaleKeys.trash_text.tr(),
fontSize: FontSizes.s16,
color: Theme.of(context).colorScheme.tertiary,
),
const Spacer(),
IntrinsicWidth(
@ -97,7 +98,7 @@ class _TrashPageState extends State<TrashPage> {
text: FlowyText.medium(LocaleKeys.trash_restoreAll.tr()),
leftIcon: svgWidget(
'editor/restore',
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
onTap: () => context.read<TrashBloc>().add(
const TrashEvent.restoreAll(),
@ -110,7 +111,7 @@ class _TrashPageState extends State<TrashPage> {
text: FlowyText.medium(LocaleKeys.trash_deleteAll.tr()),
leftIcon: svgWidget(
'editor/delete',
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
onTap: () =>
context.read<TrashBloc>().add(const TrashEvent.deleteAll()),

View File

@ -46,6 +46,7 @@ class InitAppWidgetTask extends LaunchTask {
Locale('sv'),
Locale('tr', 'TR'),
Locale('zh', 'CN'),
Locale('zh', 'TW'),
],
path: 'assets/translations',
fallbackLocale: const Locale('en'),

View File

@ -2,9 +2,7 @@ import 'dart:io';
import 'package:appflowy/util/file_picker/file_picker_service.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
@ -36,10 +34,7 @@ class _FolderWidgetState extends State<FolderWidget> {
@override
Widget build(BuildContext context) {
return SizedBox(
height: 250,
child: _mapIndexToWidget(context),
);
return _mapIndexToWidget(context);
}
Widget _mapIndexToWidget(BuildContext context) {
@ -86,37 +81,24 @@ class FolderOptionsWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
shrinkWrap: true,
children: <Widget>[
Card(
child: ListTile(
title: FlowyText.medium(
LocaleKeys.settings_files_createNewFolder.tr(),
),
subtitle: FlowyText.regular(
LocaleKeys.settings_files_createNewFolderDesc.tr(),
),
trailing: _buildTextButton(
context,
LocaleKeys.settings_files_create.tr(),
onPressedCreate,
),
return Column(
children: [
_FolderCard(
title: LocaleKeys.settings_files_createNewFolder.tr(),
subtitle: LocaleKeys.settings_files_createNewFolderDesc.tr(),
trailing: _buildTextButton(
context,
LocaleKeys.settings_files_create.tr(),
onPressedCreate,
),
),
Card(
child: ListTile(
title: FlowyText.medium(
LocaleKeys.settings_files_openFolder.tr(),
),
subtitle: FlowyText.regular(
LocaleKeys.settings_files_openFolderDesc.tr(),
),
trailing: _buildTextButton(
context,
LocaleKeys.settings_files_open.tr(),
onPressedOpen,
),
_FolderCard(
title: LocaleKeys.settings_files_openFolder.tr(),
subtitle: LocaleKeys.settings_files_openFolderDesc.tr(),
trailing: _buildTextButton(
context,
LocaleKeys.settings_files_open.tr(),
onPressedOpen,
),
),
],
@ -164,56 +146,55 @@ class CreateFolderWidgetState extends State<CreateFolderWidget> {
label: const Text('Back'),
),
),
Card(
child: ListTile(
title: FlowyText.medium(
LocaleKeys.settings_files_location.tr(),
),
subtitle: FlowyText.regular(
LocaleKeys.settings_files_locationDesc.tr(),
),
trailing: SizedBox(
width: 100,
height: 36,
child: FlowyTextField(
hintText: LocaleKeys.settings_files_folderHintText.tr(),
onChanged: (name) {
_folderName = name;
},
onSubmitted: (name) {
setState(() {
_folderName = name;
});
},
_FolderCard(
title: LocaleKeys.settings_files_location.tr(),
subtitle: LocaleKeys.settings_files_locationDesc.tr(),
trailing: SizedBox(
width: 120,
child: FlowyTextField(
hintText: LocaleKeys.settings_files_folderHintText.tr(),
onChanged: (name) => _folderName = name,
onSubmitted: (name) => setState(
() => _folderName = name,
),
),
),
),
Card(
child: ListTile(
title: FlowyText.medium(LocaleKeys.settings_files_folderPath.tr()),
subtitle: FlowyText.regular(_path),
trailing: _buildTextButton(
context, LocaleKeys.settings_files_browser.tr(), () async {
_FolderCard(
title: LocaleKeys.settings_files_folderPath.tr(),
subtitle: _path,
trailing: _buildTextButton(
context,
LocaleKeys.settings_files_browser.tr(),
() async {
final dir = await getIt<FilePickerService>().getDirectoryPath();
if (dir != null) {
setState(() {
directory = dir;
});
setState(() => directory = dir);
}
}),
},
),
),
Card(
child: _buildTextButton(
context, LocaleKeys.settings_files_create.tr(), () async {
if (_path.isEmpty) {
_showToast(LocaleKeys.settings_files_locationCannotBeEmpty.tr());
} else {
await getIt<SettingsLocationCubit>().setLocation(_path);
await widget.onPressedCreate();
}
}),
const VSpace(4.0),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: Row(
children: [
_buildTextButton(
context,
LocaleKeys.settings_files_create.tr(),
() async {
if (_path.isEmpty) {
_showToast(
LocaleKeys.settings_files_locationCannotBeEmpty.tr(),
);
} else {
await getIt<SettingsLocationCubit>().setLocation(_path);
await widget.onPressedCreate();
}
},
),
],
),
)
],
);
@ -240,12 +221,70 @@ class CreateFolderWidgetState extends State<CreateFolderWidget> {
Widget _buildTextButton(
BuildContext context, String title, VoidCallback onPressed) {
return SizedBox(
width: 70,
height: 36,
child: RoundedTextButton(
title: title,
onPressed: onPressed,
),
return FlowyTextButton(
title,
onPressed: onPressed,
fillColor: Theme.of(context).colorScheme.primary,
fontColor: Theme.of(context).colorScheme.onPrimary,
hoverColor: Theme.of(context).colorScheme.primaryContainer,
);
}
class _FolderCard extends StatelessWidget {
const _FolderCard({
Key? key,
required this.title,
required this.subtitle,
this.trailing,
}) : super(key: key);
final String title;
final String subtitle;
final Widget? trailing;
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4.0,
horizontal: 16.0,
),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FlowyText.medium(
title,
),
Row(
children: [
Flexible(
child: Text(
subtitle,
overflow: TextOverflow.ellipsis,
style:
Theme.of(context).textTheme.bodyMedium!.copyWith(
fontWeight: FontWeight.w400,
),
),
),
],
),
],
),
),
if (trailing != null) ...[
const HSpace(40),
trailing!,
],
],
),
),
);
}
}

View File

@ -1,9 +1,8 @@
import 'package:appflowy/core/frameless_window.dart';
import 'package:dartz/dartz.dart' as dartz;
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
@ -39,6 +38,7 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const _SkipLoginMoveWindow(),
body: Center(
child: _renderBody(context),
),
@ -54,9 +54,13 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
logoSize: const Size.square(60),
),
const VSpace(40),
SizedBox(
width: 250,
child: GoButton(onPressed: () => _autoRegister(context)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GoButton(
onPressed: () => _autoRegister(context),
),
],
),
const VSpace(20),
SizedBox(
@ -72,18 +76,15 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
},
),
),
const VSpace(20),
SizedBox(
width: 400,
child: _buildSubscribeButtons(context),
),
const Spacer(),
_buildSubscribeButtons(context),
],
);
}
Row _buildSubscribeButtons(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisAlignment: MainAxisAlignment.center,
children: [
FlowyTextButton(
LocaleKeys.githubStarText.tr(),
@ -95,6 +96,7 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
onPressed: () =>
_launchURL('https://github.com/AppFlowy-IO/appflowy'),
),
const HSpace(20),
FlowyTextButton(
LocaleKeys.subscribeNewsletterText.tr(),
fontWeight: FontWeight.w500,
@ -149,19 +151,41 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
class GoButton extends StatelessWidget {
final VoidCallback onPressed;
const GoButton({
Key? key,
super.key,
required this.onPressed,
}) : super(key: key);
});
@override
Widget build(BuildContext context) {
return RoundedTextButton(
title: LocaleKeys.letsGoButtonText.tr(),
return FlowyTextButton(
LocaleKeys.letsGoButtonText.tr(),
fontSize: FontSizes.s16,
height: 50,
borderRadius: Corners.s10Border,
padding: const EdgeInsets.symmetric(horizontal: 80, vertical: 12.0),
onPressed: onPressed,
fillColor: Theme.of(context).colorScheme.primary,
fontColor: Theme.of(context).colorScheme.onPrimary,
hoverColor: Theme.of(context).colorScheme.primaryContainer,
);
}
}
class _SkipLoginMoveWindow extends StatelessWidget
implements PreferredSizeWidget {
const _SkipLoginMoveWindow();
@override
Widget build(BuildContext context) {
return Row(
children: const [
Expanded(
child: MoveWindowDetector(),
),
],
);
}
@override
Size get preferredSize => const Size.fromHeight(55.0);
}

View File

@ -49,6 +49,7 @@ class FlowyLogoTitle extends StatelessWidget {
FlowyText.semibold(
title,
fontSize: FontSizes.s24,
color: Theme.of(context).colorScheme.tertiary,
),
],
),

View File

@ -212,14 +212,20 @@ class AppearanceSettingsState with _$AppearanceSettingsState {
return ThemeData(
brightness: brightness,
textTheme:
_getTextTheme(fontFamily: fontFamily, fontColor: theme.shader1),
textTheme: _getTextTheme(fontFamily: fontFamily, fontColor: theme.text),
textSelectionTheme: TextSelectionThemeData(
cursorColor: theme.main2,
selectionHandleColor: theme.main2,
),
primaryIconTheme: IconThemeData(color: theme.hover),
iconTheme: IconThemeData(color: theme.shader1),
iconTheme: IconThemeData(color: theme.icon),
tooltipTheme: TooltipThemeData(
textStyle: _getFontStyle(
fontFamily: fontFamily,
fontSize: FontSizes.s11,
fontWeight: FontWeight.w400,
fontColor: theme.surface,
),
),
scrollbarTheme: ScrollbarThemeData(
thumbColor: MaterialStateProperty.all(theme.shader3),
thickness: MaterialStateProperty.resolveWith((states) {
@ -239,30 +245,38 @@ class AppearanceSettingsState with _$AppearanceSettingsState {
),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
canvasColor: theme.shader6,
dividerColor: theme.shader6,
hintColor: theme.shader3,
dividerColor: theme.divider,
hintColor: theme.hint,
//action item hover color
hoverColor: theme.hoverBG2,
disabledColor: theme.shader4,
highlightColor: theme.main1,
indicatorColor: theme.main1,
toggleableActiveColor: theme.main1,
cardColor: theme.input,
colorScheme: ColorScheme(
brightness: brightness,
primary: theme.main1,
onPrimary: _white,
primary: theme.primary,
onPrimary: theme.onPrimary,
primaryContainer: theme.main2,
onPrimaryContainer: _white,
secondary: theme.hover,
// page title hover color
secondary: theme.hoverBG1,
onSecondary: theme.shader1,
// setting value hover color
secondaryContainer: theme.selector,
onSecondaryContainer: theme.shader1,
onSecondaryContainer: theme.topbarBg,
tertiary: theme.shader7,
tertiaryContainer: theme.questionBubbleBG,
background: theme.surface,
onBackground: theme.shader1,
onBackground: theme.text,
surface: theme.surface,
onSurface: theme.shader1,
// text&icon color when it is hovered
onSurface: theme.hoverFG,
onError: theme.shader7,
error: theme.red,
outline: theme.shader4,
surfaceVariant: theme.bg1,
surfaceVariant: theme.sidebarBg,
shadow: theme.shadow,
),
extensions: [
@ -278,7 +292,7 @@ class AppearanceSettingsState with _$AppearanceSettingsState {
tint7: theme.tint7,
tint8: theme.tint8,
tint9: theme.tint9,
greyHover: theme.bg2,
greyHover: theme.hoverBG1,
greySelect: theme.bg3,
lightGreyHover: theme.shader6,
toggleOffFill: theme.shader5,

View File

@ -36,7 +36,7 @@ extension ViewExtension on ViewPB {
Widget renderThumbnail({Color? iconColor}) {
String thumbnail = "file_icon";
final Widget widget = svgWidget(thumbnail, color: iconColor);
final Widget widget = FlowySvg(name: thumbnail);
return widget;
}

View File

@ -199,7 +199,7 @@ class HomeTopBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).colorScheme.surface,
color: Theme.of(context).colorScheme.onSecondaryContainer,
height: HomeSizes.topBarHeight,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,

View File

@ -18,9 +18,14 @@ class NewAppButton extends StatelessWidget {
LocaleKeys.newPageText.tr(),
fillColor: Colors.transparent,
hoverColor: Colors.transparent,
fontColor: Theme.of(context).colorScheme.onSurfaceVariant,
fontColor: Theme.of(context).colorScheme.tertiary,
onPressed: () async => await _showCreateAppDialog(context),
heading: svgWidget("home/new_app", size: const Size(16, 16)),
heading: Theme.of(context).brightness == Brightness.light
? svgWidget("home/new_app", size: const Size(16, 16))
: svgWidget(
"home/new_app_dark",
size: const Size(16, 16),
),
padding: EdgeInsets.symmetric(horizontal: Insets.l, vertical: 20),
);

View File

@ -6,9 +6,9 @@ import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_editor/appflowy_editor.dart' show Document;
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
@ -50,13 +50,19 @@ class AddButton extends StatelessWidget {
actions: actions,
offset: const Offset(0, 8),
buildChild: (controller) {
return FlowyIconButton(
return SizedBox(
width: 22,
onPressed: () => controller.show(),
icon: svgWidget(
"home/add",
color: Theme.of(context).colorScheme.onSurface,
).padding(horizontal: 3, vertical: 3),
child: InkWell(
onTap: () => controller.show(),
child: FlowyHover(
style: HoverStyle(
hoverColor: AFThemeExtension.of(context).greySelect,
),
builder: (context, onHover) => const FlowySvg(
name: 'home/add',
),
),
),
);
},
onSelected: (action, controller) {
@ -83,8 +89,7 @@ class AddButtonActionWrapper extends ActionCell {
AddButtonActionWrapper({required this.pluginBuilder});
@override
Widget? leftIcon(Color iconColor) =>
svgWidget(pluginBuilder.menuIcon, color: iconColor);
Widget? leftIcon(Color iconColor) => FlowySvg(name: pluginBuilder.menuIcon);
@override
String get name => pluginBuilder.menuName;
@ -100,9 +105,8 @@ class ImportActionWrapper extends ActionCell {
});
@override
Widget? leftIcon(Color iconColor) => svgWidget(
'editor/import',
color: iconColor,
Widget? leftIcon(Color iconColor) => const FlowySvg(
name: 'editor/import',
);
@override

View File

@ -5,7 +5,6 @@ import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:expandable/expandable.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra/icon_data.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/app.pb.dart';
@ -15,7 +14,6 @@ import 'package:appflowy/workspace/application/app/app_bloc.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:flowy_infra/image.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
import '../menu_app.dart';
import 'add_button.dart';
@ -58,7 +56,7 @@ class MenuAppHeader extends StatelessWidget {
theme: ExpandableThemeData(
expandIcon: FlowyIconData.drop_down_show,
collapseIcon: FlowyIconData.drop_down_hide,
iconColor: Theme.of(context).colorScheme.onSurface,
iconColor: Theme.of(context).colorScheme.tertiary,
iconSize: MenuAppSizes.iconSize,
iconPadding: const EdgeInsets.fromLTRB(0, 0, 10, 0),
hasIcon: false,
@ -104,7 +102,6 @@ class MenuAppHeader extends StatelessWidget {
Widget _renderCreateViewButton(BuildContext context) {
return Tooltip(
message: LocaleKeys.menuAppHeader_addPageTooltip.tr(),
textStyle: AFThemeExtension.of(context).caption.textColor(Colors.white),
child: AddButton(
onSelected: (pluginBuilder, document) {
context.read<AppBloc>().add(
@ -139,9 +136,9 @@ extension AppDisclosureExtension on AppDisclosureAction {
Widget icon(Color iconColor) {
switch (this) {
case AppDisclosureAction.rename:
return svgWidget('editor/edit', color: iconColor);
return const FlowySvg(name: 'editor/edit');
case AppDisclosureAction.delete:
return svgWidget('editor/delete', color: iconColor);
return const FlowySvg(name: 'editor/delete');
}
}
}
@ -174,6 +171,7 @@ class AppActionList extends StatelessWidget {
builder: (context, app) => FlowyText.medium(
app.name,
overflow: TextOverflow.ellipsis,
color: Theme.of(context).colorScheme.tertiary,
),
),
);

View File

@ -24,6 +24,7 @@ Future<void> showImportPanel(
title: FlowyText.semibold(
LocaleKeys.moreAction_import.tr(),
fontSize: 20,
color: Theme.of(context).colorScheme.tertiary,
),
content: _ImportPanel(importCallback: callback),
contentPadding: const EdgeInsets.symmetric(

View File

@ -4,7 +4,6 @@ import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
@ -51,7 +50,7 @@ class ViewSectionItem extends StatelessWidget {
onTap: () => onSelected(blocContext.read<ViewBloc>().state.view),
child: FlowyHover(
style: HoverStyle(
hoverColor: AFThemeExtension.of(context).greySelect,
hoverColor: Theme.of(context).colorScheme.secondary,
),
// If current state.isEditing is true, the hover should not
// rebuild when onEnter/onExit events happened.
@ -60,7 +59,6 @@ class ViewSectionItem extends StatelessWidget {
blocContext,
onHover,
state,
Theme.of(context).colorScheme.onSurface,
),
isSelected: () => state.isEditing || isSelected,
),
@ -75,13 +73,12 @@ class ViewSectionItem extends StatelessWidget {
BuildContext blocContext,
bool onHover,
ViewState state,
Color iconColor,
) {
List<Widget> children = [
SizedBox(
width: 16,
height: 16,
child: state.view.renderThumbnail(iconColor: iconColor),
child: state.view.renderThumbnail(),
),
const HSpace(2),
Expanded(
@ -154,11 +151,11 @@ extension ViewDisclosureExtension on ViewDisclosureAction {
Widget icon(Color iconColor) {
switch (this) {
case ViewDisclosureAction.rename:
return svgWidget('editor/edit', color: iconColor);
return const FlowySvg(name: 'editor/edit');
case ViewDisclosureAction.delete:
return svgWidget('editor/delete', color: iconColor);
return const FlowySvg(name: 'editor/delete');
case ViewDisclosureAction.duplicate:
return svgWidget('editor/copy', color: iconColor);
return const FlowySvg(name: 'editor/copy');
}
}
}
@ -186,7 +183,7 @@ class ViewDisclosureButton extends StatelessWidget {
width: 26,
icon: svgWidget(
"editor/details",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
onPressed: () {
onEdit(true);

View File

@ -229,7 +229,7 @@ class MenuTopBar extends StatelessWidget {
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
icon: svgWidget(
"home/hide_menu",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
),
)

View File

@ -2,7 +2,6 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/menu/menu_user_bloc.dart';
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
@ -13,7 +12,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
class MenuUser extends StatelessWidget {
final UserProfilePB user;
@ -69,6 +67,7 @@ class MenuUser extends StatelessWidget {
return FlowyText.medium(
name,
overflow: TextOverflow.ellipsis,
color: Theme.of(context).colorScheme.tertiary,
);
}
@ -76,7 +75,6 @@ class MenuUser extends StatelessWidget {
final userProfile = context.read<MenuUserBloc>().state.userProfile;
return Tooltip(
message: LocaleKeys.settings_menu_open.tr(),
textStyle: AFThemeExtension.of(context).caption.textColor(Colors.white),
child: IconButton(
onPressed: () {
showDialog(
@ -90,7 +88,7 @@ class MenuUser extends StatelessWidget {
dimension: 20,
child: svgWidget(
"home/settings",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).colorScheme.tertiary,
),
),
),

View File

@ -6,14 +6,12 @@ import 'package:appflowy/workspace/presentation/home/home_stack.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
typedef NaviAction = void Function();
@ -87,7 +85,7 @@ class FlowyNavigation extends StatelessWidget {
iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2),
icon: svgWidget(
"home/hide_menu",
color: Theme.of(context).colorScheme.onSurface,
color: Theme.of(context).iconTheme.color,
),
)),
);
@ -180,11 +178,9 @@ TextSpan sidebarTooltipTextSpan(BuildContext context, String hintText) =>
children: [
TextSpan(
text: "$hintText\n",
style: AFThemeExtension.of(context).callout.textColor(Colors.white),
),
TextSpan(
text: Platform.isMacOS ? "⌘+\\" : "Ctrl+\\",
style: AFThemeExtension.of(context).caption.textColor(Colors.white60),
),
],
);

View File

@ -32,6 +32,7 @@ class SettingsDialog extends StatelessWidget {
LocaleKeys.settings_title.tr(),
fontSize: 20,
fontWeight: FontWeight.w700,
color: Theme.of(context).colorScheme.tertiary,
),
),
child: ScaffoldMessenger(
@ -54,7 +55,9 @@ class SettingsDialog extends StatelessWidget {
context.read<SettingsDialogBloc>().state.page,
),
),
const VerticalDivider(),
VerticalDivider(
color: Theme.of(context).dividerColor,
),
const SizedBox(width: 10),
Expanded(
child: getSettingsView(

View File

@ -50,8 +50,8 @@ class ThemeSetting extends StatelessWidget {
direction: PopoverDirection.bottomWithRightAligned,
child: FlowyTextButton(
currentTheme,
fontColor: Theme.of(context).colorScheme.onBackground,
fillColor: Colors.transparent,
hoverColor: Theme.of(context).colorScheme.secondary,
onPressed: () {},
),
popupBuilder: (BuildContext context) {
@ -107,8 +107,8 @@ class ThemeModeSetting extends StatelessWidget {
direction: PopoverDirection.bottomWithRightAligned,
child: FlowyTextButton(
_themeModeLabelText(currentThemeMode),
fontColor: Theme.of(context).colorScheme.onBackground,
fillColor: Colors.transparent,
hoverColor: Theme.of(context).colorScheme.secondary,
onPressed: () {},
),
popupBuilder: (BuildContext context) {

View File

@ -47,7 +47,7 @@ class _LanguageSelectorDropdownState extends State<LanguageSelectorDropdown> {
void hoverEnterLanguage() {
setState(() {
currHoverColor = Theme.of(context).colorScheme.primary;
currHoverColor = Theme.of(context).colorScheme.secondaryContainer;
});
}
@ -67,6 +67,7 @@ class _LanguageSelectorDropdownState extends State<LanguageSelectorDropdown> {
padding: const EdgeInsets.symmetric(horizontal: 6),
child: DropdownButton<Locale>(
value: context.locale,
dropdownColor: Theme.of(context).cardColor,
onChanged: (locale) {
context
.read<AppearanceSettingsCubit>()
@ -80,7 +81,10 @@ class _LanguageSelectorDropdownState extends State<LanguageSelectorDropdown> {
value: locale,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: FlowyText.medium(languageFromLocale(locale)),
child: FlowyText.medium(
languageFromLocale(locale),
color: Theme.of(context).colorScheme.tertiary,
),
),
);
}).toList(),

View File

@ -1,5 +1,6 @@
import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
@ -21,29 +22,32 @@ class SettingsMenuElement extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(
icon,
size: 16,
color: page == selectedPage
? Theme.of(context).colorScheme.onSurface
: Theme.of(context).colorScheme.onSurface,
return FlowyHover(
style: HoverStyle(
hoverColor: Theme.of(context).colorScheme.primary,
),
onTap: () {
changeSelectedPage(page);
},
selected: page == selectedPage,
selectedColor: Theme.of(context).colorScheme.onSurface,
selectedTileColor: Theme.of(context).colorScheme.primaryContainer,
hoverColor: Theme.of(context).colorScheme.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
minLeadingWidth: 0,
title: FlowyText.semibold(
label,
fontSize: FontSizes.s14,
overflow: TextOverflow.ellipsis,
child: ListTile(
leading: Icon(icon,
size: 16,
color: page == selectedPage
? Theme.of(context).colorScheme.onSurface
: null),
onTap: () {
changeSelectedPage(page);
},
selected: page == selectedPage,
selectedColor: Theme.of(context).colorScheme.onSurface,
selectedTileColor: Theme.of(context).colorScheme.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
minLeadingWidth: 0,
title: FlowyText.semibold(label,
fontSize: FontSizes.s14,
overflow: TextOverflow.ellipsis,
color: page == selectedPage
? Theme.of(context).colorScheme.onSurface
: null),
),
);
}

View File

@ -48,6 +48,9 @@ class BubbleActionList extends StatelessWidget {
'?',
tooltip: LocaleKeys.questionBubble_help.tr(),
fontWeight: FontWeight.w600,
fontColor: Theme.of(context).colorScheme.tertiary,
fillColor: Theme.of(context).colorScheme.tertiaryContainer,
hoverColor: Theme.of(context).colorScheme.tertiaryContainer,
mainAxisAlignment: MainAxisAlignment.center,
radius: Corners.s10Border,
onPressed: () => controller.show(),
@ -200,7 +203,7 @@ extension QuestionBubbleExtension on BubbleAction {
case BubbleAction.debug:
return '🐛';
case BubbleAction.shortcuts:
return '⌨️';
return '📋';
}
}
}

View File

@ -8,6 +8,7 @@ import 'package:appflowy_editor/src/render/link_menu/link_menu.dart';
import 'package:appflowy_editor/src/extensions/text_node_extensions.dart';
import 'package:appflowy_editor/src/extensions/editor_state_extensions.dart';
import 'package:appflowy_editor/src/service/default_text_operations/format_rich_text_style.dart';
import 'dart:io' show Platform;
import 'package:flutter/material.dart' hide Overlay, OverlayEntry;
@ -127,7 +128,9 @@ List<ToolbarItem> defaultToolbarItems = [
ToolbarItem(
id: 'appflowy.toolbar.bold',
type: 2,
tooltipsMessage: AppFlowyEditorLocalizations.current.bold,
tooltipsMessage: AppFlowyEditorLocalizations.current.bold +
"\n" +
(Platform.isMacOS ? "⌘ + B" : "CTRL + B"),
iconBuilder: (isHighlight) => FlowySvg(
name: 'toolbar/bold',
color: isHighlight ? Colors.lightBlue : null,
@ -143,7 +146,9 @@ List<ToolbarItem> defaultToolbarItems = [
ToolbarItem(
id: 'appflowy.toolbar.italic',
type: 2,
tooltipsMessage: AppFlowyEditorLocalizations.current.italic,
tooltipsMessage: AppFlowyEditorLocalizations.current.italic +
"\n" +
(Platform.isMacOS ? "⌘ + I" : "CTRL + I"),
iconBuilder: (isHighlight) => FlowySvg(
name: 'toolbar/italic',
color: isHighlight ? Colors.lightBlue : null,
@ -159,7 +164,9 @@ List<ToolbarItem> defaultToolbarItems = [
ToolbarItem(
id: 'appflowy.toolbar.underline',
type: 2,
tooltipsMessage: AppFlowyEditorLocalizations.current.underline,
tooltipsMessage: AppFlowyEditorLocalizations.current.underline +
"\n" +
(Platform.isMacOS ? "⌘ + U" : "CTRL + U"),
iconBuilder: (isHighlight) => FlowySvg(
name: 'toolbar/underline',
color: isHighlight ? Colors.lightBlue : null,
@ -175,7 +182,9 @@ List<ToolbarItem> defaultToolbarItems = [
ToolbarItem(
id: 'appflowy.toolbar.strikethrough',
type: 2,
tooltipsMessage: AppFlowyEditorLocalizations.current.strikethrough,
tooltipsMessage: AppFlowyEditorLocalizations.current.strikethrough +
"\n" +
(Platform.isMacOS ? "⌘ + SHIFT + S" : "CTRL + SHIFT + S"),
iconBuilder: (isHighlight) => FlowySvg(
name: 'toolbar/strikethrough',
color: isHighlight ? Colors.lightBlue : null,
@ -191,7 +200,9 @@ List<ToolbarItem> defaultToolbarItems = [
ToolbarItem(
id: 'appflowy.toolbar.code',
type: 2,
tooltipsMessage: AppFlowyEditorLocalizations.current.embedCode,
tooltipsMessage: AppFlowyEditorLocalizations.current.embedCode +
"\n" +
(Platform.isMacOS ? "⌘ + E" : "CTRL + E"),
iconBuilder: (isHighlight) => FlowySvg(
name: 'toolbar/code',
color: isHighlight ? Colors.lightBlue : null,
@ -238,10 +249,28 @@ List<ToolbarItem> defaultToolbarItems = [
),
handler: (editorState, context) => formatBulletedList(editorState),
),
ToolbarItem(
id: 'appflowy.toolbar.number_list',
type: 3,
tooltipsMessage: AppFlowyEditorLocalizations.current.numberedList,
iconBuilder: (isHighlight) => FlowySvg(
name: 'toolbar/number_list',
color: isHighlight ? Colors.lightBlue : null,
),
validator: _onlyShowInSingleTextSelection,
highlightCallback: (editorState) => _allSatisfy(
editorState,
BuiltInAttributeKey.subtype,
(value) => value == BuiltInAttributeKey.numberList,
),
handler: (editorState, context) => formatNumberedList(editorState),
),
ToolbarItem(
id: 'appflowy.toolbar.link',
type: 4,
tooltipsMessage: AppFlowyEditorLocalizations.current.link,
tooltipsMessage: AppFlowyEditorLocalizations.current.link +
"\n" +
(Platform.isMacOS ? "⌘ + K" : "CTRL + K"),
iconBuilder: (isHighlight) => FlowySvg(
name: 'toolbar/link',
color: isHighlight ? Colors.lightBlue : null,
@ -257,7 +286,9 @@ List<ToolbarItem> defaultToolbarItems = [
ToolbarItem(
id: 'appflowy.toolbar.highlight',
type: 4,
tooltipsMessage: AppFlowyEditorLocalizations.current.highlight,
tooltipsMessage: AppFlowyEditorLocalizations.current.highlight +
"\n" +
(Platform.isMacOS ? "⌘ + SHIFT + H" : "CTRL + SHIFT + H"),
iconBuilder: (isHighlight) => FlowySvg(
name: 'toolbar/highlight',
color: isHighlight ? Colors.lightBlue : null,

View File

@ -21,6 +21,7 @@ class ToolbarItemWidget extends StatelessWidget {
width: 28,
height: 28,
child: Tooltip(
textAlign: TextAlign.center,
preferBelow: false,
message: item.tooltipsMessage,
child: MouseRegion(

View File

@ -91,6 +91,13 @@ void formatBulletedList(EditorState editorState) {
});
}
void formatNumberedList(EditorState editorState) {
formatTextNodes(editorState, {
BuiltInAttributeKey.subtype: BuiltInAttributeKey.numberList,
BuiltInAttributeKey.number: 1,
});
}
/// Format the current selection with the given attributes.
///
/// If the selected nodes are not text nodes, this method will do nothing.

View File

@ -310,6 +310,47 @@ ShortcutEventHandler underscoreToItalicHandler = (editorState, event) {
return KeyEventResult.handled;
};
//Same functionality implemented via Asterisk - for italics
ShortcutEventHandler asteriskToItalicHandler = (editorState, event) {
final selectionService = editorState.service.selectionService;
final selection = selectionService.currentSelection.value;
final textNodes = selectionService.currentSelectedNodes.whereType<TextNode>();
if (selection == null || !selection.isSingle || textNodes.length != 1) {
return KeyEventResult.ignored;
}
final textNode = textNodes.first;
final text = textNode.toPlainText();
// Determine if an 'asterisk' already exists in the text node and only once.
final firstAsterisk = text.indexOf('*');
final lastAsterisk = text.lastIndexOf('*');
if (firstAsterisk == -1 ||
firstAsterisk != lastAsterisk ||
firstAsterisk == selection.start.offset - 1) {
return KeyEventResult.ignored;
}
final transaction = editorState.transaction
..deleteText(textNode, firstAsterisk, 1)
..formatText(
textNode,
firstAsterisk,
selection.end.offset - firstAsterisk - 1,
{
BuiltInAttributeKey.italic: true,
},
)
..afterSelection = Selection.collapsed(
Position(
path: textNode.path,
offset: selection.end.offset - 1,
),
);
editorState.apply(transaction);
return KeyEventResult.handled;
};
ShortcutEventHandler doubleAsteriskToBoldHandler = (editorState, event) {
final selectionService = editorState.service.selectionService;
final selection = selectionService.currentSelection.value;

View File

@ -307,6 +307,11 @@ List<ShortcutEvent> builtInShortcutEvents = [
character: '_',
handler: underscoreToItalicHandler,
),
ShortcutEvent(
key: 'Asterisk to italic',
character: '*',
handler: asteriskToItalicHandler,
),
ShortcutEvent(
key: 'Double asterisk to bold',
character: '*',

View File

@ -302,6 +302,33 @@ void main() async {
});
}));
group('toolbar, number list' , (() {
testWidgets('Select Text, Click Toolbar and set style for number list',
(tester) async {
final editor = tester.editor..insertTextNode(singleLineText);
await editor.startTesting();
final numberList = Selection(
start: Position(path: [0],offset: 0),
end: Position(path: [0], offset: singleLineText.length));
await editor.updateSelection(numberList);
await tester.pumpAndSettle(const Duration(milliseconds: 500));
expect(find.byType(ToolbarWidget), findsOneWidget);
final numberListButton = find.byWidgetPredicate((widget) {
if (widget is ToolbarItemWidget) {
return widget.item.id == 'appflowy.toolbar.number_list';
}
return false;
});
expect(numberListButton, findsOneWidget);
await tester.tap(numberListButton);
await tester.pumpAndSettle();
final node = editor.nodeAtPath([0]) as TextNode;
expect(node.subtype, 'number-list');
});
}));
group('toolbar, highlight', (() {
testWidgets('Select Text, Click Toolbar and set style for highlighted text',
(tester) async {

View File

@ -441,4 +441,53 @@ void main() async {
expect(textNode.toPlainText(), text);
}));
});
group('Convert single asterisk to italic', () {
testWidgets('Test Single Asterisk for Italics', (tester) async {
const text = '*Hello World';
final editor = tester.editor..insertTextNode(text);
await editor.startTesting();
await editor.updateSelection(
Selection.single(path: [0], startOffset: text.length),
);
await editor.pressLogicKey(character: '*');
final textNode = editor.nodeAtPath([0]) as TextNode;
final allItalic = textNode.allSatisfyItalicInSelection(
Selection.single(
path: [0],
startOffset: 0,
endOffset: text.length - 1, // delete the first *
),
);
expect(allItalic, true);
});
testWidgets(
'nothing happens if there\'re more than one * precede the current position',
(tester) async {
const text = '**Hello World';
final editor = tester.editor..insertTextNode(text);
await editor.startTesting();
await editor.updateSelection(
Selection.single(path: [0], startOffset: text.length),
);
await editor.pressLogicKey(character: '*');
await tester.pumpAndSettle();
final textNode = editor.nodeAtPath([0]) as TextNode;
final allItalic = textNode.allSatisfyItalicInSelection(
Selection.single(
path: [0],
startOffset: 0,
endOffset: text.length, // insert a new *
),
);
expect(allItalic, false);
});
});
}

View File

@ -56,6 +56,22 @@ abstract class FlowyColorScheme {
final Color main1;
final Color main2;
final Color shadow;
final Color sidebarBg;
final Color divider;
final Color topbarBg;
final Color icon;
final Color text;
final Color input;
final Color hint;
final Color primary;
final Color onPrimary;
//page title hover effect
final Color hoverBG1;
//action item hover effect
final Color hoverBG2;
//the text color when it is hovered
final Color hoverFG;
final Color questionBubbleBG;
const FlowyColorScheme({
required this.surface,
@ -87,6 +103,19 @@ abstract class FlowyColorScheme {
required this.main1,
required this.main2,
required this.shadow,
required this.sidebarBg,
required this.divider,
required this.topbarBg,
required this.icon,
required this.text,
required this.input,
required this.hint,
required this.primary,
required this.onPrimary,
required this.hoverBG1,
required this.hoverBG2,
required this.hoverFG,
required this.questionBubbleBG,
});
factory FlowyColorScheme.builtIn(String themeName, Brightness brightness) {

View File

@ -4,6 +4,21 @@ import 'colorscheme.dart';
const _black = Color(0xff000000);
const _white = Color(0xFFFFFFFF);
const _lightHover = Color(0xFFe0f8ff);
const _lightSelector = Color(0xfff2fcff);
const _lightBg1 = Color(0xFFFFD13E);
const _lightBg2 = Color(0xffedeef2);
const _lightShader1 = Color(0xff333333);
const _lightShader3 = Color(0xff828282);
const _lightShader6 = Color(0xfff2f2f2);
const _lightMain1 = Color(0xffe21f74);
const _darkShader1 = Color(0xff131720);
const _darkShader2 = Color(0xff1A202C);
const _darkShader3 = Color(0xff363D49);
const _darkShader5 = Color(0xffBBC3CD);
const _darkShader6 = Color(0xffF2F2F2);
const _darkMain1 = Color(0xffe21f74);
class DandelionColorScheme extends FlowyColorScheme {
const DandelionColorScheme.light()
@ -20,8 +35,8 @@ class DandelionColorScheme extends FlowyColorScheme {
shader4: const Color(0xffbdbdbd),
shader5: const Color(0xffe0e0e0),
shader6: const Color(0xfff2f2f2),
shader7: const Color(0xffffffff),
bg1: const Color(0xFFFFD13E),
shader7: _black,
bg1: _lightBg1,
bg2: const Color(0xffedeef2),
bg3: const Color(0xffe2e4eb),
bg4: const Color(0xff2c144b),
@ -34,9 +49,22 @@ class DandelionColorScheme extends FlowyColorScheme {
tint7: const Color(0xffddffd6),
tint8: const Color(0xffdefff1),
tint9: const Color(0xffe1fbff),
main1: const Color(0xffe21f74),
main1: _lightMain1,
main2: const Color.fromARGB(255, 224, 25, 111),
shadow: _black,
sidebarBg: _lightBg1,
divider: _lightShader6,
topbarBg: _white,
icon: _lightShader1,
text: _lightShader1,
input: _white,
hint: _lightShader3,
primary: _lightMain1,
onPrimary: _white,
hoverBG1: _lightBg2,
hoverBG2: _lightHover,
hoverFG: _lightShader1,
questionBubbleBG: _lightSelector,
);
const DandelionColorScheme.dark()
@ -48,12 +76,12 @@ class DandelionColorScheme extends FlowyColorScheme {
yellow: const Color(0xffffd667),
green: const Color(0xff66cf80),
shader1: _white,
shader2: const Color(0xffffffff),
shader2: _darkShader2,
shader3: const Color(0xff828282),
shader4: const Color(0xffbdbdbd),
shader5: _white,
shader6: _black,
shader7: _black,
shader5: _darkShader5,
shader6: _darkShader6,
shader7: _white,
bg1: const Color(0xFFD5A200),
bg2: _black,
bg3: const Color(0xff4f4f4f),
@ -67,8 +95,21 @@ class DandelionColorScheme extends FlowyColorScheme {
tint7: const Color(0xffbcffad),
tint8: const Color(0xffadffe2),
tint9: const Color(0xffade4ff),
main1: const Color(0xffe21f74),
main1: _darkMain1,
main2: const Color.fromARGB(255, 224, 25, 111),
shadow: _black,
sidebarBg: const Color(0xff232B38),
divider: _darkShader3,
topbarBg: _darkShader1,
icon: _darkShader5,
text: _darkShader5,
input: const Color(0xff282E3A),
hint: _darkShader5,
primary: _darkMain1,
onPrimary: _darkShader1,
hoverBG1: _darkMain1,
hoverBG2: _darkMain1,
hoverFG: _darkShader1,
questionBubbleBG: _darkShader3,
);
}

View File

@ -4,25 +4,39 @@ import 'colorscheme.dart';
const _black = Color(0xff000000);
const _white = Color(0xFFFFFFFF);
const _lightHover = Color(0xFFe0f8ff);
const _lightSelector = Color(0xfff2fcff);
const _lightBg1 = Color(0xfff7f8fc);
const _lightBg2 = Color(0xffedeef2);
const _lightShader1 = Color(0xff333333);
const _lightShader3 = Color(0xff828282);
const _lightShader6 = Color(0xfff2f2f2);
const _lightMain1 = Color(0xff00bcf0);
const _darkShader1 = Color(0xff131720);
const _darkShader2 = Color(0xff1A202C);
const _darkShader3 = Color(0xff363D49);
const _darkShader5 = Color(0xffBBC3CD);
const _darkShader6 = Color(0xffF2F2F2);
const _darkMain1 = Color(0xff00BCF0);
class DefaultColorScheme extends FlowyColorScheme {
const DefaultColorScheme.light()
: super(
surface: Colors.white,
hover: const Color(0xFFe0f8ff),
selector: const Color(0xfff2fcff),
surface: _white,
hover: _lightHover,
selector: _lightSelector,
red: const Color(0xfffb006d),
yellow: const Color(0xffffd667),
green: const Color(0xff66cf80),
shader1: const Color(0xff333333),
shader1: _lightShader1,
shader2: const Color(0xff4f4f4f),
shader3: const Color(0xff828282),
shader3: _lightShader3,
shader4: const Color(0xffbdbdbd),
shader5: const Color(0xffe0e0e0),
shader6: const Color(0xfff2f2f2),
shader7: const Color(0xffffffff),
bg1: const Color(0xfff7f8fc),
bg2: const Color(0xffedeef2),
shader6: _lightShader6,
shader7: _lightShader1,
bg1: _lightBg1,
bg2: _lightBg2,
bg3: const Color(0xffe2e4eb),
bg4: const Color(0xff2c144b),
tint1: const Color(0xffe8e0ff),
@ -34,41 +48,67 @@ class DefaultColorScheme extends FlowyColorScheme {
tint7: const Color(0xffddffd6),
tint8: const Color(0xffdefff1),
tint9: const Color(0xffe1fbff),
main1: const Color(0xff00bcf0),
main1: _lightMain1,
main2: const Color(0xff00b7ea),
shadow: _black,
sidebarBg: _lightBg1,
divider: _lightShader6,
topbarBg: _white,
icon: _lightShader1,
text: _lightShader1,
input: _white,
hint: _lightShader3,
primary: _lightMain1,
onPrimary: _white,
hoverBG1: _lightBg2,
hoverBG2: _lightHover,
hoverFG: _lightShader1,
questionBubbleBG: _lightSelector,
);
const DefaultColorScheme.dark()
: super(
surface: const Color(0xff292929),
hover: const Color(0xff1f1f1f),
selector: const Color(0xff333333),
surface: _darkShader2,
hover: _darkMain1,
selector: _darkShader2,
red: const Color(0xfffb006d),
yellow: const Color(0xffffd667),
green: const Color(0xff66cf80),
shader1: _white,
shader2: const Color(0xffffffff),
shader3: const Color(0xff828282),
shader4: const Color(0xffbdbdbd),
shader5: _white,
shader6: _black,
shader7: _black,
bg1: _black,
bg2: _black,
bg3: const Color(0xff4f4f4f),
bg4: const Color(0xff2c144b),
tint1: const Color(0xffc3adff),
tint2: const Color(0xffffadf9),
tint3: const Color(0xffffadad),
tint4: const Color(0xffffcfad),
tint5: const Color(0xfffffead),
tint6: const Color(0xffe6ffa3),
tint7: const Color(0xffbcffad),
tint8: const Color(0xffadffe2),
tint9: const Color(0xffade4ff),
main1: const Color(0xff00bcf0),
main2: const Color(0xff009cc7),
shadow: _black,
yellow: const Color(0xffF7CF46),
green: const Color(0xff66CF80),
shader1: _darkShader1,
shader2: _darkShader2,
shader3: _darkShader3,
shader4: const Color(0xff7C8CA5),
shader5: _darkShader5,
shader6: _darkShader6,
shader7: _white,
bg1: const Color(0xffF7F8FC),
bg2: const Color(0xffEDEEF2),
bg3: _darkMain1,
bg4: const Color(0xff2C144B),
tint1: const Color(0xff8738F5),
tint2: const Color(0xffE6336E),
tint3: const Color(0xffFF2D9E),
tint4: const Color(0xffE9973E),
tint5: const Color(0xffFBF000),
tint6: const Color(0xffC0F000),
tint7: const Color(0xff15F74E),
tint8: const Color(0xff00F0E2),
tint9: const Color(0xff00BCF0),
main1: _darkMain1,
main2: const Color(0xff00B7EA),
shadow: const Color(0xff0F131C),
sidebarBg: const Color(0xff232B38),
divider: _darkShader3,
topbarBg: _darkShader1,
icon: _darkShader5,
text: _darkShader5,
input: const Color(0xff282E3A),
hint: _darkShader5,
primary: _darkMain1,
onPrimary: _darkShader1,
hoverBG1: _darkMain1,
hoverBG2: _darkMain1,
hoverFG: _darkShader1,
questionBubbleBG: _darkShader3,
);
}

View File

@ -5,6 +5,22 @@ import 'colorscheme.dart';
const _black = Color(0xff000000);
const _white = Color(0xFFFFFFFF);
const _lightHover = Color(0xFFe0f8ff);
const _lightSelector = Color(0xfff2fcff);
const _lightBg1 = Color(0xfff7f8fc);
const _lightBg2 = Color(0xffedeef2);
const _lightShader1 = Color(0xff333333);
const _lightShader3 = Color(0xff828282);
const _lightShader6 = Color(0xfff2f2f2);
const _lightMain1 = Color(0xffA652FB);
const _darkShader1 = Color(0xff131720);
const _darkShader2 = Color(0xff1A202C);
const _darkShader3 = Color(0xff363D49);
const _darkShader5 = Color(0xffBBC3CD);
const _darkShader6 = Color(0xffF2F2F2);
const _darkMain1 = Color(0xffA652FB);
class LavenderColorScheme extends FlowyColorScheme {
const LavenderColorScheme.light()
: super(
@ -20,7 +36,7 @@ class LavenderColorScheme extends FlowyColorScheme {
shader4: const Color(0xffbdbdbd),
shader5: const Color(0xffe0e0e0),
shader6: const Color(0xfff2f2f2),
shader7: const Color(0xffffffff),
shader7: _black,
bg1: const Color(0xffAC59FF),
bg2: const Color(0xffedeef2),
bg3: const Color(0xffe2e4eb),
@ -34,9 +50,22 @@ class LavenderColorScheme extends FlowyColorScheme {
tint7: const Color(0xffddffd6),
tint8: const Color(0xffdefff1),
tint9: const Color(0xffe1fbff),
main1: const Color(0xffA652FB),
main1: _lightMain1,
main2: const Color(0xff9327FF),
shadow: _black,
sidebarBg: _lightBg1,
divider: _lightShader6,
topbarBg: _white,
icon: _lightShader1,
text: _lightShader1,
input: _white,
hint: _lightShader3,
primary: _lightMain1,
onPrimary: _white,
hoverBG1: _lightBg2,
hoverBG2: _lightHover,
hoverFG: _lightShader1,
questionBubbleBG: _lightSelector,
);
const LavenderColorScheme.dark()
@ -48,12 +77,12 @@ class LavenderColorScheme extends FlowyColorScheme {
yellow: const Color(0xffffd667),
green: const Color(0xff66cf80),
shader1: _white,
shader2: const Color(0xffffffff),
shader2: _darkShader2,
shader3: const Color(0xff828282),
shader4: const Color(0xffbdbdbd),
shader5: _white,
shader6: _black,
shader7: _black,
shader6: _darkShader6,
shader7: _white,
bg1: const Color(0xff8C23F6),
bg2: _black,
bg3: const Color(0xff4f4f4f),
@ -67,8 +96,21 @@ class LavenderColorScheme extends FlowyColorScheme {
tint7: const Color(0xffbcffad),
tint8: const Color(0xffadffe2),
tint9: const Color(0xffade4ff),
main1: const Color(0xffA652FB),
main1: _darkMain1,
main2: const Color(0xff9327FF),
shadow: _black,
sidebarBg: const Color(0xff232B38),
divider: _darkShader3,
topbarBg: _darkShader1,
icon: _darkShader5,
text: _darkShader5,
input: const Color(0xff282E3A),
hint: _darkShader5,
primary: _darkMain1,
onPrimary: _darkShader1,
hoverBG1: _darkMain1,
hoverBG2: _darkMain1,
hoverFG: _darkShader1,
questionBubbleBG: _darkShader3,
);
}

View File

@ -1,6 +1,30 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter/material.dart';
/// For icon that needs to change color when it is on hovered
///
/// Get the hover color from ThemeData
class FlowySvg extends StatelessWidget {
const FlowySvg({super.key, this.size, required this.name});
final String name;
final Size? size;
@override
Widget build(BuildContext context) {
if (size != null) {
return SizedBox.fromSize(
size: size,
child: SvgPicture.asset('assets/images/$name.svg',
color: Theme.of(context).iconTheme.color),
);
} else {
return SvgPicture.asset('assets/images/$name.svg',
color: Theme.of(context).iconTheme.color);
}
}
}
Widget svgWidget(String name, {Size? size, Color? color}) {
if (size != null) {
return SizedBox.fromSize(

View File

@ -6,7 +6,14 @@ String languageFromLocale(Locale locale) {
case "en":
return "English";
case "zh":
return "简体中文";
switch (locale.countryCode) {
case "CN":
return "简体中文";
case "TW":
return "繁體中文";
default:
return locale.languageCode;
}
// Then in alphabetical order
case "ca":

View File

@ -81,7 +81,7 @@ class _PopoverContainer extends StatelessWidget {
Widget build(BuildContext context) {
final decoration = this.decoration ??
FlowyDecoration.decoration(
Theme.of(context).colorScheme.surface,
Theme.of(context).cardColor,
Theme.of(context).colorScheme.shadow.withOpacity(0.15),
);

View File

@ -26,6 +26,7 @@ class FlowyDialog extends StatelessWidget {
final size = windowSize * 0.7;
return SimpleDialog(
contentPadding: EdgeInsets.zero,
backgroundColor: Theme.of(context).cardColor,
title: title,
shape: shape ??
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),

View File

@ -1,11 +1,9 @@
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/ignore_parent_gesture.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
class FlowyButton extends StatelessWidget {
final Widget text;
@ -177,7 +175,8 @@ class FlowyTextButton extends StatelessWidget {
highlightElevation: 0,
shape: RoundedRectangleBorder(borderRadius: radius ?? Corners.s6Border),
fillColor: fillColor ?? Theme.of(context).colorScheme.secondaryContainer,
hoverColor: hoverColor ?? Theme.of(context).colorScheme.secondary,
hoverColor:
hoverColor ?? Theme.of(context).colorScheme.secondaryContainer,
focusColor: Colors.transparent,
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
@ -195,7 +194,6 @@ class FlowyTextButton extends StatelessWidget {
if (tooltip != null) {
child = Tooltip(
message: tooltip!,
textStyle: AFThemeExtension.of(context).caption.textColor(Colors.white),
child: child,
);
}
@ -285,7 +283,6 @@ class FlowyRichTextButton extends StatelessWidget {
if (tooltip != null) {
child = Tooltip(
message: tooltip!,
textStyle: AFThemeExtension.of(context).caption.textColor(Colors.white),
child: child,
);
}

View File

@ -115,11 +115,11 @@ class HoverStyle {
class FlowyHoverContainer extends StatelessWidget {
final HoverStyle style;
final Widget? child;
final Widget child;
const FlowyHoverContainer({
Key? key,
this.child,
required this.child,
required this.style,
}) : super(key: key);
@ -137,7 +137,22 @@ class FlowyHoverContainer extends StatelessWidget {
color: style.hoverColor ?? Theme.of(context).colorScheme.secondary,
borderRadius: style.borderRadius,
),
child: child,
child:
//override text's theme with new color when it is hovered
Theme(
data: Theme.of(context).copyWith(
textTheme: Theme.of(context).textTheme.copyWith(
bodyMedium: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(color: Theme.of(context).colorScheme.onSurface),
),
iconTheme: Theme.of(context)
.iconTheme
.copyWith(color: Theme.of(context).colorScheme.onSurface),
),
child: child,
),
);
}
}

View File

@ -9,7 +9,7 @@ class BaseStyledButton extends StatefulWidget {
final Color? bgColor;
final Color? focusColor;
final Color? hoverColor;
final Color? downColor;
final Color? highlightColor;
final EdgeInsets? contentPadding;
final double? minWidth;
final double? minHeight;
@ -34,7 +34,7 @@ class BaseStyledButton extends StatefulWidget {
this.minHeight,
this.borderRadius,
this.hoverColor,
this.downColor,
this.highlightColor,
this.shape,
this.useBtnText = true,
this.autoFocus = false,
@ -116,10 +116,8 @@ class BaseStyledBtnState extends State<BaseStyledButton> {
highlightElevation: 0,
focusElevation: 0,
fillColor: Colors.transparent,
hoverColor:
widget.hoverColor ?? Theme.of(context).colorScheme.secondary,
highlightColor:
widget.downColor ?? Theme.of(context).colorScheme.primary,
hoverColor: widget.hoverColor ?? Colors.transparent,
highlightColor: widget.highlightColor ?? Colors.transparent,
focusColor: widget.focusColor ?? Colors.grey.withOpacity(0.35),
constraints: BoxConstraints(
minHeight: widget.minHeight ?? 0, minWidth: widget.minWidth ?? 0),

View File

@ -42,7 +42,6 @@ class PrimaryButton extends StatelessWidget {
contentPadding: EdgeInsets.zero,
bgColor: Theme.of(context).colorScheme.primary,
hoverColor: Theme.of(context).colorScheme.primaryContainer,
downColor: Theme.of(context).colorScheme.primary,
borderRadius: bigMode ? Corners.s12Border : Corners.s8Border,
onPressed: onPressed,
child: child,

View File

@ -42,8 +42,6 @@ class SecondaryButton extends StatelessWidget {
minHeight: bigMode ? 40 : 38,
contentPadding: EdgeInsets.zero,
bgColor: Theme.of(context).colorScheme.surface,
hoverColor: Theme.of(context).colorScheme.secondary,
downColor: Theme.of(context).colorScheme.primary,
outlineColor: Theme.of(context).colorScheme.primary,
borderRadius: bigMode ? Corners.s12Border : Corners.s8Border,
onPressed: onPressed,

View File

@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.1.1
version: 0.1.2
environment:
sdk: ">=2.18.0 <3.0.0"
@ -89,7 +89,6 @@ dependencies:
google_fonts: ^3.0.1
file_picker: <=5.0.0
percent_indicator: ^4.0.1
appflowy_editor_plugins:
path: packages/appflowy_editor_plugins
calendar_view: ^1.0.1

View File

@ -10,7 +10,7 @@ pub fn init_flowy_core() -> AppFlowyCore {
}
data_path.push("data");
std::env::set_var("RUST_LOG", "debug");
std::env::set_var("RUST_LOG", "trace");
let server_config = get_client_server_configuration().unwrap();
let config = AppFlowyCoreConfig::new(
data_path.to_str().unwrap(),

View File

@ -10,6 +10,8 @@ import { ClockSvg } from '$app/components/_shared/svg/ClockSvg';
import { MoreSvg } from '$app/components/_shared/svg/MoreSvg';
import { EditorUncheckSvg } from '$app/components/_shared/svg/EditorUncheckSvg';
import { useCell } from '$app/components/_shared/database-hooks/useCell';
import { CalendarData } from '$app/stores/effects/database/cell/controller_builder';
import { DateCellDataPB } from '@/services/backend';
export const DatePickerPopup = ({
left,
@ -29,7 +31,6 @@ export const DatePickerPopup = ({
const { data, cellController } = useCell(cellIdentifier, cellCache, fieldController);
const ref = useRef<HTMLDivElement>(null);
const [adjustedTop, setAdjustedTop] = useState(-100);
// const [value, setValue] = useState();
const { t } = useTranslation('');
const [selectedDate, setSelectedDate] = useState<Date>(new Date());
@ -48,15 +49,18 @@ export const DatePickerPopup = ({
});
useEffect(() => {
// console.log((data as DateCellDataPB).date);
// setSelectedDate(new Date((data as DateCellDataPB).date));
const date_pb = data as DateCellDataPB | undefined;
if (!date_pb || !date_pb?.date.length) return;
// should be changed after we can modify date format
setSelectedDate(dayjs(date_pb.date, 'MMM DD, YYYY').toDate());
}, [data]);
const onChange = (v: Date | null | (Date | null)[]) => {
const onChange = async (v: Date | null | (Date | null)[]) => {
if (v instanceof Date) {
console.log(dayjs(v).format('YYYY-MM-DD'));
setSelectedDate(v);
// void cellController?.saveCellData(new DateCellDataPB({ date: dayjs(v).format('YYYY-MM-DD') }));
const date = new CalendarData(dayjs(v).add(dayjs().utcOffset(), 'minutes').toDate(), false);
await cellController?.saveCellData(date);
}
};

View File

@ -76,7 +76,10 @@ export const EditCellWrapper = ({
)}
{cellIdentifier.fieldType === FieldType.Checkbox && cellController && (
<EditCheckboxCell data={data as boolean | undefined} cellController={cellController}></EditCheckboxCell>
<EditCheckboxCell
data={data as 'Yes' | 'No' | undefined}
cellController={cellController}
></EditCheckboxCell>
)}
{cellIdentifier.fieldType === FieldType.DateTime && (

View File

@ -1,22 +1,26 @@
import { EditorCheckSvg } from '$app/components/_shared/svg/EditorCheckSvg';
import { EditorUncheckSvg } from '$app/components/_shared/svg/EditorUncheckSvg';
import { CellController } from '$app/stores/effects/database/cell/cell_controller';
import { CheckboxCellController } from '$app/stores/effects/database/cell/controller_builder';
export const EditCheckboxCell = ({
data,
cellController,
}: {
data: boolean | undefined;
cellController: CellController<any, any>;
data: 'Yes' | 'No' | undefined;
cellController: CheckboxCellController;
}) => {
const toggleValue = async () => {
await cellController?.saveCellData(!data);
if (data === 'Yes') {
await cellController?.saveCellData('No');
} else {
await cellController?.saveCellData('Yes');
}
};
return (
<div onClick={() => toggleValue()} className={'block px-4 py-2'}>
<button className={'h-5 w-5'}>
{data ? <EditorCheckSvg></EditorCheckSvg> : <EditorUncheckSvg></EditorUncheckSvg>}
{data === 'Yes' ? <EditorCheckSvg></EditorCheckSvg> : <EditorUncheckSvg></EditorUncheckSvg>}
</button>
</div>
);

View File

@ -108,7 +108,11 @@ export const EditRow = ({
const onDragEnd: OnDragEndResponder = (result) => {
if (!result.destination?.index) return;
void controller.moveField(result.source.droppableId, result.source.index, result.destination.index);
void controller.moveField({
fieldId: result.source.droppableId,
fromIndex: result.source.index,
toIndex: result.destination.index,
});
};
return (

View File

@ -1,13 +1,12 @@
import { CellIdentifier } from '../../stores/effects/database/cell/cell_bd_svc';
import { CellCache } from '../../stores/effects/database/cell/cell_cache';
import { FieldController } from '../../stores/effects/database/field/field_controller';
import { FieldType, SelectOptionCellDataPB } from '../../../services/backend';
import { FieldType } from '../../../services/backend';
import { BoardOptionsCell } from './BoardOptionsCell';
import { BoardDateCell } from './BoardDateCell';
import { BoardTextCell } from './BoardTextCell';
import { BoardUrlCell } from '$app/components/board/BoardUrlCell';
import { useCell } from '../_shared/database-hooks/useCell';
import { CellOptions } from '../_shared/EditRow/CellOptions';
import { BoardCheckboxCell } from '$app/components/board/BoardCheckboxCell';
export const BoardCell = ({
cellIdentifier,
@ -18,19 +17,16 @@ export const BoardCell = ({
cellCache: CellCache;
fieldController: FieldController;
}) => {
const { data, cellController } = useCell(cellIdentifier, cellCache, fieldController);
return (
<>
{cellIdentifier.fieldType === FieldType.SingleSelect ||
cellIdentifier.fieldType === FieldType.MultiSelect ||
cellIdentifier.fieldType === FieldType.Checklist ? (
<CellOptions
data={data as SelectOptionCellDataPB}
onEditClick={(top: number, left: number) => {
console.log(top, left);
}}
/>
<BoardOptionsCell
cellIdentifier={cellIdentifier}
cellCache={cellCache}
fieldController={fieldController}
></BoardOptionsCell>
) : cellIdentifier.fieldType === FieldType.DateTime ? (
<BoardDateCell
cellIdentifier={cellIdentifier}
@ -43,6 +39,12 @@ export const BoardCell = ({
cellCache={cellCache}
fieldController={fieldController}
></BoardUrlCell>
) : cellIdentifier.fieldType === FieldType.Checkbox ? (
<BoardCheckboxCell
cellIdentifier={cellIdentifier}
cellCache={cellCache}
fieldController={fieldController}
></BoardCheckboxCell>
) : (
<BoardTextCell
cellIdentifier={cellIdentifier}

View File

@ -0,0 +1,23 @@
import { EditorCheckSvg } from '$app/components/_shared/svg/EditorCheckSvg';
import { EditorUncheckSvg } from '$app/components/_shared/svg/EditorUncheckSvg';
import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc';
import { CellCache } from '$app/stores/effects/database/cell/cell_cache';
import { FieldController } from '$app/stores/effects/database/field/field_controller';
import { useCell } from '$app/components/_shared/database-hooks/useCell';
export const BoardCheckboxCell = ({
cellIdentifier,
cellCache,
fieldController,
}: {
cellIdentifier: CellIdentifier;
cellCache: CellCache;
fieldController: FieldController;
}) => {
const { data } = useCell(cellIdentifier, cellCache, fieldController);
return (
<i className={'h-5 w-5'}>
{data === 'Yes' ? <EditorCheckSvg></EditorCheckSvg> : <EditorUncheckSvg></EditorUncheckSvg>}
</i>
);
};

View File

@ -12,6 +12,7 @@ import { RowInfo } from '../../stores/effects/database/row/row_cache';
import { RowController } from '../../stores/effects/database/row/row_controller';
import {
CellControllerBuilder,
CheckboxCellController,
DateCellController,
NumberCellController,
SelectOptionCellController,
@ -126,6 +127,17 @@ export async function makeDateCellController(
return Some(builder.build() as DateCellController);
}
export async function makeCheckboxCellController(
fieldId: string,
rowInfo: RowInfo,
databaseController: DatabaseController
): Promise<Option<CheckboxCellController>> {
const builder = await makeCellControllerBuilder(fieldId, rowInfo, FieldType.Checkbox, databaseController).then(
(result) => result.unwrap()
);
return Some(builder.build() as CheckboxCellController);
}
export async function makeURLCellController(
fieldId: string,
rowInfo: RowInfo,

View File

@ -8,10 +8,13 @@ import {
TestDeleteField,
TestDeleteRow,
TestEditCell,
TestEditCheckboxCell,
TestEditDateCell,
TestEditField,
TestEditTextCell,
TestEditURLCell,
TestGetSingleSelectFieldData,
TestMoveField,
TestSwitchFromMultiSelectToText,
TestSwitchFromSingleSelectToNumber,
} from './TestGrid';
@ -37,9 +40,12 @@ export const TestAPI = () => {
<TestEditCell></TestEditCell>
<TestEditTextCell></TestEditTextCell>
<TestEditURLCell></TestEditURLCell>
<TestEditDateCell></TestEditDateCell>
<TestEditCheckboxCell></TestEditCheckboxCell>
<TestCreateSelectOptionInCell></TestCreateSelectOptionInCell>
<TestGetSingleSelectFieldData></TestGetSingleSelectFieldData>
<TestEditField></TestEditField>
<TestMoveField></TestMoveField>
<TestCreateNewField></TestCreateNewField>
<TestDeleteField></TestDeleteField>
<TestSwitchFromSingleSelectToNumber></TestSwitchFromSingleSelectToNumber>

Some files were not shown because too many files have changed in this diff Show More