Skip to content

Commit

Permalink
fix: edit group title + rebuild improvement (AppFlowy-IO#6156)
Browse files Browse the repository at this point in the history
* fix: edit group title + rebuild improvement

* chore: fix clippy

* chore: fix clippy

* fix: stop widget replacement causing perf issues

* fix: after merge main

* chore: minor cleanup in view_editor

* fix: attempt to fix hover issue in tests
  • Loading branch information
Xazin authored Sep 5, 2024
1 parent 7ea71fc commit 4f592e8
Show file tree
Hide file tree
Showing 25 changed files with 592 additions and 200 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
Expand Down Expand Up @@ -30,10 +35,6 @@ import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/widget/buttons/primary_button.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

import 'emoji.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import 'package:flutter/material.dart';

import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/card/card.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/plugins/database/application/database_controller.dart';
import 'package:appflowy/plugins/database/board/application/board_bloc.dart';
import 'package:appflowy/plugins/database/board/group_ext.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_builder.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_skeleton/text_card_cell.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';

Expand Down Expand Up @@ -200,7 +202,7 @@ class MobileHiddenGroup extends StatelessWidget {
children: [
Expanded(
child: Text(
context.read<BoardBloc>().generateGroupNameFromGroup(group),
group.generateGroupName(databaseController),
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 2,
overflow: TextOverflow.ellipsis,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import 'dart:async';
import 'dart:collection';

import 'package:flutter/foundation.dart';

import 'package:appflowy/plugins/database/application/defines.dart';
import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:appflowy/plugins/database/domain/group_service.dart';
import 'package:appflowy/plugins/database/application/row/row_service.dart';
import 'package:appflowy/plugins/database/board/group_ext.dart';
import 'package:appflowy/plugins/database/domain/group_service.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
Expand All @@ -13,17 +16,14 @@ import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:appflowy_result/appflowy_result.dart';
import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:protobuf/protobuf.dart' hide FieldInfo;
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:calendar_view/calendar_view.dart';

import '../../application/database_controller.dart';
import '../../application/field/field_controller.dart';
import '../../application/row/row_cache.dart';

import 'group_controller.dart';

part 'board_bloc.freezed.dart';
Expand Down Expand Up @@ -204,13 +204,13 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
endEditingHeader: (String groupId, String? groupName) async {
final group = groupControllers[groupId]?.group;
if (group != null) {
if (generateGroupNameFromGroup(group) != groupName) {
final currentName = group.generateGroupName(databaseController);
if (currentName != groupName) {
await groupBackendSvc.updateGroup(
fieldId: groupControllers.values.first.group.fieldId,
groupId: groupId,
name: groupName,
);
return;
}
}

Expand Down Expand Up @@ -436,7 +436,9 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
boardController.getGroupController(group.groupId);
if (columnController != null) {
// remove the group or update its name
columnController.updateGroupName(generateGroupNameFromGroup(group));
columnController.updateGroupName(
group.generateGroupName(databaseController),
);
if (!group.isVisible) {
boardController.removeGroup(group.groupId);
}
Expand Down Expand Up @@ -516,111 +518,14 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
AppFlowyGroupData _initializeGroupData(GroupPB group) {
return AppFlowyGroupData(
id: group.groupId,
name: generateGroupNameFromGroup(group),
name: group.generateGroupName(databaseController),
items: _buildGroupItems(group),
customData: GroupData(
group: group,
fieldInfo: fieldController.getField(group.fieldId)!,
),
);
}

String generateGroupNameFromGroup(GroupPB group) {
final field = fieldController.getField(group.fieldId);
if (field == null) {
return "";
}

// if the group is the default group, then
if (group.isDefault) {
return "No ${field.name}";
}

final groupSettings = databaseController.fieldController.groupSettings
.firstWhereOrNull((gs) => gs.fieldId == field.id);

switch (field.fieldType) {
case FieldType.SingleSelect:
final options =
SingleSelectTypeOptionPB.fromBuffer(field.field.typeOptionData)
.options;
final option =
options.firstWhereOrNull((option) => option.id == group.groupId);
return option == null ? "" : option.name;
case FieldType.MultiSelect:
final options =
MultiSelectTypeOptionPB.fromBuffer(field.field.typeOptionData)
.options;
final option =
options.firstWhereOrNull((option) => option.id == group.groupId);
return option == null ? "" : option.name;
case FieldType.Checkbox:
return group.groupId;
case FieldType.URL:
return group.groupId;
case FieldType.DateTime:
final config = groupSettings?.content != null
? DateGroupConfigurationPB.fromBuffer(groupSettings!.content)
: DateGroupConfigurationPB();
final dateFormat = DateFormat("y/MM/dd");
try {
final targetDateTime = dateFormat.parseLoose(group.groupId);
switch (config.condition) {
case DateConditionPB.Day:
return DateFormat("MMM dd, y").format(targetDateTime);
case DateConditionPB.Week:
final beginningOfWeek = targetDateTime
.subtract(Duration(days: targetDateTime.weekday - 1));
final endOfWeek = targetDateTime.add(
Duration(days: DateTime.daysPerWeek - targetDateTime.weekday),
);

final beginningOfWeekFormat =
beginningOfWeek.year != endOfWeek.year
? "MMM dd y"
: "MMM dd";
final endOfWeekFormat = beginningOfWeek.month != endOfWeek.month
? "MMM dd y"
: "dd y";

return LocaleKeys.board_dateCondition_weekOf.tr(
args: [
DateFormat(beginningOfWeekFormat).format(beginningOfWeek),
DateFormat(endOfWeekFormat).format(endOfWeek),
],
);
case DateConditionPB.Month:
return DateFormat("MMM y").format(targetDateTime);
case DateConditionPB.Year:
return DateFormat("y").format(targetDateTime);
case DateConditionPB.Relative:
final targetDateTimeDay = DateTime(
targetDateTime.year,
targetDateTime.month,
targetDateTime.day,
);
final nowDay = DateTime.now().withoutTime;
final diff = targetDateTimeDay.difference(nowDay).inDays;
return switch (diff) {
0 => LocaleKeys.board_dateCondition_today.tr(),
-1 => LocaleKeys.board_dateCondition_yesterday.tr(),
1 => LocaleKeys.board_dateCondition_tomorrow.tr(),
-7 => LocaleKeys.board_dateCondition_lastSevenDays.tr(),
2 => LocaleKeys.board_dateCondition_nextSevenDays.tr(),
-30 => LocaleKeys.board_dateCondition_lastThirtyDays.tr(),
8 => LocaleKeys.board_dateCondition_nextThirtyDays.tr(),
_ => DateFormat("MMM y").format(targetDateTimeDay)
};
default:
return "";
}
} on FormatException {
return "";
}
default:
return "";
}
}
}

@freezed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import 'package:appflowy/plugins/database/board/group_ext.dart';
import 'package:appflowy/plugins/database/domain/group_service.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

import '../../application/database_controller.dart';
import '../../application/field/field_controller.dart';

part 'column_header_bloc.freezed.dart';

class ColumnHeaderBloc extends Bloc<ColumnHeaderEvent, ColumnHeaderState> {
ColumnHeaderBloc({
required this.databaseController,
required this.fieldId,
required this.group,
}) : super(const ColumnHeaderState.loading()) {
groupBackendSvc = GroupBackendService(viewId);
_dispatch();
}

final DatabaseController databaseController;
final String fieldId;
final GroupPB group;

late final GroupBackendService groupBackendSvc;

FieldController get fieldController => databaseController.fieldController;
String get viewId => databaseController.viewId;

void _dispatch() {
on<ColumnHeaderEvent>(
(event, emit) async {
await event.when(
initial: () {
final name = group.generateGroupName(databaseController);
emit(ColumnHeaderState.initial(name));
},
startEditing: () async {
state.maybeMap(
ready: (state) => emit(state.copyWith(isEditing: true)),
orElse: () {},
);
},
endEditing: (String? groupName) async {
if (groupName != null) {
final stateGroupName = state.maybeMap(
ready: (state) => state.groupName,
orElse: () => null,
);

if (stateGroupName == null || stateGroupName == groupName) {
state.maybeMap(
ready: (state) => emit(
state.copyWith(
groupName: stateGroupName!,
isEditing: false,
),
),
orElse: () {},
);
}

await groupBackendSvc.renameGroup(
groupId: group.groupId,
fieldId: fieldId,
name: groupName,
);
state.maybeMap(
ready: (state) {
emit(state.copyWith(groupName: groupName, isEditing: false));
},
orElse: () {},
);
}
},
);
},
);
}
}

@freezed
class ColumnHeaderEvent with _$ColumnHeaderEvent {
const factory ColumnHeaderEvent.initial() = _Initial;
const factory ColumnHeaderEvent.startEditing() = _StartEditing;
const factory ColumnHeaderEvent.endEditing(String? groupName) = _EndEditing;
}

@freezed
class ColumnHeaderState with _$ColumnHeaderState {
const ColumnHeaderState._();

const factory ColumnHeaderState.loading() = _ColumnHeaderLoadingState;

const factory ColumnHeaderState.error({
required FlowyError error,
}) = _ColumnHeaderErrorState;

const factory ColumnHeaderState.ready({
required String groupName,
@Default(false) bool isEditing,
@Default(false) bool canEdit,
}) = _ColumnHeaderReadyState;

factory ColumnHeaderState.initial(String name) =>
ColumnHeaderState.ready(groupName: name);

bool get isLoading => maybeMap(loading: (_) => true, orElse: () => false);
bool get isError => maybeMap(error: (_) => true, orElse: () => false);
bool get isReady => maybeMap(ready: (_) => true, orElse: () => false);
}
Loading

0 comments on commit 4f592e8

Please sign in to comment.