|
1 | 1 | import 'package:appflowy/generated/flowy_svgs.g.dart'; |
2 | 2 | import 'package:appflowy/generated/locale_keys.g.dart'; |
3 | 3 | import 'package:appflowy/startup/tasks/app_widget.dart'; |
| 4 | +import 'package:appflowy/util/theme_extension.dart'; |
4 | 5 | import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/shared_widget.dart'; |
5 | 6 | import 'package:easy_localization/easy_localization.dart'; |
6 | 7 | import 'package:flowy_infra/size.dart'; |
@@ -364,71 +365,59 @@ class OkCancelButton extends StatelessWidget { |
364 | 365 |
|
365 | 366 | void showToastNotification( |
366 | 367 | BuildContext context, { |
367 | | - required String message, |
| 368 | + String? message, |
| 369 | + TextSpan? richMessage, |
368 | 370 | String? description, |
369 | 371 | ToastificationType type = ToastificationType.success, |
370 | 372 | ToastificationCallbacks? callbacks, |
371 | 373 | double bottomPadding = 100, |
372 | 374 | }) { |
373 | | - if (UniversalPlatform.isMobile) { |
374 | | - toastification.showCustom( |
375 | | - alignment: Alignment.bottomCenter, |
376 | | - autoCloseDuration: const Duration(milliseconds: 3000), |
377 | | - callbacks: callbacks ?? const ToastificationCallbacks(), |
378 | | - builder: (_, __) => _MToast( |
379 | | - message: message, |
380 | | - type: type, |
381 | | - bottomPadding: bottomPadding, |
382 | | - description: description, |
383 | | - ), |
384 | | - ); |
385 | | - return; |
386 | | - } |
387 | | - |
388 | | - toastification.show( |
389 | | - context: context, |
390 | | - type: type, |
391 | | - style: ToastificationStyle.flat, |
392 | | - closeButtonShowType: CloseButtonShowType.onHover, |
| 375 | + assert( |
| 376 | + (message == null) != (richMessage == null), |
| 377 | + "Exactly one of message or richMessage must be non-null.", |
| 378 | + ); |
| 379 | + toastification.showCustom( |
393 | 380 | alignment: Alignment.bottomCenter, |
394 | 381 | autoCloseDuration: const Duration(milliseconds: 3000), |
395 | | - showProgressBar: false, |
396 | | - backgroundColor: Theme.of(context).colorScheme.surface, |
397 | | - borderSide: BorderSide( |
398 | | - color: Colors.grey.withOpacity(0.4), |
399 | | - ), |
400 | | - title: FlowyText( |
401 | | - message, |
402 | | - maxLines: 3, |
403 | | - ), |
404 | | - description: description != null |
405 | | - ? FlowyText.regular( |
406 | | - description, |
407 | | - fontSize: 12, |
408 | | - lineHeight: 1.2, |
409 | | - maxLines: 3, |
410 | | - ) |
411 | | - : null, |
| 382 | + callbacks: callbacks ?? const ToastificationCallbacks(), |
| 383 | + builder: (_, item) { |
| 384 | + return UniversalPlatform.isMobile |
| 385 | + ? _MobileToast( |
| 386 | + message: message, |
| 387 | + type: type, |
| 388 | + bottomPadding: bottomPadding, |
| 389 | + description: description, |
| 390 | + ) |
| 391 | + : _DesktopToast( |
| 392 | + message: message, |
| 393 | + richMessage: richMessage, |
| 394 | + type: type, |
| 395 | + onDismiss: () => toastification.dismiss(item), |
| 396 | + ); |
| 397 | + }, |
412 | 398 | ); |
413 | 399 | } |
414 | 400 |
|
415 | | -class _MToast extends StatelessWidget { |
416 | | - const _MToast({ |
417 | | - required this.message, |
| 401 | +class _MobileToast extends StatelessWidget { |
| 402 | + const _MobileToast({ |
| 403 | + this.message, |
418 | 404 | this.type = ToastificationType.success, |
419 | 405 | this.bottomPadding = 100, |
420 | 406 | this.description, |
421 | 407 | }); |
422 | 408 |
|
423 | | - final String message; |
| 409 | + final String? message; |
424 | 410 | final ToastificationType type; |
425 | 411 | final double bottomPadding; |
426 | 412 | final String? description; |
427 | 413 |
|
428 | 414 | @override |
429 | 415 | Widget build(BuildContext context) { |
| 416 | + if (message == null) { |
| 417 | + return const SizedBox.shrink(); |
| 418 | + } |
430 | 419 | final hintText = FlowyText.regular( |
431 | | - message, |
| 420 | + message!, |
432 | 421 | fontSize: 16.0, |
433 | 422 | figmaLineHeight: 18.0, |
434 | 423 | color: Colors.white, |
@@ -498,6 +487,90 @@ class _MToast extends StatelessWidget { |
498 | 487 | } |
499 | 488 | } |
500 | 489 |
|
| 490 | +class _DesktopToast extends StatelessWidget { |
| 491 | + const _DesktopToast({ |
| 492 | + this.message, |
| 493 | + this.richMessage, |
| 494 | + required this.type, |
| 495 | + this.onDismiss, |
| 496 | + }); |
| 497 | + |
| 498 | + final String? message; |
| 499 | + final TextSpan? richMessage; |
| 500 | + final ToastificationType type; |
| 501 | + final void Function()? onDismiss; |
| 502 | + |
| 503 | + @override |
| 504 | + Widget build(BuildContext context) { |
| 505 | + return Center( |
| 506 | + child: Container( |
| 507 | + constraints: const BoxConstraints(maxWidth: 360.0), |
| 508 | + padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), |
| 509 | + margin: const EdgeInsets.only(bottom: 32.0), |
| 510 | + decoration: BoxDecoration( |
| 511 | + color: Theme.of(context).isLightMode |
| 512 | + ? const Color(0xFF333333) |
| 513 | + : const Color(0xFF363D49), |
| 514 | + borderRadius: const BorderRadius.all(Radius.circular(8.0)), |
| 515 | + ), |
| 516 | + child: Row( |
| 517 | + mainAxisSize: MainAxisSize.min, |
| 518 | + mainAxisAlignment: MainAxisAlignment.center, |
| 519 | + children: [ |
| 520 | + // icon |
| 521 | + FlowySvg( |
| 522 | + switch (type) { |
| 523 | + ToastificationType.warning => FlowySvgs.toast_warning_filled_s, |
| 524 | + ToastificationType.success => FlowySvgs.toast_checked_filled_s, |
| 525 | + ToastificationType.error => FlowySvgs.toast_error_filled_s, |
| 526 | + _ => throw UnimplementedError(), |
| 527 | + }, |
| 528 | + size: const Size.square(20.0), |
| 529 | + blendMode: null, |
| 530 | + ), |
| 531 | + const HSpace(8.0), |
| 532 | + // text |
| 533 | + Flexible( |
| 534 | + child: message != null |
| 535 | + ? FlowyText( |
| 536 | + message!, |
| 537 | + maxLines: 2, |
| 538 | + figmaLineHeight: 20.0, |
| 539 | + overflow: TextOverflow.ellipsis, |
| 540 | + color: const Color(0xFFFFFFFF), |
| 541 | + ) |
| 542 | + : RichText( |
| 543 | + text: richMessage!, |
| 544 | + maxLines: 2, |
| 545 | + overflow: TextOverflow.ellipsis, |
| 546 | + ), |
| 547 | + ), |
| 548 | + const HSpace(16.0), |
| 549 | + // close |
| 550 | + MouseRegion( |
| 551 | + cursor: SystemMouseCursors.click, |
| 552 | + child: GestureDetector( |
| 553 | + behavior: HitTestBehavior.opaque, |
| 554 | + onTap: onDismiss, |
| 555 | + child: const SizedBox.square( |
| 556 | + dimension: 24.0, |
| 557 | + child: Center( |
| 558 | + child: FlowySvg( |
| 559 | + FlowySvgs.toast_close_s, |
| 560 | + size: Size.square(16.0), |
| 561 | + color: Color(0xFFBDBDBD), |
| 562 | + ), |
| 563 | + ), |
| 564 | + ), |
| 565 | + ), |
| 566 | + ), |
| 567 | + ], |
| 568 | + ), |
| 569 | + ), |
| 570 | + ); |
| 571 | + } |
| 572 | +} |
| 573 | + |
501 | 574 | Future<void> showConfirmDeletionDialog({ |
502 | 575 | required BuildContext context, |
503 | 576 | required String name, |
|
0 commit comments