Parcourir la source

Merge pull request #474 from AppFlowy-IO/feat_number_format

Feature: support more number format
Nathan.fooo il y a 3 ans
Parent
commit
a298f7c576
16 fichiers modifiés avec 951 ajouts et 136 suppressions
  1. 4 1
      frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart
  2. 142 0
      frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_format_bloc.dart
  3. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart
  4. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart
  5. 22 11
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart
  6. 4 2
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart
  7. 1 3
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart
  8. 3 3
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart
  9. 3 3
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/field_option_pannel.dart
  10. 81 57
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart
  11. 1 0
      frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/flowy_overlay.dart
  12. 67 3
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbenum.dart
  13. 35 3
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbjson.dart
  14. 117 8
      frontend/rust-lib/flowy-grid/src/protobuf/model/number_type_option.rs
  15. 34 2
      frontend/rust-lib/flowy-grid/src/protobuf/proto/number_type_option.proto
  16. 435 38
      frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs

+ 4 - 1
frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart

@@ -96,7 +96,10 @@ class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionE
 
   List<SelectOption> _makeOptions(String filter, List<SelectOption> allOptions) {
     final List<SelectOption> options = List.from(allOptions);
-    options.retainWhere((option) => option.name.contains(filter));
+    if (filter.isNotEmpty) {
+      options.retainWhere((option) => option.name.toLowerCase().contains(filter.toLowerCase()));
+    }
+
     return options;
   }
 

+ 142 - 0
frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_format_bloc.dart

@@ -0,0 +1,142 @@
+import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+import 'dart:async';
+part 'number_format_bloc.freezed.dart';
+
+class NumberFormatBloc extends Bloc<NumberFormatEvent, NumberFormatState> {
+  NumberFormatBloc() : super(NumberFormatState.initial()) {
+    on<NumberFormatEvent>(
+      (event, emit) async {
+        event.map(setFilter: (_SetFilter value) {
+          final List<NumberFormat> formats = List.from(NumberFormat.values);
+          if (value.filter.isNotEmpty) {
+            formats.retainWhere((element) => element.title().toLowerCase().contains(value.filter.toLowerCase()));
+          }
+          emit(state.copyWith(formats: formats, filter: value.filter));
+        });
+      },
+    );
+  }
+
+  @override
+  Future<void> close() async {
+    return super.close();
+  }
+}
+
+@freezed
+class NumberFormatEvent with _$NumberFormatEvent {
+  const factory NumberFormatEvent.setFilter(String filter) = _SetFilter;
+}
+
+@freezed
+class NumberFormatState with _$NumberFormatState {
+  const factory NumberFormatState({
+    required List<NumberFormat> formats,
+    required String filter,
+  }) = _NumberFormatState;
+
+  factory NumberFormatState.initial() {
+    return const NumberFormatState(
+      formats: NumberFormat.values,
+      filter: "",
+    );
+  }
+}
+
+extension NumberFormatExtension on NumberFormat {
+  String title() {
+    switch (this) {
+      case NumberFormat.ArgentinePeso:
+        return "Argentine peso";
+      case NumberFormat.Baht:
+        return "Baht";
+      case NumberFormat.CanadianDollar:
+        return "Canadian dollar";
+      case NumberFormat.ChileanPeso:
+        return "Chilean peso";
+      case NumberFormat.ColombianPeso:
+        return "Colombian peso";
+      case NumberFormat.DanishKrone:
+        return "Danish krone";
+      case NumberFormat.Dirham:
+        return "Dirham";
+      case NumberFormat.EUR:
+        return "Euro";
+      case NumberFormat.Forint:
+        return "Forint";
+      case NumberFormat.Franc:
+        return "Franc";
+      case NumberFormat.HongKongDollar:
+        return "Hone Kong dollar";
+      case NumberFormat.Koruna:
+        return "Koruna";
+      case NumberFormat.Krona:
+        return "Krona";
+      case NumberFormat.Leu:
+        return "Leu";
+      case NumberFormat.Lira:
+        return "Lira";
+      case NumberFormat.MexicanPeso:
+        return "Mexican Peso";
+      case NumberFormat.NewTaiwanDollar:
+        return "New Taiwan dollar";
+      case NumberFormat.NewZealandDollar:
+        return "New Zealand dollar";
+      case NumberFormat.NorwegianKrone:
+        return "Norwegian krone";
+      case NumberFormat.Number:
+        return "Number";
+      case NumberFormat.Percent:
+        return "Percent";
+      case NumberFormat.PhilippinePeso:
+        return "Percent";
+      case NumberFormat.Pound:
+        return "Pound";
+      case NumberFormat.Rand:
+        return "Rand";
+      case NumberFormat.Real:
+        return "Real";
+      case NumberFormat.Ringgit:
+        return "Ringgit";
+      case NumberFormat.Riyal:
+        return "Riyal";
+      case NumberFormat.Ruble:
+        return "Ruble";
+      case NumberFormat.Rupee:
+        return "Rupee";
+      case NumberFormat.Rupiah:
+        return "Rupiah";
+      case NumberFormat.Shekel:
+        return "Skekel";
+      case NumberFormat.USD:
+        return "US Dollar";
+      case NumberFormat.UruguayanPeso:
+        return "Uruguayan peso";
+      case NumberFormat.Won:
+        return "Uruguayan peso";
+      case NumberFormat.Yen:
+        return "Yen";
+      case NumberFormat.Yuan:
+        return "Yuan";
+      default:
+        throw UnimplementedError;
+    }
+  }
+
+  // String iconName() {
+  //   switch (this) {
+  //     case NumberFormat.CNY:
+  //       return "grid/field/yen";
+  //     case NumberFormat.EUR:
+  //       return "grid/field/euro";
+  //     case NumberFormat.Number:
+  //       return "grid/field/numbers";
+  //     case NumberFormat.USD:
+  //       return "grid/field/us_dollar";
+  //     default:
+  //       throw UnimplementedError;
+  //   }
+  // }
+}

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart

@@ -12,7 +12,7 @@ class GridSize {
   static double get cellHPadding => 10 * scale;
   static double get cellVPadding => 10 * scale;
   static double get typeOptionItemHeight => 32 * scale;
-  static double get typeOptionSeparatorHeight => 6 * scale;
+  static double get typeOptionSeparatorHeight => 4 * scale;
 
   //
   static EdgeInsets get headerContentInsets => EdgeInsets.symmetric(

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart

@@ -3,7 +3,7 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
 import 'package:app_flowy/workspace/application/grid/cell/selection_editor_bloc.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart';
-import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart';
+import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';

+ 22 - 11
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart → frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart

@@ -3,23 +3,25 @@ import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-class NameTextField extends StatefulWidget {
-  final void Function(String) onDone;
+class InputTextField extends StatefulWidget {
+  final void Function(String)? onDone;
+  final void Function(String)? onChanged;
   final void Function() onCanceled;
-  final String name;
+  final String text;
 
-  const NameTextField({
-    required this.name,
-    required this.onDone,
+  const InputTextField({
+    required this.text,
+    this.onDone,
     required this.onCanceled,
+    this.onChanged,
     Key? key,
   }) : super(key: key);
 
   @override
-  State<NameTextField> createState() => _NameTextFieldState();
+  State<InputTextField> createState() => _InputTextFieldState();
 }
 
-class _NameTextFieldState extends State<NameTextField> {
+class _InputTextFieldState extends State<InputTextField> {
   late FocusNode _focusNode;
   var isEdited = false;
   late TextEditingController _controller;
@@ -27,7 +29,7 @@ class _NameTextFieldState extends State<NameTextField> {
   @override
   void initState() {
     _focusNode = FocusNode();
-    _controller = TextEditingController(text: widget.name);
+    _controller = TextEditingController(text: widget.text);
 
     _focusNode.addListener(notifyDidEndEditing);
     super.initState();
@@ -46,8 +48,15 @@ class _NameTextFieldState extends State<NameTextField> {
       normalBorderColor: theme.shader4,
       focusBorderColor: theme.main1,
       cursorColor: theme.main1,
+      onChanged: (text) {
+        if (widget.onChanged != null) {
+          widget.onChanged!(text);
+        }
+      },
       onEditingComplete: () {
-        widget.onDone(_controller.text);
+        if (widget.onDone != null) {
+          widget.onDone!(_controller.text);
+        }
       },
     );
   }
@@ -64,7 +73,9 @@ class _NameTextFieldState extends State<NameTextField> {
       if (_controller.text.isEmpty) {
         widget.onCanceled();
       } else {
-        widget.onDone(_controller.text);
+        if (widget.onDone != null) {
+          widget.onDone!(_controller.text);
+        }
       }
     }
   }

+ 4 - 2
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart

@@ -6,6 +6,7 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
+import 'package:flowy_sdk/log.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field;
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
@@ -29,11 +30,12 @@ class FieldEditor extends FlowyOverlayDelegate {
     BuildContext context, {
     AnchorDirection anchorDirection = AnchorDirection.bottomWithLeftAligned,
   }) {
+    Log.trace("Show $identifier()");
     FlowyOverlay.of(context).remove(identifier());
     FlowyOverlay.of(context).insertWithAnchor(
       widget: OverlayContainer(
         child: _FieldEditorWidget(_fieldEditorBloc, fieldContextLoader),
-        constraints: BoxConstraints.loose(const Size(220, 400)),
+        constraints: BoxConstraints.loose(const Size(280, 400)),
       ),
       identifier: identifier(),
       anchorContext: context,
@@ -68,7 +70,7 @@ class _FieldEditorWidget extends StatelessWidget {
       child: BlocBuilder<FieldEditorBloc, FieldEditorState>(
         builder: (context, state) {
           return state.field.fold(
-            () => const SizedBox(width: 200),
+            () => const SizedBox(),
             (field) => ListView(
               shrinkWrap: true,
               children: [

+ 1 - 3
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart

@@ -14,13 +14,11 @@ import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pbserver.dart
 import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
-
 import 'package:app_flowy/startup/startup.dart';
 import 'package:app_flowy/workspace/application/grid/prelude.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart';
-
 import 'field_type_extension.dart';
 import 'type_option/multi_select.dart';
 import 'type_option/number.dart';
@@ -146,7 +144,7 @@ class _FieldSwitcherState extends State<FieldSwitcher> {
     FlowyOverlay.of(context).insertWithAnchor(
       widget: OverlayContainer(
         child: child,
-        constraints: BoxConstraints.loose(const Size(340, 400)),
+        constraints: BoxConstraints.loose(const Size(460, 440)),
       ),
       identifier: identifier,
       anchorContext: context,

+ 3 - 3
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart

@@ -1,7 +1,7 @@
 import 'package:app_flowy/workspace/application/grid/field/type_option/edit_select_option_bloc.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/extension.dart';
-import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart';
+import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
@@ -95,8 +95,8 @@ class _OptionNameTextField extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return NameTextField(
-      name: name,
+    return InputTextField(
+      text: name,
       onCanceled: () {},
       onDone: (optionName) {
         if (name != optionName) {

+ 3 - 3
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/field_option_pannel.dart

@@ -1,5 +1,6 @@
 import 'package:app_flowy/workspace/application/grid/field/type_option/field_option_pannel_bloc.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
+import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
@@ -13,7 +14,6 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:app_flowy/generated/locale_keys.g.dart';
 
 import 'edit_option_pannel.dart';
-import 'widget.dart';
 
 class FieldSelectOptionPannel extends StatelessWidget {
   final List<SelectOption> options;
@@ -222,8 +222,8 @@ class _OptionNameTextField extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return NameTextField(
-      name: "",
+    return InputTextField(
+      text: "",
       onCanceled: () {
         context.read<FieldOptionPannelBloc>().add(const FieldOptionPannelEvent.endAddingOption());
       },

+ 81 - 57
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart

@@ -1,6 +1,8 @@
 import 'package:app_flowy/startup/startup.dart';
 import 'package:app_flowy/workspace/application/grid/field/type_option/number_bloc.dart';
+import 'package:app_flowy/workspace/application/grid/field/type_option/number_format_bloc.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
+import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
@@ -50,14 +52,27 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
           listener: (context, state) => dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()),
           builder: (context, state) {
             return FlowyButton(
-              text: FlowyText.medium(LocaleKeys.grid_field_numberFormat.tr(), fontSize: 12),
+              text: Row(
+                children: [
+                  FlowyText.medium(LocaleKeys.grid_field_numberFormat.tr(), fontSize: 12),
+                  // const HSpace(6),
+                  const Spacer(),
+                  FlowyText.regular(state.typeOption.format.title(), fontSize: 12),
+                ],
+              ),
               padding: GridSize.typeOptionContentInsets,
               hoverColor: theme.hover,
               onTap: () {
-                final list = NumberFormatList(onSelected: (format) {
-                  context.read<NumberTypeOptionBloc>().add(NumberTypeOptionEvent.didSelectFormat(format));
-                });
-                overlayDelegate.showOverlay(context, list);
+                final list = NumberFormatList(
+                  onSelected: (format) {
+                    context.read<NumberTypeOptionBloc>().add(NumberTypeOptionEvent.didSelectFormat(format));
+                  },
+                  selectedFormat: state.typeOption.format,
+                );
+                overlayDelegate.showOverlay(
+                  context,
+                  list,
+                );
               },
               rightIcon: svgWidget("grid/more", color: theme.iconColor),
             );
@@ -72,31 +87,47 @@ typedef _SelectNumberFormatCallback = Function(NumberFormat format);
 
 class NumberFormatList extends StatelessWidget {
   final _SelectNumberFormatCallback onSelected;
-  const NumberFormatList({required this.onSelected, Key? key}) : super(key: key);
+  final NumberFormat selectedFormat;
+  const NumberFormatList({required this.selectedFormat, required this.onSelected, Key? key}) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
-    final cells = NumberFormat.values.map((format) {
-      return NumberFormatCell(
-          format: format,
-          onSelected: (format) {
-            onSelected(format);
-            FlowyOverlay.of(context).remove(NumberFormatList.identifier());
-          });
-    }).toList();
+    return BlocProvider(
+      create: (context) => NumberFormatBloc(),
+      child: SizedBox(
+        width: 180,
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            const _FilterTextField(),
+            BlocBuilder<NumberFormatBloc, NumberFormatState>(
+              builder: (context, state) {
+                final cells = state.formats.map((format) {
+                  return NumberFormatCell(
+                      isSelected: format == selectedFormat,
+                      format: format,
+                      onSelected: (format) {
+                        onSelected(format);
+                        FlowyOverlay.of(context).remove(NumberFormatList.identifier());
+                      });
+                }).toList();
 
-    return SizedBox(
-      width: 120,
-      child: ListView.separated(
-        shrinkWrap: true,
-        controller: ScrollController(),
-        separatorBuilder: (context, index) {
-          return VSpace(GridSize.typeOptionSeparatorHeight);
-        },
-        itemCount: cells.length,
-        itemBuilder: (BuildContext context, int index) {
-          return cells[index];
-        },
+                final list = ListView.separated(
+                  shrinkWrap: true,
+                  controller: ScrollController(),
+                  separatorBuilder: (context, index) {
+                    return VSpace(GridSize.typeOptionSeparatorHeight);
+                  },
+                  itemCount: cells.length,
+                  itemBuilder: (BuildContext context, int index) {
+                    return cells[index];
+                  },
+                );
+                return Expanded(child: list);
+              },
+            ),
+          ],
+        ),
       ),
     );
   }
@@ -108,52 +139,45 @@ class NumberFormatList extends StatelessWidget {
 
 class NumberFormatCell extends StatelessWidget {
   final NumberFormat format;
+  final bool isSelected;
   final Function(NumberFormat format) onSelected;
-  const NumberFormatCell({required this.format, required this.onSelected, Key? key}) : super(key: key);
+  const NumberFormatCell({
+    required this.isSelected,
+    required this.format,
+    required this.onSelected,
+    Key? key,
+  }) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
+    Widget? checkmark;
+    if (isSelected) {
+      checkmark = svgWidget("grid/checkmark");
+    }
+
     return SizedBox(
       height: GridSize.typeOptionItemHeight,
       child: FlowyButton(
         text: FlowyText.medium(format.title(), fontSize: 12),
         hoverColor: theme.hover,
         onTap: () => onSelected(format),
-        leftIcon: svgWidget(format.iconName(), color: theme.iconColor),
+        rightIcon: checkmark,
       ),
     );
   }
 }
 
-extension NumberFormatExtension on NumberFormat {
-  String title() {
-    switch (this) {
-      case NumberFormat.CNY:
-        return "Yen";
-      case NumberFormat.EUR:
-        return "Euro";
-      case NumberFormat.Number:
-        return "Numbers";
-      case NumberFormat.USD:
-        return "US Dollar";
-      default:
-        throw UnimplementedError;
-    }
-  }
-
-  String iconName() {
-    switch (this) {
-      case NumberFormat.CNY:
-        return "grid/field/yen";
-      case NumberFormat.EUR:
-        return "grid/field/euro";
-      case NumberFormat.Number:
-        return "grid/field/numbers";
-      case NumberFormat.USD:
-        return "grid/field/us_dollar";
-      default:
-        throw UnimplementedError;
-    }
+class _FilterTextField extends StatelessWidget {
+  const _FilterTextField({Key? key}) : super(key: key);
+  @override
+  Widget build(BuildContext context) {
+    return InputTextField(
+      text: "",
+      onCanceled: () {},
+      onChanged: (text) {
+        context.read<NumberFormatBloc>().add(NumberFormatEvent.setFilter(text));
+      },
+    );
   }
 }

+ 1 - 0
frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/flowy_overlay.dart

@@ -176,6 +176,7 @@ class FlowyOverlayState extends State<FlowyOverlay> {
     FlowyOverlayStyle? style,
     Offset? anchorOffset,
   }) {
+    debugPrint("Show overlay: $identifier");
     this.style = style ?? FlowyOverlayStyle();
 
     _showOverlay(

+ 67 - 3
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbenum.dart

@@ -12,14 +12,78 @@ import 'package:protobuf/protobuf.dart' as $pb;
 class NumberFormat extends $pb.ProtobufEnum {
   static const NumberFormat Number = NumberFormat._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Number');
   static const NumberFormat USD = NumberFormat._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'USD');
-  static const NumberFormat CNY = NumberFormat._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CNY');
-  static const NumberFormat EUR = NumberFormat._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EUR');
+  static const NumberFormat CanadianDollar = NumberFormat._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CanadianDollar');
+  static const NumberFormat EUR = NumberFormat._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EUR');
+  static const NumberFormat Pound = NumberFormat._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Pound');
+  static const NumberFormat Yen = NumberFormat._(6, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Yen');
+  static const NumberFormat Ruble = NumberFormat._(7, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Ruble');
+  static const NumberFormat Rupee = NumberFormat._(8, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Rupee');
+  static const NumberFormat Won = NumberFormat._(9, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Won');
+  static const NumberFormat Yuan = NumberFormat._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Yuan');
+  static const NumberFormat Real = NumberFormat._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Real');
+  static const NumberFormat Lira = NumberFormat._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Lira');
+  static const NumberFormat Rupiah = NumberFormat._(13, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Rupiah');
+  static const NumberFormat Franc = NumberFormat._(14, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Franc');
+  static const NumberFormat HongKongDollar = NumberFormat._(15, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'HongKongDollar');
+  static const NumberFormat NewZealandDollar = NumberFormat._(16, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'NewZealandDollar');
+  static const NumberFormat Krona = NumberFormat._(17, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Krona');
+  static const NumberFormat NorwegianKrone = NumberFormat._(18, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'NorwegianKrone');
+  static const NumberFormat MexicanPeso = NumberFormat._(19, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MexicanPeso');
+  static const NumberFormat Rand = NumberFormat._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Rand');
+  static const NumberFormat NewTaiwanDollar = NumberFormat._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'NewTaiwanDollar');
+  static const NumberFormat DanishKrone = NumberFormat._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DanishKrone');
+  static const NumberFormat Baht = NumberFormat._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Baht');
+  static const NumberFormat Forint = NumberFormat._(24, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Forint');
+  static const NumberFormat Koruna = NumberFormat._(25, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Koruna');
+  static const NumberFormat Shekel = NumberFormat._(26, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Shekel');
+  static const NumberFormat ChileanPeso = NumberFormat._(27, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ChileanPeso');
+  static const NumberFormat PhilippinePeso = NumberFormat._(28, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PhilippinePeso');
+  static const NumberFormat Dirham = NumberFormat._(29, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Dirham');
+  static const NumberFormat ColombianPeso = NumberFormat._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ColombianPeso');
+  static const NumberFormat Riyal = NumberFormat._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Riyal');
+  static const NumberFormat Ringgit = NumberFormat._(32, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Ringgit');
+  static const NumberFormat Leu = NumberFormat._(33, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Leu');
+  static const NumberFormat ArgentinePeso = NumberFormat._(34, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ArgentinePeso');
+  static const NumberFormat UruguayanPeso = NumberFormat._(35, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UruguayanPeso');
+  static const NumberFormat Percent = NumberFormat._(36, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Percent');
 
   static const $core.List<NumberFormat> values = <NumberFormat> [
     Number,
     USD,
-    CNY,
+    CanadianDollar,
     EUR,
+    Pound,
+    Yen,
+    Ruble,
+    Rupee,
+    Won,
+    Yuan,
+    Real,
+    Lira,
+    Rupiah,
+    Franc,
+    HongKongDollar,
+    NewZealandDollar,
+    Krona,
+    NorwegianKrone,
+    MexicanPeso,
+    Rand,
+    NewTaiwanDollar,
+    DanishKrone,
+    Baht,
+    Forint,
+    Koruna,
+    Shekel,
+    ChileanPeso,
+    PhilippinePeso,
+    Dirham,
+    ColombianPeso,
+    Riyal,
+    Ringgit,
+    Leu,
+    ArgentinePeso,
+    UruguayanPeso,
+    Percent,
   ];
 
   static final $core.Map<$core.int, NumberFormat> _byValue = $pb.ProtobufEnum.initByValue(values);

+ 35 - 3
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbjson.dart

@@ -14,13 +14,45 @@ const NumberFormat$json = const {
   '2': const [
     const {'1': 'Number', '2': 0},
     const {'1': 'USD', '2': 1},
-    const {'1': 'CNY', '2': 2},
-    const {'1': 'EUR', '2': 3},
+    const {'1': 'CanadianDollar', '2': 2},
+    const {'1': 'EUR', '2': 4},
+    const {'1': 'Pound', '2': 5},
+    const {'1': 'Yen', '2': 6},
+    const {'1': 'Ruble', '2': 7},
+    const {'1': 'Rupee', '2': 8},
+    const {'1': 'Won', '2': 9},
+    const {'1': 'Yuan', '2': 10},
+    const {'1': 'Real', '2': 11},
+    const {'1': 'Lira', '2': 12},
+    const {'1': 'Rupiah', '2': 13},
+    const {'1': 'Franc', '2': 14},
+    const {'1': 'HongKongDollar', '2': 15},
+    const {'1': 'NewZealandDollar', '2': 16},
+    const {'1': 'Krona', '2': 17},
+    const {'1': 'NorwegianKrone', '2': 18},
+    const {'1': 'MexicanPeso', '2': 19},
+    const {'1': 'Rand', '2': 20},
+    const {'1': 'NewTaiwanDollar', '2': 21},
+    const {'1': 'DanishKrone', '2': 22},
+    const {'1': 'Baht', '2': 23},
+    const {'1': 'Forint', '2': 24},
+    const {'1': 'Koruna', '2': 25},
+    const {'1': 'Shekel', '2': 26},
+    const {'1': 'ChileanPeso', '2': 27},
+    const {'1': 'PhilippinePeso', '2': 28},
+    const {'1': 'Dirham', '2': 29},
+    const {'1': 'ColombianPeso', '2': 30},
+    const {'1': 'Riyal', '2': 31},
+    const {'1': 'Ringgit', '2': 32},
+    const {'1': 'Leu', '2': 33},
+    const {'1': 'ArgentinePeso', '2': 34},
+    const {'1': 'UruguayanPeso', '2': 35},
+    const {'1': 'Percent', '2': 36},
   ],
 };
 
 /// Descriptor for `NumberFormat`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List numberFormatDescriptor = $convert.base64Decode('CgxOdW1iZXJGb3JtYXQSCgoGTnVtYmVyEAASBwoDVVNEEAESBwoDQ05ZEAISBwoDRVVSEAM=');
+final $typed_data.Uint8List numberFormatDescriptor = $convert.base64Decode('CgxOdW1iZXJGb3JtYXQSCgoGTnVtYmVyEAASBwoDVVNEEAESEgoOQ2FuYWRpYW5Eb2xsYXIQAhIHCgNFVVIQBBIJCgVQb3VuZBAFEgcKA1llbhAGEgkKBVJ1YmxlEAcSCQoFUnVwZWUQCBIHCgNXb24QCRIICgRZdWFuEAoSCAoEUmVhbBALEggKBExpcmEQDBIKCgZSdXBpYWgQDRIJCgVGcmFuYxAOEhIKDkhvbmdLb25nRG9sbGFyEA8SFAoQTmV3WmVhbGFuZERvbGxhchAQEgkKBUtyb25hEBESEgoOTm9yd2VnaWFuS3JvbmUQEhIPCgtNZXhpY2FuUGVzbxATEggKBFJhbmQQFBITCg9OZXdUYWl3YW5Eb2xsYXIQFRIPCgtEYW5pc2hLcm9uZRAWEggKBEJhaHQQFxIKCgZGb3JpbnQQGBIKCgZLb3J1bmEQGRIKCgZTaGVrZWwQGhIPCgtDaGlsZWFuUGVzbxAbEhIKDlBoaWxpcHBpbmVQZXNvEBwSCgoGRGlyaGFtEB0SEQoNQ29sb21iaWFuUGVzbxAeEgkKBVJpeWFsEB8SCwoHUmluZ2dpdBAgEgcKA0xldRAhEhEKDUFyZ2VudGluZVBlc28QIhIRCg1VcnVndWF5YW5QZXNvECMSCwoHUGVyY2VudBAk');
 @$core.Deprecated('Use numberTypeOptionDescriptor instead')
 const NumberTypeOption$json = const {
   '1': 'NumberTypeOption',

+ 117 - 8
frontend/rust-lib/flowy-grid/src/protobuf/model/number_type_option.rs

@@ -329,8 +329,40 @@ impl ::protobuf::reflect::ProtobufValue for NumberTypeOption {
 pub enum NumberFormat {
     Number = 0,
     USD = 1,
-    CNY = 2,
-    EUR = 3,
+    CanadianDollar = 2,
+    EUR = 4,
+    Pound = 5,
+    Yen = 6,
+    Ruble = 7,
+    Rupee = 8,
+    Won = 9,
+    Yuan = 10,
+    Real = 11,
+    Lira = 12,
+    Rupiah = 13,
+    Franc = 14,
+    HongKongDollar = 15,
+    NewZealandDollar = 16,
+    Krona = 17,
+    NorwegianKrone = 18,
+    MexicanPeso = 19,
+    Rand = 20,
+    NewTaiwanDollar = 21,
+    DanishKrone = 22,
+    Baht = 23,
+    Forint = 24,
+    Koruna = 25,
+    Shekel = 26,
+    ChileanPeso = 27,
+    PhilippinePeso = 28,
+    Dirham = 29,
+    ColombianPeso = 30,
+    Riyal = 31,
+    Ringgit = 32,
+    Leu = 33,
+    ArgentinePeso = 34,
+    UruguayanPeso = 35,
+    Percent = 36,
 }
 
 impl ::protobuf::ProtobufEnum for NumberFormat {
@@ -342,8 +374,40 @@ impl ::protobuf::ProtobufEnum for NumberFormat {
         match value {
             0 => ::std::option::Option::Some(NumberFormat::Number),
             1 => ::std::option::Option::Some(NumberFormat::USD),
-            2 => ::std::option::Option::Some(NumberFormat::CNY),
-            3 => ::std::option::Option::Some(NumberFormat::EUR),
+            2 => ::std::option::Option::Some(NumberFormat::CanadianDollar),
+            4 => ::std::option::Option::Some(NumberFormat::EUR),
+            5 => ::std::option::Option::Some(NumberFormat::Pound),
+            6 => ::std::option::Option::Some(NumberFormat::Yen),
+            7 => ::std::option::Option::Some(NumberFormat::Ruble),
+            8 => ::std::option::Option::Some(NumberFormat::Rupee),
+            9 => ::std::option::Option::Some(NumberFormat::Won),
+            10 => ::std::option::Option::Some(NumberFormat::Yuan),
+            11 => ::std::option::Option::Some(NumberFormat::Real),
+            12 => ::std::option::Option::Some(NumberFormat::Lira),
+            13 => ::std::option::Option::Some(NumberFormat::Rupiah),
+            14 => ::std::option::Option::Some(NumberFormat::Franc),
+            15 => ::std::option::Option::Some(NumberFormat::HongKongDollar),
+            16 => ::std::option::Option::Some(NumberFormat::NewZealandDollar),
+            17 => ::std::option::Option::Some(NumberFormat::Krona),
+            18 => ::std::option::Option::Some(NumberFormat::NorwegianKrone),
+            19 => ::std::option::Option::Some(NumberFormat::MexicanPeso),
+            20 => ::std::option::Option::Some(NumberFormat::Rand),
+            21 => ::std::option::Option::Some(NumberFormat::NewTaiwanDollar),
+            22 => ::std::option::Option::Some(NumberFormat::DanishKrone),
+            23 => ::std::option::Option::Some(NumberFormat::Baht),
+            24 => ::std::option::Option::Some(NumberFormat::Forint),
+            25 => ::std::option::Option::Some(NumberFormat::Koruna),
+            26 => ::std::option::Option::Some(NumberFormat::Shekel),
+            27 => ::std::option::Option::Some(NumberFormat::ChileanPeso),
+            28 => ::std::option::Option::Some(NumberFormat::PhilippinePeso),
+            29 => ::std::option::Option::Some(NumberFormat::Dirham),
+            30 => ::std::option::Option::Some(NumberFormat::ColombianPeso),
+            31 => ::std::option::Option::Some(NumberFormat::Riyal),
+            32 => ::std::option::Option::Some(NumberFormat::Ringgit),
+            33 => ::std::option::Option::Some(NumberFormat::Leu),
+            34 => ::std::option::Option::Some(NumberFormat::ArgentinePeso),
+            35 => ::std::option::Option::Some(NumberFormat::UruguayanPeso),
+            36 => ::std::option::Option::Some(NumberFormat::Percent),
             _ => ::std::option::Option::None
         }
     }
@@ -352,8 +416,40 @@ impl ::protobuf::ProtobufEnum for NumberFormat {
         static values: &'static [NumberFormat] = &[
             NumberFormat::Number,
             NumberFormat::USD,
-            NumberFormat::CNY,
+            NumberFormat::CanadianDollar,
             NumberFormat::EUR,
+            NumberFormat::Pound,
+            NumberFormat::Yen,
+            NumberFormat::Ruble,
+            NumberFormat::Rupee,
+            NumberFormat::Won,
+            NumberFormat::Yuan,
+            NumberFormat::Real,
+            NumberFormat::Lira,
+            NumberFormat::Rupiah,
+            NumberFormat::Franc,
+            NumberFormat::HongKongDollar,
+            NumberFormat::NewZealandDollar,
+            NumberFormat::Krona,
+            NumberFormat::NorwegianKrone,
+            NumberFormat::MexicanPeso,
+            NumberFormat::Rand,
+            NumberFormat::NewTaiwanDollar,
+            NumberFormat::DanishKrone,
+            NumberFormat::Baht,
+            NumberFormat::Forint,
+            NumberFormat::Koruna,
+            NumberFormat::Shekel,
+            NumberFormat::ChileanPeso,
+            NumberFormat::PhilippinePeso,
+            NumberFormat::Dirham,
+            NumberFormat::ColombianPeso,
+            NumberFormat::Riyal,
+            NumberFormat::Ringgit,
+            NumberFormat::Leu,
+            NumberFormat::ArgentinePeso,
+            NumberFormat::UruguayanPeso,
+            NumberFormat::Percent,
         ];
         values
     }
@@ -386,9 +482,22 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \x06format\x18\x01\x20\x01(\x0e2\r.NumberFormatR\x06format\x12\x14\n\x05\
     scale\x18\x02\x20\x01(\rR\x05scale\x12\x16\n\x06symbol\x18\x03\x20\x01(\
     \tR\x06symbol\x12#\n\rsign_positive\x18\x04\x20\x01(\x08R\x0csignPositiv\
-    e\x12\x12\n\x04name\x18\x05\x20\x01(\tR\x04name*5\n\x0cNumberFormat\x12\
-    \n\n\x06Number\x10\0\x12\x07\n\x03USD\x10\x01\x12\x07\n\x03CNY\x10\x02\
-    \x12\x07\n\x03EUR\x10\x03b\x06proto3\
+    e\x12\x12\n\x04name\x18\x05\x20\x01(\tR\x04name*\xf8\x03\n\x0cNumberForm\
+    at\x12\n\n\x06Number\x10\0\x12\x07\n\x03USD\x10\x01\x12\x12\n\x0eCanadia\
+    nDollar\x10\x02\x12\x07\n\x03EUR\x10\x04\x12\t\n\x05Pound\x10\x05\x12\
+    \x07\n\x03Yen\x10\x06\x12\t\n\x05Ruble\x10\x07\x12\t\n\x05Rupee\x10\x08\
+    \x12\x07\n\x03Won\x10\t\x12\x08\n\x04Yuan\x10\n\x12\x08\n\x04Real\x10\
+    \x0b\x12\x08\n\x04Lira\x10\x0c\x12\n\n\x06Rupiah\x10\r\x12\t\n\x05Franc\
+    \x10\x0e\x12\x12\n\x0eHongKongDollar\x10\x0f\x12\x14\n\x10NewZealandDoll\
+    ar\x10\x10\x12\t\n\x05Krona\x10\x11\x12\x12\n\x0eNorwegianKrone\x10\x12\
+    \x12\x0f\n\x0bMexicanPeso\x10\x13\x12\x08\n\x04Rand\x10\x14\x12\x13\n\
+    \x0fNewTaiwanDollar\x10\x15\x12\x0f\n\x0bDanishKrone\x10\x16\x12\x08\n\
+    \x04Baht\x10\x17\x12\n\n\x06Forint\x10\x18\x12\n\n\x06Koruna\x10\x19\x12\
+    \n\n\x06Shekel\x10\x1a\x12\x0f\n\x0bChileanPeso\x10\x1b\x12\x12\n\x0ePhi\
+    lippinePeso\x10\x1c\x12\n\n\x06Dirham\x10\x1d\x12\x11\n\rColombianPeso\
+    \x10\x1e\x12\t\n\x05Riyal\x10\x1f\x12\x0b\n\x07Ringgit\x10\x20\x12\x07\n\
+    \x03Leu\x10!\x12\x11\n\rArgentinePeso\x10\"\x12\x11\n\rUruguayanPeso\x10\
+    #\x12\x0b\n\x07Percent\x10$b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 34 - 2
frontend/rust-lib/flowy-grid/src/protobuf/proto/number_type_option.proto

@@ -10,6 +10,38 @@ message NumberTypeOption {
 enum NumberFormat {
     Number = 0;
     USD = 1;
-    CNY = 2;
-    EUR = 3;
+    CanadianDollar = 2;
+    EUR = 4;
+    Pound = 5;
+    Yen = 6;
+    Ruble = 7;
+    Rupee = 8;
+    Won = 9;
+    Yuan = 10;
+    Real = 11;
+    Lira = 12;
+    Rupiah = 13;
+    Franc = 14;
+    HongKongDollar = 15;
+    NewZealandDollar = 16;
+    Krona = 17;
+    NorwegianKrone = 18;
+    MexicanPeso = 19;
+    Rand = 20;
+    NewTaiwanDollar = 21;
+    DanishKrone = 22;
+    Baht = 23;
+    Forint = 24;
+    Koruna = 25;
+    Shekel = 26;
+    ChileanPeso = 27;
+    PhilippinePeso = 28;
+    Dirham = 29;
+    ColombianPeso = 30;
+    Riyal = 31;
+    Ringgit = 32;
+    Leu = 33;
+    ArgentinePeso = 34;
+    UruguayanPeso = 35;
+    Percent = 36;
 }

+ 435 - 38
frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs

@@ -1,19 +1,16 @@
 use crate::impl_type_option;
+use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
 use crate::services::row::{CellDataChangeset, CellDataOperation, TypeOptionCellData};
+use bytes::Bytes;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::FlowyError;
 use flowy_grid_data_model::entities::{
     CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry,
 };
-
 use lazy_static::lazy_static;
-
 use rust_decimal::Decimal;
-use rusty_money::iso::{Currency, CNY, EUR, USD};
+use rusty_money::define_currency_set;
 use serde::{Deserialize, Serialize};
-
-use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use bytes::Bytes;
 use std::str::FromStr;
 use strum::IntoEnumIterator;
 use strum_macros::EnumIter;
@@ -88,16 +85,9 @@ impl CellDataOperation for NumberTypeOption {
 
             let cell_data = type_option_cell_data.data;
             match self.format {
-                NumberFormat::Number => {
-                    if cell_data.parse::<i64>().is_ok() {
-                        cell_data
-                    } else {
-                        String::new()
-                    }
-                }
-                NumberFormat::USD => self.money_from_str(&cell_data, USD),
-                NumberFormat::CNY => self.money_from_str(&cell_data, CNY),
-                NumberFormat::EUR => self.money_from_str(&cell_data, EUR),
+                NumberFormat::Number => cell_data.parse::<i64>().map_or(String::new(), |v| v.to_string()),
+                NumberFormat::Percent => cell_data.parse::<f64>().map_or(String::new(), |v| v.to_string()),
+                _ => self.money_from_str(&cell_data),
             }
         } else {
             String::new()
@@ -140,7 +130,7 @@ impl NumberTypeOption {
         self.symbol = format.symbol();
     }
 
-    fn money_from_str(&self, s: &str, currency: &'static Currency) -> String {
+    fn money_from_str(&self, s: &str) -> String {
         match Decimal::from_str(s) {
             Ok(mut decimal) => {
                 match decimal.set_scale(self.scale) {
@@ -149,8 +139,9 @@ impl NumberTypeOption {
                         tracing::error!("Set decimal scale failed: {:?}", e);
                     }
                 }
+
                 decimal.set_sign_positive(self.sign_positive);
-                let money = rusty_money::Money::from_decimal(decimal, currency);
+                let money = rusty_money::Money::from_decimal(decimal, self.format.currency());
                 money.to_string()
             }
             Err(_) => String::new(),
@@ -170,8 +161,40 @@ impl NumberTypeOption {
 pub enum NumberFormat {
     Number = 0,
     USD = 1,
-    CNY = 2,
-    EUR = 3,
+    CanadianDollar = 2,
+    EUR = 4,
+    Pound = 5,
+    Yen = 6,
+    Ruble = 7,
+    Rupee = 8,
+    Won = 9,
+    Yuan = 10,
+    Real = 11,
+    Lira = 12,
+    Rupiah = 13,
+    Franc = 14,
+    HongKongDollar = 15,
+    NewZealandDollar = 16,
+    Krona = 17,
+    NorwegianKrone = 18,
+    MexicanPeso = 19,
+    Rand = 20,
+    NewTaiwanDollar = 21,
+    DanishKrone = 22,
+    Baht = 23,
+    Forint = 24,
+    Koruna = 25,
+    Shekel = 26,
+    ChileanPeso = 27,
+    PhilippinePeso = 28,
+    Dirham = 29,
+    ColombianPeso = 30,
+    Riyal = 31,
+    Ringgit = 32,
+    Leu = 33,
+    ArgentinePeso = 34,
+    UruguayanPeso = 35,
+    Percent = 36,
 }
 
 impl std::default::Default for NumberFormat {
@@ -180,24 +203,389 @@ impl std::default::Default for NumberFormat {
     }
 }
 
-impl NumberFormat {
-    pub fn symbol(&self) -> String {
-        match self {
-            NumberFormat::Number => "".to_string(),
-            NumberFormat::USD => USD.symbol.to_string(),
-            NumberFormat::CNY => CNY.symbol.to_string(),
-            NumberFormat::EUR => EUR.symbol.to_string(),
+define_currency_set!(
+    number_currency {
+        NUMBER : {
+            code: "",
+            exponent: 2,
+            locale: EnEu,
+            minor_units: 1,
+            name: "number",
+            symbol: "RUB",
+            symbol_first: false,
+        },
+        USD : {
+            code: "USD",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 1,
+            name: "United States Dollar",
+            symbol: "$",
+            symbol_first: true,
+        },
+        CANADIAN_DOLLAR : {
+            code: "USD",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 1,
+            name: "Canadian Dollar",
+            symbol: "CA$",
+            symbol_first: true,
+        },
+         NEW_TAIWAN_DOLLAR : {
+            code: "USD",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 1,
+            name: "NewTaiwan Dollar",
+            symbol: "NT$",
+            symbol_first: true,
+        },
+        HONG_KONG_DOLLAR : {
+            code: "USD",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 1,
+            name: "HongKong Dollar",
+            symbol: "HZ$",
+            symbol_first: true,
+        },
+        NEW_ZEALAND_DOLLAR : {
+            code: "USD",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 1,
+            name: "NewZealand Dollar",
+            symbol: "NZ$",
+            symbol_first: true,
+        },
+        EUR : {
+            code: "EUR",
+            exponent: 2,
+            locale: EnEu,
+            minor_units: 1,
+            name: "Euro",
+            symbol: "€",
+            symbol_first: true,
+        },
+        GIP : {
+            code: "GIP",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 1,
+            name: "Gibraltar Pound",
+            symbol: "£",
+            symbol_first: true,
+        },
+        CNY : {
+            code: "CNY",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 1,
+            name: "Chinese Renminbi Yuan",
+            symbol: "¥",
+            symbol_first: true,
+        },
+        YUAN : {
+            code: "CNY",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 1,
+            name: "Chinese Renminbi Yuan",
+            symbol: "CN¥",
+            symbol_first: true,
+        },
+        RUB : {
+            code: "RUB",
+            exponent: 2,
+            locale: EnEu,
+            minor_units: 1,
+            name: "Russian Ruble",
+            symbol: "RUB",
+            symbol_first: false,
+        },
+        INR : {
+            code: "INR",
+            exponent: 2,
+            locale: EnIn,
+            minor_units: 50,
+            name: "Indian Rupee",
+            symbol: "₹",
+            symbol_first: true,
+        },
+        KRW : {
+            code: "KRW",
+            exponent: 0,
+            locale: EnUs,
+            minor_units: 1,
+            name: "South Korean Won",
+            symbol: "₩",
+            symbol_first: true,
+        },
+        BRL : {
+            code: "BRL",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 5,
+            name: "Brazilian real",
+            symbol: "R$",
+            symbol_first: true,
+        },
+        TRY : {
+            code: "TRY",
+            exponent: 2,
+            locale: EnEu,
+            minor_units: 1,
+            name: "Turkish Lira",
+            // symbol: "₺",
+            symbol: "TRY",
+            symbol_first: true,
+        },
+        IDR : {
+            code: "IDR",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 5000,
+            name: "Indonesian Rupiah",
+            // symbol: "Rp",
+            symbol: "IDR",
+            symbol_first: true,
+        },
+        CHF : {
+            code: "CHF",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 5,
+            name: "Swiss Franc",
+            // symbol: "Fr",
+            symbol: "CHF",
+            symbol_first: true,
+        },
+        SEK : {
+            code: "SEK",
+            exponent: 2,
+            locale: EnBy,
+            minor_units: 100,
+            name: "Swedish Krona",
+            // symbol: "kr",
+            symbol: "SEK",
+            symbol_first: false,
+        },
+        NOK : {
+            code: "NOK",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 100,
+            name: "Norwegian Krone",
+            // symbol: "kr",
+            symbol: "NOK",
+            symbol_first: false,
+        },
+        MEXICAN_PESO : {
+            code: "USD",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 1,
+            name: "Mexican Peso",
+            symbol: "MX$",
+            symbol_first: true,
+        },
+        ZAR : {
+            code: "ZAR",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 10,
+            name: "South African Rand",
+            // symbol: "R",
+            symbol: "ZAR",
+            symbol_first: true,
+        },
+        DKK : {
+            code: "DKK",
+            exponent: 2,
+            locale: EnEu,
+            minor_units: 50,
+            name: "Danish Krone",
+            // symbol: "kr.",
+            symbol: "DKK",
+            symbol_first: false,
+        },
+        THB : {
+            code: "THB",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 1,
+            name: "Thai Baht",
+            // symbol: "฿",
+            symbol: "THB",
+            symbol_first: true,
+        },
+        HUF : {
+            code: "HUF",
+            exponent: 0,
+            locale: EnBy,
+            minor_units: 5,
+            name: "Hungarian Forint",
+            // symbol: "Ft",
+            symbol: "HUF",
+            symbol_first: false,
+        },
+        KORUNA : {
+            code: "CZK",
+            exponent: 2,
+            locale: EnBy,
+            minor_units: 100,
+            name: "Czech Koruna",
+            // symbol: "Kč",
+            symbol: "CZK",
+            symbol_first: false,
+        },
+        SHEKEL : {
+            code: "CZK",
+            exponent: 2,
+            locale: EnBy,
+            minor_units: 100,
+            name: "Czech Koruna",
+            symbol: "Kč",
+            symbol_first: false,
+        },
+        CLP : {
+            code: "CLP",
+            exponent: 0,
+            locale: EnEu,
+            minor_units: 1,
+            name: "Chilean Peso",
+            // symbol: "$",
+            symbol: "CLP",
+            symbol_first: true,
+        },
+        PHP : {
+            code: "PHP",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 1,
+            name: "Philippine Peso",
+            symbol: "₱",
+            symbol_first: true,
+        },
+        AED : {
+            code: "AED",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 25,
+            name: "United Arab Emirates Dirham",
+            // symbol: "د.إ",
+            symbol: "AED",
+            symbol_first: false,
+        },
+        COP : {
+            code: "COP",
+            exponent: 2,
+            locale: EnEu,
+            minor_units: 20,
+            name: "Colombian Peso",
+            // symbol: "$",
+            symbol: "COP",
+            symbol_first: true,
+        },
+        SAR : {
+            code: "SAR",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 5,
+            name: "Saudi Riyal",
+            // symbol: "ر.س",
+            symbol: "SAR",
+            symbol_first: true,
+        },
+        MYR : {
+            code: "MYR",
+            exponent: 2,
+            locale: EnUs,
+            minor_units: 5,
+            name: "Malaysian Ringgit",
+            // symbol: "RM",
+            symbol: "MYR",
+            symbol_first: true,
+        },
+        RON : {
+            code: "RON",
+            exponent: 2,
+            locale: EnEu,
+            minor_units: 1,
+            name: "Romanian Leu",
+            // symbol: "ر.ق",
+            symbol: "RON",
+            symbol_first: false,
+        },
+        ARS : {
+            code: "ARS",
+            exponent: 2,
+            locale: EnEu,
+            minor_units: 1,
+            name: "Argentine Peso",
+            // symbol: "$",
+            symbol: "ARS",
+            symbol_first: true,
+        },
+        UYU : {
+            code: "UYU",
+            exponent: 2,
+            locale: EnEu,
+            minor_units: 100,
+            name: "Uruguayan Peso",
+            // symbol: "$U",
+            symbol: "UYU",
+            symbol_first: true,
         }
     }
+);
 
-    #[allow(dead_code)]
-    pub fn code(&self) -> String {
-        match self {
-            NumberFormat::Number => "".to_string(),
-            NumberFormat::USD => USD.iso_alpha_code.to_string(),
-            NumberFormat::CNY => CNY.iso_alpha_code.to_string(),
-            NumberFormat::EUR => EUR.iso_alpha_code.to_string(),
-        }
+impl NumberFormat {
+    pub fn currency(&self) -> &'static number_currency::Currency {
+        let currency = match self {
+            NumberFormat::Number => number_currency::NUMBER,
+            NumberFormat::USD => number_currency::USD,
+            NumberFormat::CanadianDollar => number_currency::CANADIAN_DOLLAR,
+            NumberFormat::EUR => number_currency::EUR,
+            NumberFormat::Pound => number_currency::GIP,
+            NumberFormat::Yen => number_currency::CNY,
+            NumberFormat::Ruble => number_currency::RUB,
+            NumberFormat::Rupee => number_currency::INR,
+            NumberFormat::Won => number_currency::KRW,
+            NumberFormat::Yuan => number_currency::YUAN,
+            NumberFormat::Real => number_currency::BRL,
+            NumberFormat::Lira => number_currency::TRY,
+            NumberFormat::Rupiah => number_currency::IDR,
+            NumberFormat::Franc => number_currency::CHF,
+            NumberFormat::HongKongDollar => number_currency::HONG_KONG_DOLLAR,
+            NumberFormat::NewZealandDollar => number_currency::NEW_ZEALAND_DOLLAR,
+            NumberFormat::Krona => number_currency::SEK,
+            NumberFormat::NorwegianKrone => number_currency::NOK,
+            NumberFormat::MexicanPeso => number_currency::MEXICAN_PESO,
+            NumberFormat::Rand => number_currency::ZAR,
+            NumberFormat::NewTaiwanDollar => number_currency::NEW_TAIWAN_DOLLAR,
+            NumberFormat::DanishKrone => number_currency::DKK,
+            NumberFormat::Baht => number_currency::THB,
+            NumberFormat::Forint => number_currency::HUF,
+            NumberFormat::Koruna => number_currency::KORUNA,
+            NumberFormat::Shekel => number_currency::SHEKEL,
+            NumberFormat::ChileanPeso => number_currency::CLP,
+            NumberFormat::PhilippinePeso => number_currency::PHP,
+            NumberFormat::Dirham => number_currency::AED,
+            NumberFormat::ColombianPeso => number_currency::COP,
+            NumberFormat::Riyal => number_currency::SAR,
+            NumberFormat::Ringgit => number_currency::MYR,
+            NumberFormat::Leu => number_currency::RON,
+            NumberFormat::ArgentinePeso => number_currency::ARS,
+            NumberFormat::UruguayanPeso => number_currency::UYU,
+            NumberFormat::Percent => number_currency::USD,
+        };
+        currency
+    }
+
+    pub fn symbol(&self) -> String {
+        self.currency().symbol.to_string()
     }
 }
 
@@ -250,18 +638,25 @@ mod tests {
                     assert_eq!(type_option.decode_cell_data(data(""), &field_meta), "".to_owned());
                     assert_eq!(type_option.decode_cell_data(data("abc"), &field_meta), "".to_owned());
                 }
-                NumberFormat::CNY => {
+                NumberFormat::Yen => {
                     assert_eq!(
                         type_option.decode_cell_data(data("18443"), &field_meta),
                         "¥18,443".to_owned()
                     );
                 }
+                NumberFormat::Yuan => {
+                    assert_eq!(
+                        type_option.decode_cell_data(data("18443"), &field_meta),
+                        "CN¥18,443".to_owned()
+                    );
+                }
                 NumberFormat::EUR => {
                     assert_eq!(
                         type_option.decode_cell_data(data("18443"), &field_meta),
                         "€18.443".to_owned()
                     );
                 }
+                _ => {}
             }
         }
     }
@@ -293,7 +688,7 @@ mod tests {
                         "$1,844.3".to_owned()
                     );
                 }
-                NumberFormat::CNY => {
+                NumberFormat::Yen => {
                     assert_eq!(
                         type_option.decode_cell_data(data("18443"), &field_meta),
                         "¥1,844.3".to_owned()
@@ -305,6 +700,7 @@ mod tests {
                         "€1.844,3".to_owned()
                     );
                 }
+                _ => {}
             }
         }
     }
@@ -332,7 +728,7 @@ mod tests {
                         "-$18,443".to_owned()
                     );
                 }
-                NumberFormat::CNY => {
+                NumberFormat::Yen => {
                     assert_eq!(
                         type_option.decode_cell_data(data("18443"), &field_meta),
                         "-¥18,443".to_owned()
@@ -344,6 +740,7 @@ mod tests {
                         "-€18.443".to_owned()
                     );
                 }
+                _ => {}
             }
         }
     }