feat: support editing database icon (#4052)

This commit is contained in:
Lucas.Xu 2023-11-30 16:56:44 +08:00 committed by GitHub
parent b307dd30d8
commit d7a67c0efb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 143 additions and 62 deletions

View File

@ -304,7 +304,7 @@ class _SingleMobileInnerViewItemState extends State<SingleMobileInnerViewItem> {
_buildLeftIcon(),
const HSpace(4),
// icon
_buildViewIconButton(),
_buildViewIcon(),
const HSpace(8),
// title
Expanded(
@ -354,7 +354,7 @@ class _SingleMobileInnerViewItemState extends State<SingleMobileInnerViewItem> {
return child;
}
Widget _buildViewIconButton() {
Widget _buildViewIcon() {
final icon = widget.view.icon.value.isNotEmpty
? EmojiText(
emoji: widget.view.icon.value,

View File

@ -1,13 +1,36 @@
import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart';
import 'package:appflowy/plugins/base/emoji/emoji_text.dart';
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
import 'package:appflowy/plugins/database_view/application/tab_bar_bloc.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/mobile_database_settings_button.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:collection/collection.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';
class MobileTabBarHeader extends StatelessWidget {
class MobileTabBarHeader extends StatefulWidget {
const MobileTabBarHeader({super.key});
@override
State<MobileTabBarHeader> createState() => _MobileTabBarHeaderState();
}
class _MobileTabBarHeaderState extends State<MobileTabBarHeader> {
final controller = TextEditingController();
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<DatabaseTabBarBloc, DatabaseTabBarState>(
@ -20,6 +43,8 @@ class MobileTabBarHeader extends StatelessWidget {
return const SizedBox.shrink();
}
controller.text = currentView.view.name;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -27,11 +52,31 @@ class MobileTabBarHeader extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 14),
child: Row(
children: [
_buildViewIconButton(currentView.view),
const HSpace(8.0),
Expanded(
child: Text(
currentView.view.name,
style: Theme.of(context).textTheme.titleLarge,
overflow: TextOverflow.ellipsis,
child: FlowyTextField(
autoFocus: false,
maxLines: null,
controller: controller,
textAlignVertical: TextAlignVertical.top,
decoration: const InputDecoration(
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
contentPadding: EdgeInsets.zero,
),
textStyle: Theme.of(context).textTheme.titleLarge,
onSubmitted: (value) {
if (value.isNotEmpty) {
context.read<ViewBloc>().add(
ViewEvent.rename(value),
);
}
},
onCanceled: () {
controller.text = currentView.view.name;
},
),
),
MobileDatabaseSettingsButton(
@ -43,10 +88,40 @@ class MobileTabBarHeader extends StatelessWidget {
],
),
),
const Divider(height: 1, thickness: 1),
const Divider(
height: 1,
thickness: 1,
),
],
);
},
);
}
Widget _buildViewIconButton(ViewPB view) {
final icon = view.icon.value.isNotEmpty
? EmojiText(
emoji: view.icon.value,
fontSize: 24.0,
)
: SizedBox.square(
dimension: 26.0,
child: view.defaultIcon(),
);
return FlowyButton(
text: icon,
useIntrinsicWidth: true,
onTap: () async {
final result = await context.push<EmojiPickerResult>(
MobileEmojiPickerScreen.routeName,
);
if (context.mounted && result != null) {
await ViewBackendService.updateViewIcon(
viewId: view.id,
viewIcon: result.emoji,
);
}
},
);
}
}

View File

@ -20,7 +20,7 @@ class FlowyTextField extends StatefulWidget {
final bool submitOnLeave;
final Duration? debounceDuration;
final String? errorText;
final int maxLines;
final int? maxLines;
final bool showCounter;
final Widget? prefixIcon;
final Widget? suffixIcon;
@ -28,6 +28,8 @@ class FlowyTextField extends StatefulWidget {
final BoxConstraints? suffixIconConstraints;
final BoxConstraints? hintTextConstraints;
final TextStyle? hintStyle;
final InputDecoration? decoration;
final TextAlignVertical? textAlignVertical;
const FlowyTextField({
super.key,
@ -54,6 +56,8 @@ class FlowyTextField extends StatefulWidget {
this.suffixIconConstraints,
this.hintTextConstraints,
this.hintStyle,
this.decoration,
this.textAlignVertical,
});
@override
@ -130,64 +134,66 @@ class FlowyTextFieldState extends State<FlowyTextField> {
maxLength: widget.maxLength,
maxLengthEnforcement: MaxLengthEnforcement.truncateAfterCompositionEnds,
style: widget.textStyle ?? Theme.of(context).textTheme.bodySmall,
textAlignVertical: TextAlignVertical.center,
textAlignVertical: widget.textAlignVertical ?? TextAlignVertical.center,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
constraints: widget.hintTextConstraints ??
BoxConstraints(
maxHeight: widget.errorText?.isEmpty ?? true ? 32 : 58,
decoration: widget.decoration ??
InputDecoration(
constraints: widget.hintTextConstraints ??
BoxConstraints(
maxHeight: widget.errorText?.isEmpty ?? true ? 32 : 58,
),
contentPadding: EdgeInsets.symmetric(
horizontal: 12,
vertical:
(widget.maxLines == null || widget.maxLines! > 1) ? 12 : 0,
),
contentPadding: EdgeInsets.symmetric(
horizontal: 12,
vertical: widget.maxLines > 1 ? 12 : 0,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.outline,
width: 1.0,
),
borderRadius: Corners.s8Border,
),
isDense: false,
hintText: widget.hintText,
errorText: widget.errorText,
errorStyle: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Theme.of(context).colorScheme.error),
hintStyle: widget.hintStyle ??
Theme.of(context)
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.outline,
width: 1.0,
),
borderRadius: Corners.s8Border,
),
isDense: false,
hintText: widget.hintText,
errorText: widget.errorText,
errorStyle: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Theme.of(context).hintColor),
suffixText: widget.showCounter ? _suffixText() : "",
counterText: "",
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary,
width: 1.0,
.copyWith(color: Theme.of(context).colorScheme.error),
hintStyle: widget.hintStyle ??
Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Theme.of(context).hintColor),
suffixText: widget.showCounter ? _suffixText() : "",
counterText: "",
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary,
width: 1.0,
),
borderRadius: Corners.s8Border,
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.error,
width: 1.0,
),
borderRadius: Corners.s8Border,
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.error,
width: 1.0,
),
borderRadius: Corners.s8Border,
),
prefixIcon: widget.prefixIcon,
suffixIcon: widget.suffixIcon,
prefixIconConstraints: widget.prefixIconConstraints,
suffixIconConstraints: widget.suffixIconConstraints,
),
borderRadius: Corners.s8Border,
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.error,
width: 1.0,
),
borderRadius: Corners.s8Border,
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.error,
width: 1.0,
),
borderRadius: Corners.s8Border,
),
prefixIcon: widget.prefixIcon,
suffixIcon: widget.suffixIcon,
prefixIconConstraints: widget.prefixIconConstraints,
suffixIconConstraints: widget.suffixIconConstraints,
),
);
}