mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: Merge main 521 (#2574)
* chore: merge main branch * chore: remove document plugins * chore: add color generator * ci: tests
This commit is contained in:
@ -45,7 +45,8 @@
|
|||||||
"medium": "medium",
|
"medium": "medium",
|
||||||
"large": "large",
|
"large": "large",
|
||||||
"fontSize": "Font Size",
|
"fontSize": "Font Size",
|
||||||
"import": "Import"
|
"import": "Import",
|
||||||
|
"moreOptions": "More options"
|
||||||
},
|
},
|
||||||
"disclosureAction": {
|
"disclosureAction": {
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
@ -108,6 +109,7 @@
|
|||||||
"openAsPage": "Open as a Page",
|
"openAsPage": "Open as a Page",
|
||||||
"addNewRow": "Add a new row",
|
"addNewRow": "Add a new row",
|
||||||
"openMenu": "Click to open menu",
|
"openMenu": "Click to open menu",
|
||||||
|
"dragRow": "Long press to reorder the row",
|
||||||
"viewDataBase": "View database",
|
"viewDataBase": "View database",
|
||||||
"referencePage": "This {name} is referenced"
|
"referencePage": "This {name} is referenced"
|
||||||
},
|
},
|
||||||
@ -358,12 +360,14 @@
|
|||||||
"autoGeneratorGenerate": "Generate",
|
"autoGeneratorGenerate": "Generate",
|
||||||
"autoGeneratorHintText": "Ask OpenAI ...",
|
"autoGeneratorHintText": "Ask OpenAI ...",
|
||||||
"autoGeneratorCantGetOpenAIKey": "Can't get OpenAI key",
|
"autoGeneratorCantGetOpenAIKey": "Can't get OpenAI key",
|
||||||
|
"autoGeneratorRewrite": "Rewrite",
|
||||||
"smartEdit": "AI Assistants",
|
"smartEdit": "AI Assistants",
|
||||||
"openAI": "OpenAI",
|
"openAI": "OpenAI",
|
||||||
"smartEditFixSpelling": "Fix spelling",
|
"smartEditFixSpelling": "Fix spelling",
|
||||||
"warning": "⚠️ AI responses can be inaccurate or misleading.",
|
"warning": "⚠️ AI responses can be inaccurate or misleading.",
|
||||||
"smartEditSummarize": "Summarize",
|
"smartEditSummarize": "Summarize",
|
||||||
"smartEditImproveWriting": "Improve Writing",
|
"smartEditImproveWriting": "Improve writing",
|
||||||
|
"smartEditMakeLonger": "Make longer",
|
||||||
"smartEditCouldNotFetchResult": "Could not fetch result from OpenAI",
|
"smartEditCouldNotFetchResult": "Could not fetch result from OpenAI",
|
||||||
"smartEditCouldNotFetchKey": "Could not fetch OpenAI key",
|
"smartEditCouldNotFetchKey": "Could not fetch OpenAI key",
|
||||||
"smartEditDisabled": "Connect OpenAI in Settings",
|
"smartEditDisabled": "Connect OpenAI in Settings",
|
||||||
@ -427,4 +431,4 @@
|
|||||||
"emptyNoDate": "No unscheduled events"
|
"emptyNoDate": "No unscheduled events"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,6 @@ class DateCellDataPersistence implements CellDataPersistence<DateCellData> {
|
|||||||
@override
|
@override
|
||||||
Future<Option<FlowyError>> save(DateCellData data) {
|
Future<Option<FlowyError>> save(DateCellData data) {
|
||||||
var payload = DateChangesetPB.create()..cellPath = _makeCellPath(cellId);
|
var payload = DateChangesetPB.create()..cellPath = _makeCellPath(cellId);
|
||||||
|
|
||||||
if (data.dateTime != null) {
|
if (data.dateTime != null) {
|
||||||
final date = (data.dateTime!.millisecondsSinceEpoch ~/ 1000).toString();
|
final date = (data.dateTime!.millisecondsSinceEpoch ~/ 1000).toString();
|
||||||
payload.date = date;
|
payload.date = date;
|
||||||
|
@ -176,18 +176,28 @@ class DatabaseController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Either<Unit, FlowyError>> moveRow({
|
Future<Either<Unit, FlowyError>> moveGroupRow({
|
||||||
required RowPB fromRow,
|
required RowPB fromRow,
|
||||||
required String groupId,
|
required String groupId,
|
||||||
RowPB? toRow,
|
RowPB? toRow,
|
||||||
}) {
|
}) {
|
||||||
return _databaseViewBackendSvc.moveRow(
|
return _databaseViewBackendSvc.moveGroupRow(
|
||||||
fromRowId: fromRow.id,
|
fromRowId: fromRow.id,
|
||||||
toGroupId: groupId,
|
toGroupId: groupId,
|
||||||
toRowId: toRow?.id,
|
toRowId: toRow?.id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Either<Unit, FlowyError>> moveRow({
|
||||||
|
required RowPB fromRow,
|
||||||
|
required RowPB toRow,
|
||||||
|
}) {
|
||||||
|
return _databaseViewBackendSvc.moveRow(
|
||||||
|
fromRowId: fromRow.id,
|
||||||
|
toRowId: toRow.id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<Either<Unit, FlowyError>> moveGroup({
|
Future<Either<Unit, FlowyError>> moveGroup({
|
||||||
required String fromGroupId,
|
required String fromGroupId,
|
||||||
required String toGroupId,
|
required String toGroupId,
|
||||||
|
@ -43,7 +43,7 @@ class DatabaseViewBackendService {
|
|||||||
return DatabaseEventCreateRow(payload).send();
|
return DatabaseEventCreateRow(payload).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Either<Unit, FlowyError>> moveRow({
|
Future<Either<Unit, FlowyError>> moveGroupRow({
|
||||||
required RowId fromRowId,
|
required RowId fromRowId,
|
||||||
required String toGroupId,
|
required String toGroupId,
|
||||||
RowId? toRowId,
|
RowId? toRowId,
|
||||||
@ -60,6 +60,18 @@ class DatabaseViewBackendService {
|
|||||||
return DatabaseEventMoveGroupRow(payload).send();
|
return DatabaseEventMoveGroupRow(payload).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Either<Unit, FlowyError>> moveRow({
|
||||||
|
required String fromRowId,
|
||||||
|
required String toRowId,
|
||||||
|
}) {
|
||||||
|
var payload = MoveRowPayloadPB.create()
|
||||||
|
..viewId = viewId
|
||||||
|
..fromRowId = fromRowId
|
||||||
|
..toRowId = toRowId;
|
||||||
|
|
||||||
|
return DatabaseEventMoveRow(payload).send();
|
||||||
|
}
|
||||||
|
|
||||||
Future<Either<Unit, FlowyError>> moveGroup({
|
Future<Either<Unit, FlowyError>> moveGroup({
|
||||||
required String fromGroupId,
|
required String fromGroupId,
|
||||||
required String toGroupId,
|
required String toGroupId,
|
||||||
|
@ -30,7 +30,7 @@ abstract class RowCacheDelegate {
|
|||||||
class RowCache {
|
class RowCache {
|
||||||
final String viewId;
|
final String viewId;
|
||||||
|
|
||||||
/// _rows containers the current block's rows
|
/// _rows contains the current block's rows
|
||||||
/// Use List to reverse the order of the GridRow.
|
/// Use List to reverse the order of the GridRow.
|
||||||
final RowList _rowList = RowList();
|
final RowList _rowList = RowList();
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
|||||||
final fromRow = groupControllers[groupId]?.rowAtIndex(fromIndex);
|
final fromRow = groupControllers[groupId]?.rowAtIndex(fromIndex);
|
||||||
final toRow = groupControllers[groupId]?.rowAtIndex(toIndex);
|
final toRow = groupControllers[groupId]?.rowAtIndex(toIndex);
|
||||||
if (fromRow != null) {
|
if (fromRow != null) {
|
||||||
_databaseController.moveRow(
|
_databaseController.moveGroupRow(
|
||||||
fromRow: fromRow,
|
fromRow: fromRow,
|
||||||
toRow: toRow,
|
toRow: toRow,
|
||||||
groupId: groupId,
|
groupId: groupId,
|
||||||
@ -70,7 +70,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
|||||||
final fromRow = groupControllers[fromGroupId]?.rowAtIndex(fromIndex);
|
final fromRow = groupControllers[fromGroupId]?.rowAtIndex(fromIndex);
|
||||||
final toRow = groupControllers[toGroupId]?.rowAtIndex(toIndex);
|
final toRow = groupControllers[toGroupId]?.rowAtIndex(toIndex);
|
||||||
if (fromRow != null) {
|
if (fromRow != null) {
|
||||||
_databaseController.moveRow(
|
_databaseController.moveGroupRow(
|
||||||
fromRow: fromRow,
|
fromRow: fromRow,
|
||||||
toRow: toRow,
|
toRow: toRow,
|
||||||
groupId: toGroupId,
|
groupId: toGroupId,
|
||||||
|
@ -161,6 +161,9 @@ class CalendarDayCard extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
renderHook.addSelectOptionHook((selectedOptions, cardData, _) {
|
renderHook.addSelectOptionHook((selectedOptions, cardData, _) {
|
||||||
|
if (selectedOptions.isEmpty) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
final children = selectedOptions.map(
|
final children = selectedOptions.map(
|
||||||
(option) {
|
(option) {
|
||||||
return SelectOptionTag.fromOption(
|
return SelectOptionTag.fromOption(
|
||||||
|
@ -35,6 +35,17 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
|||||||
);
|
);
|
||||||
await rowService.deleteRow(rowInfo.rowPB.id);
|
await rowService.deleteRow(rowInfo.rowPB.id);
|
||||||
},
|
},
|
||||||
|
moveRow: (int from, int to) {
|
||||||
|
final List<RowInfo> rows = [...state.rowInfos];
|
||||||
|
|
||||||
|
final fromRow = rows[from].rowPB;
|
||||||
|
final toRow = rows[to].rowPB;
|
||||||
|
|
||||||
|
rows.insert(to, rows.removeAt(from));
|
||||||
|
emit(state.copyWith(rowInfos: rows));
|
||||||
|
|
||||||
|
databaseController.moveRow(fromRow: fromRow, toRow: toRow);
|
||||||
|
},
|
||||||
didReceiveGridUpdate: (grid) {
|
didReceiveGridUpdate: (grid) {
|
||||||
emit(state.copyWith(grid: Some(grid)));
|
emit(state.copyWith(grid: Some(grid)));
|
||||||
},
|
},
|
||||||
@ -110,6 +121,7 @@ class GridEvent with _$GridEvent {
|
|||||||
const factory GridEvent.initial() = InitialGrid;
|
const factory GridEvent.initial() = InitialGrid;
|
||||||
const factory GridEvent.createRow() = _CreateRow;
|
const factory GridEvent.createRow() = _CreateRow;
|
||||||
const factory GridEvent.deleteRow(RowInfo rowInfo) = _DeleteRow;
|
const factory GridEvent.deleteRow(RowInfo rowInfo) = _DeleteRow;
|
||||||
|
const factory GridEvent.moveRow(int from, int to) = _MoveRow;
|
||||||
const factory GridEvent.didReceiveRowUpdate(
|
const factory GridEvent.didReceiveRowUpdate(
|
||||||
List<RowInfo> rows,
|
List<RowInfo> rows,
|
||||||
RowsChangedReason listState,
|
RowsChangedReason listState,
|
||||||
|
@ -91,21 +91,6 @@ class _GridPageState extends State<GridPage> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void deactivate() {
|
|
||||||
super.deactivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didUpdateWidget(covariant GridPage oldWidget) {
|
|
||||||
super.didUpdateWidget(oldWidget);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class FlowyGrid extends StatefulWidget {
|
class FlowyGrid extends StatefulWidget {
|
||||||
@ -119,12 +104,12 @@ class _FlowyGridState extends State<FlowyGrid> {
|
|||||||
final _scrollController = GridScrollController(
|
final _scrollController = GridScrollController(
|
||||||
scrollGroupController: LinkedScrollControllerGroup(),
|
scrollGroupController: LinkedScrollControllerGroup(),
|
||||||
);
|
);
|
||||||
late ScrollController headerScrollController;
|
late final ScrollController headerScrollController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
headerScrollController = _scrollController.linkHorizontalController();
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
headerScrollController = _scrollController.linkHorizontalController();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -216,49 +201,78 @@ class _GridRowsState extends State<_GridRows> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocConsumer<GridBloc, GridState>(
|
return Builder(
|
||||||
listenWhen: (previous, current) => previous.reason != current.reason,
|
builder: (context) {
|
||||||
listener: (context, state) {
|
final filterState = context.watch<GridFilterMenuBloc>().state;
|
||||||
state.reason.whenOrNull(
|
final sortState = context.watch<SortMenuBloc>().state;
|
||||||
insert: (item) {
|
|
||||||
_key.currentState?.insertItem(item.index);
|
return BlocConsumer<GridBloc, GridState>(
|
||||||
},
|
listenWhen: (previous, current) => previous.reason != current.reason,
|
||||||
delete: (item) {
|
listener: (context, state) {
|
||||||
_key.currentState?.removeItem(
|
state.reason.whenOrNull(
|
||||||
item.index,
|
insert: (item) {
|
||||||
(context, animation) =>
|
_key.currentState?.insertItem(item.index);
|
||||||
_renderRow(context, item.rowInfo, animation),
|
},
|
||||||
|
delete: (item) {
|
||||||
|
_key.currentState?.removeItem(
|
||||||
|
item.index,
|
||||||
|
(context, animation) => _renderRow(
|
||||||
|
context,
|
||||||
|
item.rowInfo,
|
||||||
|
animation: animation,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
reorderSingleRow: (reorderRow, rowInfo) {
|
buildWhen: (previous, current) {
|
||||||
// _key.currentState?.removeItem(
|
return current.reason.maybeWhen(
|
||||||
// reorderRow.oldIndex,
|
|
||||||
// (context, animation) => _renderRow(context, rowInfo, animation),
|
|
||||||
// );
|
|
||||||
// _key.currentState?.insertItem(reorderRow.newIndex);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
buildWhen: (previous, current) {
|
|
||||||
return current.reason.whenOrNull(
|
|
||||||
reorderRows: () => true,
|
reorderRows: () => true,
|
||||||
reorderSingleRow: (reorderRow, rowInfo) => true,
|
reorderSingleRow: (reorderRow, rowInfo) => true,
|
||||||
) ??
|
delete: (item) => true,
|
||||||
false;
|
insert: (item) => true,
|
||||||
},
|
orElse: () => false,
|
||||||
builder: (context, state) {
|
);
|
||||||
return SliverAnimatedList(
|
},
|
||||||
key: _key,
|
builder: (context, state) {
|
||||||
initialItemCount: context.read<GridBloc>().state.rowInfos.length,
|
final rowInfos = context.watch<GridBloc>().state.rowInfos;
|
||||||
itemBuilder:
|
|
||||||
(BuildContext context, int index, Animation<double> animation) {
|
return SliverFillRemaining(
|
||||||
final rowInfos = context.read<GridBloc>().state.rowInfos;
|
child: ReorderableListView.builder(
|
||||||
if (index >= rowInfos.length) {
|
key: _key,
|
||||||
return const SizedBox();
|
buildDefaultDragHandles: false,
|
||||||
} else {
|
proxyDecorator: (child, index, animation) => Material(
|
||||||
final RowInfo rowInfo = rowInfos[index];
|
color: Colors.white.withOpacity(.1),
|
||||||
return _renderRow(context, rowInfo, animation);
|
child: Opacity(
|
||||||
}
|
opacity: .5,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onReorder: (fromIndex, newIndex) {
|
||||||
|
final toIndex =
|
||||||
|
newIndex > fromIndex ? newIndex - 1 : newIndex;
|
||||||
|
|
||||||
|
if (fromIndex == toIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context
|
||||||
|
.read<GridBloc>()
|
||||||
|
.add(GridEvent.moveRow(fromIndex, toIndex));
|
||||||
|
},
|
||||||
|
itemCount: rowInfos.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
final RowInfo rowInfo = rowInfos[index];
|
||||||
|
return _renderRow(
|
||||||
|
context,
|
||||||
|
rowInfo,
|
||||||
|
index: index,
|
||||||
|
isSortEnabled: sortState.sortInfos.isNotEmpty,
|
||||||
|
isFilterEnabled: filterState.filters.isNotEmpty,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -267,15 +281,18 @@ class _GridRowsState extends State<_GridRows> {
|
|||||||
|
|
||||||
Widget _renderRow(
|
Widget _renderRow(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
RowInfo rowInfo,
|
RowInfo rowInfo, {
|
||||||
Animation<double> animation,
|
int? index,
|
||||||
) {
|
bool isSortEnabled = false,
|
||||||
|
bool isFilterEnabled = false,
|
||||||
|
Animation<double>? animation,
|
||||||
|
}) {
|
||||||
final rowCache = context.read<GridBloc>().getRowCache(
|
final rowCache = context.read<GridBloc>().getRowCache(
|
||||||
rowInfo.rowPB.id,
|
rowInfo.rowPB.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Return placeholder widget if the rowCache is null.
|
/// Return placeholder widget if the rowCache is null.
|
||||||
if (rowCache == null) return const SizedBox();
|
if (rowCache == null) return const SizedBox.shrink();
|
||||||
|
|
||||||
final fieldController =
|
final fieldController =
|
||||||
context.read<GridBloc>().databaseController.fieldController;
|
context.read<GridBloc>().databaseController.fieldController;
|
||||||
@ -285,24 +302,32 @@ class _GridRowsState extends State<_GridRows> {
|
|||||||
rowCache: rowCache,
|
rowCache: rowCache,
|
||||||
);
|
);
|
||||||
|
|
||||||
return SizeTransition(
|
final child = GridRow(
|
||||||
sizeFactor: animation,
|
key: ValueKey(rowInfo.rowPB.id),
|
||||||
child: GridRow(
|
index: index,
|
||||||
rowInfo: rowInfo,
|
isDraggable: !isSortEnabled && !isFilterEnabled,
|
||||||
dataController: dataController,
|
rowInfo: rowInfo,
|
||||||
cellBuilder: GridCellBuilder(cellCache: dataController.cellCache),
|
dataController: dataController,
|
||||||
openDetailPage: (context, cellBuilder) {
|
cellBuilder: GridCellBuilder(cellCache: dataController.cellCache),
|
||||||
_openRowDetailPage(
|
openDetailPage: (context, cellBuilder) {
|
||||||
context,
|
_openRowDetailPage(
|
||||||
rowInfo,
|
context,
|
||||||
fieldController,
|
rowInfo,
|
||||||
rowCache,
|
fieldController,
|
||||||
cellBuilder,
|
rowCache,
|
||||||
);
|
cellBuilder,
|
||||||
},
|
);
|
||||||
key: ValueKey(rowInfo.rowPB.id),
|
},
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (animation != null) {
|
||||||
|
return SizeTransition(
|
||||||
|
sizeFactor: animation,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _openRowDetailPage(
|
void _openRowDetailPage(
|
||||||
|
@ -25,29 +25,34 @@ class GridRow extends StatefulWidget {
|
|||||||
final GridCellBuilder cellBuilder;
|
final GridCellBuilder cellBuilder;
|
||||||
final void Function(BuildContext, GridCellBuilder) openDetailPage;
|
final void Function(BuildContext, GridCellBuilder) openDetailPage;
|
||||||
|
|
||||||
|
final int? index;
|
||||||
|
final bool isDraggable;
|
||||||
|
|
||||||
const GridRow({
|
const GridRow({
|
||||||
|
super.key,
|
||||||
required this.rowInfo,
|
required this.rowInfo,
|
||||||
required this.dataController,
|
required this.dataController,
|
||||||
required this.cellBuilder,
|
required this.cellBuilder,
|
||||||
required this.openDetailPage,
|
required this.openDetailPage,
|
||||||
Key? key,
|
this.index,
|
||||||
}) : super(key: key);
|
this.isDraggable = false,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<GridRow> createState() => _GridRowState();
|
State<GridRow> createState() => _GridRowState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GridRowState extends State<GridRow> {
|
class _GridRowState extends State<GridRow> {
|
||||||
late RowBloc _rowBloc;
|
late final RowBloc _rowBloc;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
super.initState();
|
||||||
_rowBloc = RowBloc(
|
_rowBloc = RowBloc(
|
||||||
rowInfo: widget.rowInfo,
|
rowInfo: widget.rowInfo,
|
||||||
dataController: widget.dataController,
|
dataController: widget.dataController,
|
||||||
);
|
);
|
||||||
_rowBloc.add(const RowEvent.initial());
|
_rowBloc.add(const RowEvent.initial());
|
||||||
super.initState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -70,9 +75,11 @@ class _GridRowState extends State<GridRow> {
|
|||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
const _RowLeading(),
|
_RowLeading(
|
||||||
|
index: widget.index,
|
||||||
|
isDraggable: widget.isDraggable,
|
||||||
|
),
|
||||||
content,
|
content,
|
||||||
const _RowTrailing(),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -89,19 +96,25 @@ class _GridRowState extends State<GridRow> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _RowLeading extends StatefulWidget {
|
class _RowLeading extends StatefulWidget {
|
||||||
const _RowLeading({Key? key}) : super(key: key);
|
final int? index;
|
||||||
|
final bool isDraggable;
|
||||||
|
|
||||||
|
const _RowLeading({
|
||||||
|
this.index,
|
||||||
|
this.isDraggable = false,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_RowLeading> createState() => _RowLeadingState();
|
State<_RowLeading> createState() => _RowLeadingState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RowLeadingState extends State<_RowLeading> {
|
class _RowLeadingState extends State<_RowLeading> {
|
||||||
late PopoverController popoverController;
|
late final PopoverController popoverController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
popoverController = PopoverController();
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
popoverController = PopoverController();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -131,23 +144,28 @@ class _RowLeadingState extends State<_RowLeading> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const _InsertButton(),
|
const _InsertButton(),
|
||||||
_MenuButton(
|
if (isDraggable) ...[
|
||||||
openMenu: () {
|
ReorderableDragStartListener(
|
||||||
popoverController.show();
|
index: widget.index!,
|
||||||
},
|
child: _MenuButton(
|
||||||
),
|
isDragEnabled: isDraggable,
|
||||||
|
openMenu: () {
|
||||||
|
popoverController.show();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
] else ...[
|
||||||
|
_MenuButton(
|
||||||
|
openMenu: () {
|
||||||
|
popoverController.show();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class _RowTrailing extends StatelessWidget {
|
bool get isDraggable => widget.index != null && widget.isDraggable;
|
||||||
const _RowTrailing({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _InsertButton extends StatelessWidget {
|
class _InsertButton extends StatelessWidget {
|
||||||
@ -172,25 +190,31 @@ class _InsertButton extends StatelessWidget {
|
|||||||
|
|
||||||
class _MenuButton extends StatefulWidget {
|
class _MenuButton extends StatefulWidget {
|
||||||
final VoidCallback openMenu;
|
final VoidCallback openMenu;
|
||||||
|
final bool isDragEnabled;
|
||||||
|
|
||||||
const _MenuButton({
|
const _MenuButton({
|
||||||
required this.openMenu,
|
required this.openMenu,
|
||||||
Key? key,
|
this.isDragEnabled = false,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_MenuButton> createState() => _MenuButtonState();
|
State<_MenuButton> createState() => _MenuButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MenuButtonState extends State<_MenuButton> {
|
class _MenuButtonState extends State<_MenuButton> {
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FlowyIconButton(
|
return FlowyIconButton(
|
||||||
tooltipText: LocaleKeys.tooltip_openMenu.tr(),
|
tooltipText:
|
||||||
|
widget.isDragEnabled ? null : LocaleKeys.tooltip_openMenu.tr(),
|
||||||
|
richTooltipText: widget.isDragEnabled
|
||||||
|
? TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(text: '${LocaleKeys.tooltip_dragRow.tr()}\n'),
|
||||||
|
TextSpan(text: LocaleKeys.tooltip_openMenu.tr()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: null,
|
||||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||||
width: 20,
|
width: 20,
|
||||||
height: 30,
|
height: 30,
|
||||||
@ -258,6 +282,7 @@ class RowContent extends StatelessWidget {
|
|||||||
if (builder != null) {
|
if (builder != null) {
|
||||||
accessories.addAll(builder(buildContext));
|
accessories.addAll(builder(buildContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
return accessories;
|
return accessories;
|
||||||
},
|
},
|
||||||
child: child,
|
child: child,
|
||||||
@ -289,12 +314,12 @@ class _RowEnterRegion extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _RowEnterRegionState extends State<_RowEnterRegion> {
|
class _RowEnterRegionState extends State<_RowEnterRegion> {
|
||||||
late RegionStateNotifier _rowStateNotifier;
|
late final RegionStateNotifier _rowStateNotifier;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_rowStateNotifier = RegionStateNotifier();
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_rowStateNotifier = RegionStateNotifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -74,6 +74,7 @@ class GridCellBuilder {
|
|||||||
key: key,
|
key: key,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw UnimplementedError;
|
throw UnimplementedError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,7 +84,7 @@ class BlankCell extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,18 +68,15 @@ class CellContainer extends StatelessWidget {
|
|||||||
if (isFocus) {
|
if (isFocus) {
|
||||||
final borderSide = BorderSide(
|
final borderSide = BorderSide(
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
width: 1.0,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return BoxDecoration(border: Border.fromBorderSide(borderSide));
|
return BoxDecoration(border: Border.fromBorderSide(borderSide));
|
||||||
} else {
|
|
||||||
final borderSide = BorderSide(
|
|
||||||
color: Theme.of(context).dividerColor,
|
|
||||||
width: 1.0,
|
|
||||||
);
|
|
||||||
return BoxDecoration(
|
|
||||||
border: Border(right: borderSide, bottom: borderSide),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final borderSide = BorderSide(color: Theme.of(context).dividerColor);
|
||||||
|
return BoxDecoration(
|
||||||
|
border: Border(right: borderSide, bottom: borderSide),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,6 @@ class DateCellCalendarBloc
|
|||||||
date != null && time == null,
|
date != null && time == null,
|
||||||
);
|
);
|
||||||
String? newTime = time ?? state.time;
|
String? newTime = time ?? state.time;
|
||||||
|
|
||||||
DateTime? newDate = _utcToLocalAddTime(date);
|
DateTime? newDate = _utcToLocalAddTime(date);
|
||||||
if (time != null && time.isNotEmpty) {
|
if (time != null && time.isNotEmpty) {
|
||||||
newDate = state.dateTime ?? DateTime.now();
|
newDate = state.dateTime ?? DateTime.now();
|
||||||
|
@ -6,7 +6,8 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
enum SmartEditAction {
|
enum SmartEditAction {
|
||||||
summarize,
|
summarize,
|
||||||
fixSpelling,
|
fixSpelling,
|
||||||
improveWriting;
|
improveWriting,
|
||||||
|
makeItLonger;
|
||||||
|
|
||||||
String get toInstruction {
|
String get toInstruction {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
@ -16,6 +17,8 @@ enum SmartEditAction {
|
|||||||
return 'Correct this to standard English:';
|
return 'Correct this to standard English:';
|
||||||
case SmartEditAction.improveWriting:
|
case SmartEditAction.improveWriting:
|
||||||
return 'Rewrite this in your own words:';
|
return 'Rewrite this in your own words:';
|
||||||
|
case SmartEditAction.makeItLonger:
|
||||||
|
return 'Make this text longer:';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,6 +30,8 @@ enum SmartEditAction {
|
|||||||
return 'Correct this to standard English:\n\n$input';
|
return 'Correct this to standard English:\n\n$input';
|
||||||
case SmartEditAction.improveWriting:
|
case SmartEditAction.improveWriting:
|
||||||
return 'Rewrite this:\n\n$input';
|
return 'Rewrite this:\n\n$input';
|
||||||
|
case SmartEditAction.makeItLonger:
|
||||||
|
return 'Make this text longer:\n\n$input';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,6 +43,8 @@ enum SmartEditAction {
|
|||||||
return SmartEditAction.fixSpelling;
|
return SmartEditAction.fixSpelling;
|
||||||
case 2:
|
case 2:
|
||||||
return SmartEditAction.improveWriting;
|
return SmartEditAction.improveWriting;
|
||||||
|
case 3:
|
||||||
|
return SmartEditAction.makeItLonger;
|
||||||
}
|
}
|
||||||
return SmartEditAction.fixSpelling;
|
return SmartEditAction.fixSpelling;
|
||||||
}
|
}
|
||||||
@ -50,6 +57,8 @@ enum SmartEditAction {
|
|||||||
return LocaleKeys.document_plugins_smartEditFixSpelling.tr();
|
return LocaleKeys.document_plugins_smartEditFixSpelling.tr();
|
||||||
case SmartEditAction.improveWriting:
|
case SmartEditAction.improveWriting:
|
||||||
return LocaleKeys.document_plugins_smartEditImproveWriting.tr();
|
return LocaleKeys.document_plugins_smartEditImproveWriting.tr();
|
||||||
|
case SmartEditAction.makeItLonger:
|
||||||
|
return LocaleKeys.document_plugins_smartEditMakeLonger.tr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,15 +257,15 @@ class _SmartEditInputWidgetState extends State<SmartEditInputWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildResultWidget(BuildContext context) {
|
Widget _buildResultWidget(BuildContext context) {
|
||||||
final loading = Padding(
|
final loadingWidget = Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
child: SizedBox.fromSize(
|
child: SizedBox.fromSize(
|
||||||
size: const Size.square(14),
|
size: const Size.square(14),
|
||||||
child: const CircularProgressIndicator(),
|
child: const CircularProgressIndicator(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (result.isEmpty) {
|
if (result.isEmpty || loading) {
|
||||||
return loading;
|
return loadingWidget;
|
||||||
}
|
}
|
||||||
return Flexible(
|
return Flexible(
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -277,6 +277,18 @@ class _SmartEditInputWidgetState extends State<SmartEditInputWidget> {
|
|||||||
Widget _buildInputFooterWidget(BuildContext context) {
|
Widget _buildInputFooterWidget(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
|
FlowyRichTextButton(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: LocaleKeys.document_plugins_autoGeneratorRewrite.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onPressed: () => _requestCompletions(rewrite: true),
|
||||||
|
),
|
||||||
|
const Space(10, 0),
|
||||||
FlowyRichTextButton(
|
FlowyRichTextButton(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
children: [
|
children: [
|
||||||
@ -402,7 +414,13 @@ class _SmartEditInputWidgetState extends State<SmartEditInputWidget> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _requestCompletions() async {
|
Future<void> _requestCompletions({bool rewrite = false}) async {
|
||||||
|
if (rewrite) {
|
||||||
|
setState(() {
|
||||||
|
loading = true;
|
||||||
|
result = "";
|
||||||
|
});
|
||||||
|
}
|
||||||
final openAIRepository = await getIt.getAsync<OpenAIRepository>();
|
final openAIRepository = await getIt.getAsync<OpenAIRepository>();
|
||||||
|
|
||||||
var lines = content.split('\n\n');
|
var lines = content.split('\n\n');
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
|
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/more/font_size_switcher.dart';
|
import 'package:appflowy/plugins/document/presentation/more/font_size_switcher.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
@ -14,6 +16,7 @@ class DocumentMoreButton extends StatelessWidget {
|
|||||||
return PopupMenuButton<int>(
|
return PopupMenuButton<int>(
|
||||||
color: Theme.of(context).colorScheme.surfaceVariant,
|
color: Theme.of(context).colorScheme.surfaceVariant,
|
||||||
offset: const Offset(0, 30),
|
offset: const Offset(0, 30),
|
||||||
|
tooltip: LocaleKeys.moreAction_moreOptions.tr(),
|
||||||
itemBuilder: (context) {
|
itemBuilder: (context) {
|
||||||
return [
|
return [
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
class ColorGenerator {
|
||||||
|
Color generateColorFromString(String string) {
|
||||||
|
final hash = string.hashCode;
|
||||||
|
int r = (hash & 0xFF0000) >> 16;
|
||||||
|
int g = (hash & 0x00FF00) >> 8;
|
||||||
|
int b = hash & 0x0000FF;
|
||||||
|
return Color.fromRGBO(r, g, b, 0.5);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
class HomeSizes {
|
class HomeSizes {
|
||||||
static double get menuAddButtonHeight => 60;
|
static const double menuAddButtonHeight = 60;
|
||||||
static double get topBarHeight => 60;
|
static const double topBarHeight = 60;
|
||||||
static double get editPanelTopBarHeight => 60;
|
static const double editPanelTopBarHeight = 60;
|
||||||
static double get editPanelWidth => 400;
|
static const double editPanelWidth = 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
class HomeInsets {
|
class HomeInsets {
|
||||||
static double get topBarTitlePadding => 12;
|
static const double topBarTitlePadding = 12;
|
||||||
}
|
}
|
||||||
|
@ -170,23 +170,24 @@ class HomeStackManager {
|
|||||||
return MultiProvider(
|
return MultiProvider(
|
||||||
providers: [ChangeNotifierProvider.value(value: _notifier)],
|
providers: [ChangeNotifierProvider.value(value: _notifier)],
|
||||||
child: Consumer(
|
child: Consumer(
|
||||||
builder: (ctx, HomeStackNotifier notifier, child) {
|
builder: (_, HomeStackNotifier notifier, __) {
|
||||||
return FadingIndexedStack(
|
return FadingIndexedStack(
|
||||||
index: getIt<PluginSandbox>().indexOf(notifier.plugin.ty),
|
index: getIt<PluginSandbox>().indexOf(notifier.plugin.ty),
|
||||||
children:
|
children: getIt<PluginSandbox>().supportPluginTypes.map(
|
||||||
getIt<PluginSandbox>().supportPluginTypes.map((pluginType) {
|
(pluginType) {
|
||||||
if (pluginType == notifier.plugin.ty) {
|
if (pluginType == notifier.plugin.ty) {
|
||||||
final pluginWidget = notifier.plugin.display
|
final pluginWidget = notifier.plugin.display
|
||||||
.buildWidget(PluginContext(onDeleted: onDeleted));
|
.buildWidget(PluginContext(onDeleted: onDeleted));
|
||||||
if (pluginType == PluginType.editor) {
|
if (pluginType == PluginType.editor) {
|
||||||
return pluginWidget;
|
return pluginWidget;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return pluginWidget.padding(horizontal: 40, vertical: 28);
|
return pluginWidget.padding(horizontal: 40, vertical: 28);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return const BlankPage();
|
return const BlankPage();
|
||||||
}
|
},
|
||||||
}).toList(),
|
).toList(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -204,30 +205,27 @@ class HomeTopBar extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
color: Theme.of(context).colorScheme.onSecondaryContainer,
|
color: Theme.of(context).colorScheme.onSecondaryContainer,
|
||||||
height: HomeSizes.topBarHeight,
|
height: HomeSizes.topBarHeight,
|
||||||
child: Row(
|
child: Padding(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
padding: const EdgeInsets.symmetric(
|
||||||
children: [
|
horizontal: HomeInsets.topBarTitlePadding,
|
||||||
HSpace(layout.menuSpacing),
|
),
|
||||||
const FlowyNavigation(),
|
child: Row(
|
||||||
const HSpace(16),
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
ChangeNotifierProvider.value(
|
children: [
|
||||||
value: Provider.of<HomeStackNotifier>(context, listen: false),
|
HSpace(layout.menuSpacing),
|
||||||
child: Consumer(
|
const FlowyNavigation(),
|
||||||
builder: (
|
const HSpace(16),
|
||||||
BuildContext context,
|
ChangeNotifierProvider.value(
|
||||||
HomeStackNotifier notifier,
|
value: Provider.of<HomeStackNotifier>(context, listen: false),
|
||||||
Widget? child,
|
child: Consumer(
|
||||||
) {
|
builder: (_, HomeStackNotifier notifier, __) =>
|
||||||
return notifier.plugin.display.rightBarItem ?? const SizedBox();
|
notifier.plugin.display.rightBarItem ??
|
||||||
},
|
const SizedBox.shrink(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
) // _renderMoreButton(),
|
],
|
||||||
],
|
).bottomBorder(color: Theme.of(context).dividerColor),
|
||||||
)
|
),
|
||||||
.padding(
|
|
||||||
horizontal: HomeInsets.topBarTitlePadding,
|
|
||||||
)
|
|
||||||
.bottomBorder(color: Theme.of(context).dividerColor),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
|
import 'package:appflowy/util/color_generator/color_generator.dart';
|
||||||
import 'package:appflowy/workspace/application/menu/menu_user_bloc.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/settings_dialog.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
|
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
|
||||||
@ -45,8 +46,31 @@ class MenuUser extends StatelessWidget {
|
|||||||
String iconUrl = context.read<MenuUserBloc>().state.userProfile.iconUrl;
|
String iconUrl = context.read<MenuUserBloc>().state.userProfile.iconUrl;
|
||||||
if (iconUrl.isEmpty) {
|
if (iconUrl.isEmpty) {
|
||||||
iconUrl = defaultUserAvatar;
|
iconUrl = defaultUserAvatar;
|
||||||
|
final String name = context.read<MenuUserBloc>().state.userProfile.name;
|
||||||
|
final Color color = ColorGenerator().generateColorFromString(name);
|
||||||
|
const initialsCount = 2;
|
||||||
|
// Taking the first letters of the name components and limiting to 2 elements
|
||||||
|
final nameInitials = name
|
||||||
|
.split(' ')
|
||||||
|
.where((element) => element.isNotEmpty)
|
||||||
|
.take(initialsCount)
|
||||||
|
.map((element) => element[0].toUpperCase())
|
||||||
|
.join('');
|
||||||
|
return Container(
|
||||||
|
width: 28,
|
||||||
|
height: 28,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: color,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: FlowyText.semibold(
|
||||||
|
nameInitials,
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: nameInitials.length == initialsCount ? 12 : 14,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 25,
|
width: 25,
|
||||||
height: 25,
|
height: 25,
|
||||||
|
@ -17,12 +17,13 @@ class ViewLeftBarItem extends StatefulWidget {
|
|||||||
class _ViewLeftBarItemState extends State<ViewLeftBarItem> {
|
class _ViewLeftBarItemState extends State<ViewLeftBarItem> {
|
||||||
final _controller = TextEditingController();
|
final _controller = TextEditingController();
|
||||||
final _focusNode = FocusNode();
|
final _focusNode = FocusNode();
|
||||||
late ViewService _viewService;
|
late final ViewService _viewService;
|
||||||
late ViewListener _viewListener;
|
late final ViewListener _viewListener;
|
||||||
late ViewPB view;
|
late ViewPB view;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
super.initState();
|
||||||
view = widget.view;
|
view = widget.view;
|
||||||
_viewService = ViewService();
|
_viewService = ViewService();
|
||||||
_focusNode.addListener(_handleFocusChanged);
|
_focusNode.addListener(_handleFocusChanged);
|
||||||
@ -39,7 +40,8 @@ class _ViewLeftBarItemState extends State<ViewLeftBarItem> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
super.initState();
|
|
||||||
|
_controller.text = view.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -53,30 +55,24 @@ class _ViewLeftBarItemState extends State<ViewLeftBarItem> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
_controller.text = view.name;
|
return GestureDetector(
|
||||||
|
|
||||||
return IntrinsicWidth(
|
|
||||||
key: ValueKey(_controller.text),
|
key: ValueKey(_controller.text),
|
||||||
child: GestureDetector(
|
onDoubleTap: () {
|
||||||
onDoubleTap: () {
|
_controller.selection = TextSelection(
|
||||||
_controller.selection = TextSelection(
|
baseOffset: 0,
|
||||||
baseOffset: 0,
|
extentOffset: _controller.text.length,
|
||||||
extentOffset: _controller.text.length,
|
);
|
||||||
);
|
},
|
||||||
},
|
child: TextField(
|
||||||
child: TextField(
|
controller: _controller,
|
||||||
controller: _controller,
|
focusNode: _focusNode,
|
||||||
focusNode: _focusNode,
|
scrollPadding: EdgeInsets.zero,
|
||||||
scrollPadding: EdgeInsets.zero,
|
decoration: const InputDecoration(
|
||||||
decoration: const InputDecoration(
|
contentPadding: EdgeInsets.symmetric(vertical: 4.0),
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 4.0),
|
border: InputBorder.none,
|
||||||
border: InputBorder.none,
|
isDense: true,
|
||||||
isDense: true,
|
|
||||||
),
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
|
||||||
// cursorColor: widget.cursorColor,
|
|
||||||
// obscureText: widget.enableObscure,
|
|
||||||
),
|
),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ String languageFromLocale(Locale locale) {
|
|||||||
case "hu":
|
case "hu":
|
||||||
return "Magyar";
|
return "Magyar";
|
||||||
case "id":
|
case "id":
|
||||||
return "Bahasa";
|
return "Bahasa Indonesia";
|
||||||
case "it":
|
case "it":
|
||||||
return "Italiano";
|
return "Italiano";
|
||||||
case "ja":
|
case "ja":
|
||||||
|
@ -3,7 +3,7 @@ export 'package:styled_widget/styled_widget.dart';
|
|||||||
|
|
||||||
extension FlowyStyledWidget on Widget {
|
extension FlowyStyledWidget on Widget {
|
||||||
Widget bottomBorder({double width = 1.0, Color color = Colors.grey}) {
|
Widget bottomBorder({double width = 1.0, Color color = Colors.grey}) {
|
||||||
return Container(
|
return DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
bottom: BorderSide(width: width, color: color),
|
bottom: BorderSide(width: width, color: color),
|
||||||
@ -14,7 +14,7 @@ extension FlowyStyledWidget on Widget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget topBorder({double width = 1.0, Color color = Colors.grey}) {
|
Widget topBorder({double width = 1.0, Color color = Colors.grey}) {
|
||||||
return Container(
|
return DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
top: BorderSide(width: width, color: color),
|
top: BorderSide(width: width, color: color),
|
||||||
|
@ -16,6 +16,7 @@ class FlowyIconButton extends StatelessWidget {
|
|||||||
final EdgeInsets iconPadding;
|
final EdgeInsets iconPadding;
|
||||||
final BorderRadius? radius;
|
final BorderRadius? radius;
|
||||||
final String? tooltipText;
|
final String? tooltipText;
|
||||||
|
final InlineSpan? richTooltipText;
|
||||||
final bool preferBelow;
|
final bool preferBelow;
|
||||||
|
|
||||||
const FlowyIconButton({
|
const FlowyIconButton({
|
||||||
@ -29,15 +30,22 @@ class FlowyIconButton extends StatelessWidget {
|
|||||||
this.iconPadding = EdgeInsets.zero,
|
this.iconPadding = EdgeInsets.zero,
|
||||||
this.radius,
|
this.radius,
|
||||||
this.tooltipText,
|
this.tooltipText,
|
||||||
|
this.richTooltipText,
|
||||||
this.preferBelow = true,
|
this.preferBelow = true,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
}) : super(key: key);
|
}) : assert((richTooltipText != null && tooltipText == null) ||
|
||||||
|
(richTooltipText == null && tooltipText != null) ||
|
||||||
|
(richTooltipText == null && tooltipText == null)),
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget child = icon;
|
Widget child = icon;
|
||||||
final size = Size(width, height ?? width);
|
final size = Size(width, height ?? width);
|
||||||
|
|
||||||
|
final tooltipMessage =
|
||||||
|
tooltipText == null && richTooltipText == null ? '' : tooltipText;
|
||||||
|
|
||||||
assert(size.width > iconPadding.horizontal);
|
assert(size.width > iconPadding.horizontal);
|
||||||
assert(size.height > iconPadding.vertical);
|
assert(size.height > iconPadding.vertical);
|
||||||
|
|
||||||
@ -46,11 +54,14 @@ class FlowyIconButton extends StatelessWidget {
|
|||||||
final childSize = Size(childWidth, childWidth);
|
final childSize = Size(childWidth, childWidth);
|
||||||
|
|
||||||
return ConstrainedBox(
|
return ConstrainedBox(
|
||||||
constraints:
|
constraints: BoxConstraints.tightFor(
|
||||||
BoxConstraints.tightFor(width: size.width, height: size.height),
|
width: size.width,
|
||||||
|
height: size.height,
|
||||||
|
),
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
preferBelow: preferBelow,
|
preferBelow: preferBelow,
|
||||||
message: tooltipText ?? '',
|
message: tooltipMessage,
|
||||||
|
richMessage: richTooltipText,
|
||||||
showDuration: Duration.zero,
|
showDuration: Duration.zero,
|
||||||
child: RawMaterialButton(
|
child: RawMaterialButton(
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
|
@ -13,9 +13,11 @@ void main() {
|
|||||||
|
|
||||||
group('Edit Grid:', () {
|
group('Edit Grid:', () {
|
||||||
late GridTestContext context;
|
late GridTestContext context;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
context = await gridTest.createTestGrid();
|
context = await gridTest.createTestGrid();
|
||||||
});
|
});
|
||||||
|
|
||||||
// The initial number of rows is 3 for each grid.
|
// The initial number of rows is 3 for each grid.
|
||||||
blocTest<GridBloc, GridState>(
|
blocTest<GridBloc, GridState>(
|
||||||
"create a row",
|
"create a row",
|
||||||
@ -54,5 +56,34 @@ void main() {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
String? firstId;
|
||||||
|
String? secondId;
|
||||||
|
String? thirdId;
|
||||||
|
|
||||||
|
blocTest(
|
||||||
|
'reorder rows',
|
||||||
|
build: () => GridBloc(
|
||||||
|
view: context.gridView,
|
||||||
|
databaseController: DatabaseController(
|
||||||
|
view: context.gridView,
|
||||||
|
layoutType: DatabaseLayoutPB.Grid,
|
||||||
|
),
|
||||||
|
)..add(const GridEvent.initial()),
|
||||||
|
act: (bloc) async {
|
||||||
|
await gridResponseFuture();
|
||||||
|
|
||||||
|
firstId = bloc.state.rowInfos[0].rowPB.id;
|
||||||
|
secondId = bloc.state.rowInfos[1].rowPB.id;
|
||||||
|
thirdId = bloc.state.rowInfos[2].rowPB.id;
|
||||||
|
|
||||||
|
bloc.add(const GridEvent.moveRow(0, 2));
|
||||||
|
},
|
||||||
|
verify: (bloc) {
|
||||||
|
expect(secondId, bloc.state.rowInfos[0].rowPB.id);
|
||||||
|
expect(thirdId, bloc.state.rowInfos[1].rowPB.id);
|
||||||
|
expect(firstId, bloc.state.rowInfos[2].rowPB.id);
|
||||||
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ mod tests {
|
|||||||
date: Some("1653609600".to_owned()),
|
date: Some("1653609600".to_owned()),
|
||||||
time: Some("9:00 AM".to_owned()),
|
time: Some("9:00 AM".to_owned()),
|
||||||
include_time: Some(true),
|
include_time: Some(true),
|
||||||
timezone_id: None,
|
timezone_id: Some("Etc/UTC".to_owned()),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
"May 27, 2022 09:00 AM",
|
"May 27, 2022 09:00 AM",
|
||||||
@ -213,7 +213,7 @@ mod tests {
|
|||||||
date: Some("1653609600".to_owned()),
|
date: Some("1653609600".to_owned()),
|
||||||
time: Some("1:".to_owned()),
|
time: Some("1:".to_owned()),
|
||||||
include_time: Some(true),
|
include_time: Some(true),
|
||||||
timezone_id: None,
|
timezone_id: Some("Etc/UTC".to_owned()),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
"May 27, 2022 01:00",
|
"May 27, 2022 01:00",
|
||||||
@ -252,7 +252,7 @@ mod tests {
|
|||||||
date: Some("1653609600".to_owned()),
|
date: Some("1653609600".to_owned()),
|
||||||
time: Some("00:00".to_owned()),
|
time: Some("00:00".to_owned()),
|
||||||
include_time: Some(true),
|
include_time: Some(true),
|
||||||
timezone_id: None,
|
timezone_id: Some("Etc/UTC".to_owned()),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
"May 27, 2022 00:00",
|
"May 27, 2022 00:00",
|
||||||
@ -273,7 +273,7 @@ mod tests {
|
|||||||
date: Some("1653609600".to_owned()),
|
date: Some("1653609600".to_owned()),
|
||||||
time: Some("1:00 am".to_owned()),
|
time: Some("1:00 am".to_owned()),
|
||||||
include_time: Some(true),
|
include_time: Some(true),
|
||||||
timezone_id: None,
|
timezone_id: Some("Etc/UTC".to_owned()),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
"May 27, 2022 01:00 AM",
|
"May 27, 2022 01:00 AM",
|
||||||
@ -372,7 +372,7 @@ mod tests {
|
|||||||
date: Some("1700006400".to_owned()),
|
date: Some("1700006400".to_owned()),
|
||||||
time: Some("08:00".to_owned()),
|
time: Some("08:00".to_owned()),
|
||||||
include_time: Some(true),
|
include_time: Some(true),
|
||||||
timezone_id: None,
|
timezone_id: Some("Etc/UTC".to_owned()),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
assert_date(
|
assert_date(
|
||||||
@ -382,7 +382,7 @@ mod tests {
|
|||||||
date: None,
|
date: None,
|
||||||
time: Some("14:00".to_owned()),
|
time: Some("14:00".to_owned()),
|
||||||
include_time: None,
|
include_time: None,
|
||||||
timezone_id: None,
|
timezone_id: Some("Etc/UTC".to_owned()),
|
||||||
},
|
},
|
||||||
Some(old_cell_data),
|
Some(old_cell_data),
|
||||||
"Nov 15, 2023 14:00",
|
"Nov 15, 2023 14:00",
|
||||||
|
@ -1,29 +1,17 @@
|
|||||||
|
|
||||||
// @ts-check
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type { import("@inlang/core/config").DefineConfig }
|
|
||||||
*/
|
|
||||||
export async function defineConfig(env) {
|
export async function defineConfig(env) {
|
||||||
const plugin = await env.$import(
|
const { default: pluginJson } = await env.$import(
|
||||||
"https://cdn.jsdelivr.net/gh/samuelstroschein/inlang-plugin-json@1.1.1/dist/index.js"
|
'https://cdn.jsdelivr.net/gh/samuelstroschein/inlang-plugin-json@2/dist/index.js'
|
||||||
);
|
);
|
||||||
|
|
||||||
const { default: standardLintRules } = await env.$import(
|
const { default: standardLintRules } = await env.$import(
|
||||||
"https://cdn.jsdelivr.net/gh/inlang/standard-lint-rules@1.1.1/dist/index.js"
|
'https://cdn.jsdelivr.net/gh/inlang/standard-lint-rules@2/dist/index.js'
|
||||||
);
|
);
|
||||||
|
|
||||||
const pluginConfig = {
|
return {
|
||||||
pathPattern: "./frontend/appflowy_flutter/assets/translations/{language}.json",
|
referenceLanguage: 'en',
|
||||||
};
|
plugins: [pluginJson({
|
||||||
|
pathPattern: './frontend/appflowy_flutter/assets/translations/{language}.json',
|
||||||
return {
|
variableReferencePattern: ["@:"]
|
||||||
referenceLanguage: "en",
|
}), standardLintRules()]
|
||||||
languages: await plugin.getLanguages({ ...env, pluginConfig }),
|
};
|
||||||
readResources: (args) => plugin.readResources({ ...args, ...env, pluginConfig }),
|
}
|
||||||
writeResources: (args) => plugin.writeResources({ ...args, ...env, pluginConfig }),
|
|
||||||
lint: {
|
|
||||||
rules: [standardLintRules()],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user