Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .fvmrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"flutter": "3.35.4"
"flutter": "3.38.5"
}
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
### 0.0.10
- WdsTextArea > 최소 높이 60px / 최대 높이 320px 대응될 수 있게끔 개선
- WdsTextArea > 'label' 파라미터 String에서 Text로 형변환

- WdsToast > size width infinity하게 설정

### 0.0.9
- WdsToolTip > 'message'에서 'label'로 변경
Expand Down
119 changes: 119 additions & 0 deletions lib/src/util/message/wds_message_util.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import 'dart:async';

import 'package:flutter/material.dart' show Material, MaterialType;
import 'package:flutter/widgets.dart';
import 'package:wds_components/wds_components.dart'
show WdsSnackbar, WdsToast, WdsSectionMessage;

/// [WdsSnackbar], [WdsToast], [WdsSectionMessage]의
/// 생명주기를 관리하는 컨트롤러
class WdsMessageController {
WdsMessageController(this._entry, [this._timer]);

final OverlayEntry _entry;

final Timer? _timer;

bool _isDismissed = false;

/// 위젯을 제거
void dismiss() {
if (_isDismissed) return;
_isDismissed = true;
try {
_timer?.cancel();
_entry.remove();
} catch (_) {}
}
}

extension WdsMessageUtilExtension on BuildContext {
/// [WdsSnackbar], [WdsToast], [WdsSectionMessage]를 표시
///
/// 위젯을 파라미터로 받아서 표시
/// WdsSnackbar, WdsToast, WdsSectionMessage 중 하나여야 하며,
/// 그 외의 위젯이 전달되면 assert 오류가 발생
///
/// [duration]이 제공되면 해당 시간 후 자동으로 제거
/// [bottomOffset]은 하단에서의 오프셋을 지정
/// [dismissOnTapOutside]가 true면 위젯 외부 탭 시 dismiss
///
/// 예시:
/// ```dart
/// final controller = context.onMessage(
/// WdsSnackbar.multiLine(message: '메시지'),
/// duration: const Duration(seconds: 3),
/// );
///
WdsMessageController onMessage(
Widget widget, {
Duration duration = const Duration(seconds: 3),
double bottomOffset = 80,
bool dismissOnTapOutside = true,
}) {
assert(
widget is WdsSnackbar ||
widget is WdsToast ||
widget is WdsSectionMessage,
'widget은 WdsSnackbar, WdsToast, WdsSectionMessage 중 하나여야 합니다.',
);

final overlay = Overlay.of(this, rootOverlay: true);

final overlayEntry = OverlayEntry(
builder: (BuildContext context) {
return SafeArea(
top: false,
left: false,
right: false,
child: Align(
alignment: Alignment.bottomCenter,
child: LayoutBuilder(
builder: (context, constraints) {
const fixedWidth = 420.0;
const horizontalPadding = 16.0;

// 모바일 크기 내에서는 양옆 padding을 고려한 너비 사용
// 그보다 큰 경우에는 고정 너비 사용
final isMobile = constraints.maxWidth <= fixedWidth;
final availableWidth =
constraints.maxWidth - (horizontalPadding * 2);
final maxWidth = isMobile ? availableWidth : fixedWidth;
final minWidth = isMobile ? availableWidth : fixedWidth;

return Padding(
padding: EdgeInsets.only(
left: horizontalPadding,
right: horizontalPadding,
bottom: bottomOffset,
),
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: minWidth,
maxWidth: maxWidth,
),
child: Material(
type: MaterialType.transparency,
child: widget,
),
),
);
},
),
),
);
},
);

overlay.insert(overlayEntry);

Timer? timer;
timer = Timer(duration, () {
try {
overlayEntry.remove();
} catch (_) {}
});

return WdsMessageController(overlayEntry, timer);
}
}
3 changes: 3 additions & 0 deletions lib/src/util/util.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
library;

export 'message/wds_message_util.dart';
3 changes: 3 additions & 0 deletions lib/wds.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ library;

export 'package:wds_components/wds_components.dart';
export 'package:wds_foundation/wds_foundation.dart';

/// util export
export 'src/util/util.dart';
102 changes: 68 additions & 34 deletions packages/widgetbook/lib/src/component/section_message_use_case.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:wds/wds.dart';
import 'package:wds_widgetbook/src/widgetbook_components/widgetbook_components.dart';
import 'package:widgetbook/widgetbook.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;
Expand Down Expand Up @@ -35,35 +36,19 @@ Widget _buildPlaygroundSection(BuildContext context) {
initialValue: '정보를 확인해주세요',
);

final hasIcon = context.knobs.boolean(
label: 'hasIcon',
description: '아이콘을 표시할지 선택하세요',
);

final icon = context.knobs.object.dropdown<WdsIcon>(
label: 'icon',
initialOption: WdsIcon.info,
options: WdsIcon.values,
labelBuilder: (v) => v.name,
);

return WidgetbookPlayground(
info: [
'variant: ${variant.name}',
'message: "$message"',
'hasIcon: $hasIcon',
if (hasIcon) 'icon: ${icon.name}',
'padding: EdgeInsets.all(16)',
'iconSize: 16x16',
'iconSpacing: 4px',
'textStyle: body14NormalMedium',
_getVariantInfo(variant),
],
child: _buildSectionMessage(
child: _SectionMessagePlaygroundControls(
variant: variant,
message: message,
hasIcon: hasIcon,
icon: icon,
),
);
}
Expand All @@ -79,23 +64,72 @@ String _getVariantInfo(WdsSectionMessageVariant variant) {
};
}

Widget _buildSectionMessage({
required WdsSectionMessageVariant variant,
required String message,
required bool hasIcon,
required WdsIcon icon,
}) {
return switch (variant) {
WdsSectionMessageVariant.normal => WdsSectionMessage.normal(
message: message,
),
WdsSectionMessageVariant.highlight => WdsSectionMessage.highlight(
message: message,
),
WdsSectionMessageVariant.warning => WdsSectionMessage.warning(
message: message,
),
};
class _SectionMessagePlaygroundControls extends StatefulWidget {
const _SectionMessagePlaygroundControls({
required this.variant,
required this.message,
});

final WdsSectionMessageVariant variant;
final String message;

@override
State<_SectionMessagePlaygroundControls> createState() =>
_SectionMessagePlaygroundControlsState();
}

class _SectionMessagePlaygroundControlsState
extends State<_SectionMessagePlaygroundControls> {
WdsMessageController? _controller;

@override
void dispose() {
_controller?.dismiss();
super.dispose();
}

void _showSectionMessage() {
_controller?.dismiss();
final sectionMessage = _buildSectionMessage(
variant: widget.variant,
message: widget.message,
);
_controller = context.onMessage(sectionMessage);
setState(() {});
}

Widget _buildSectionMessage({
required WdsSectionMessageVariant variant,
required String message,
}) {
return switch (variant) {
WdsSectionMessageVariant.normal => WdsSectionMessage.normal(
message: message,
),
WdsSectionMessageVariant.highlight => WdsSectionMessage.highlight(
message: message,
),
WdsSectionMessageVariant.warning => WdsSectionMessage.warning(
message: message,
),
};
}

@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
spacing: 12,
children: [
WdsSquareButton.normal(
onTap: _showSectionMessage,
child: const Text(
'SectionMessage 띄우기',
),
),
],
);
}
}

Widget _buildDemonstrationSection(BuildContext context) {
Expand Down
Loading
Loading