Flutter - Coding Style === Naming Convention --- * All class names should be pascal case. (i.e. LoginPage) * All file names should be snake case. (i.e. login_page.dart) * All variables should be camel case. (i.e. passwordTextController) * Use project specific prefix for classes that may confuse with built-in classes. Example prefix: Brg (for Burgan Bank project). Example classes: BrgButton, BrgAsset, BrgTextStyle, BrgColor... * BLoC pattern naming convention: * Bloc name should be in this format "(BlocName)Bloc". (i.e. LoginBloc) * Bloc events should be in this format "(BlocName)Event(EventName)". (i.e. LoginEventPressSubmitButton) Note that; events must start with a verb (Press in this example) * Bloc states should be in this format "(BlocName)State(StateName)". (i.e. LoginStateLoading) * Write a widget for ListView(or any kind of repeated widgets inside a mapper function) items. * i.e. Lets say you are building a list with account details. You can write a widget name AccountDetailsListItemWidget. * Sub builder methods in build method should start with "_build" prefix and widget type suffix(i.e. Button, Image, Card etc. If none of the prebuilt types are suitable, we can simply add Widget suffix). * i.e.: ```gherkin= Widget build(BuildContext context) { return Column( children: [ _buildNameInputWidget(context), _buildSurnameInputWidget(context), _buildEmailInputWidget(context), _buildContinueButton(context), ], ) } ``` * Builder methods' return type should be Widget, not a widget type such as Row, Column, Padding etc. > Note: Keep build method simple as possible by using private sub builder methods or custom widgets. * Extension file names should be end with "_extensions.dart". (i.e. string_extensions.dart) * All constants in a file should be under "_Contants" class and defined as static variables. * All feature specific custom widgets should have a feature prefix in their name. (i.e. OtpCountDownTimer custom widget in otp page) * All colors and assets should be placed into their own classes/enums. (i.e. BrgColor.background, BrgAsset.backgroundImage.path) Comments --- * TODO: Use this comment type if your code can be improved but you don't have time to do it for now. * STOPSHIP: Use this comment type whenever you think that "We can't go live without doing this". We often use this comment type in development process to commit partial work. > Use triple slash ("/// High level explanation comment") for high level comments(explaining class' methods or fields). Use double slash ("// Inner comment") for inner comments.(i.e. explaining a complex method line by line) Folder Structure --- ```gherkin= - assets - images - animations - assets - lib - core - features - common - models - first_feature - bloc - first_feature_bloc.dart - first_feature_event.dart - first_feature_state.dart - models (feature specific models) - first_feature_ui_model.dart - network - first_feature_network_manager.dart - models (only network models) - first_feature_request.dart - first_feature_request.g.dart - first_feature_response.dart - first_feature_response.g.dart - repository - first_feature_repository.dart - usecases - first_feature_usecase.dart - widgets - first_feature_otp_input_widget.dart - first_feature_submit_button.dart - first_feature_page.dart - first_feature_page_router.dart - utils - animations - constants - brg_constants.dart - brg_assets.dart (enum class) - brg_text_style.dart - brg_colors.dart - extensions - string_extensions.dart - boolean_extensions.dart - widget_extensions.dart - reusable_widgets - widgetbook (optional) - pages - widgetbook_folder_login_pages.dart - widgetbook_folder_signup_pages.dart - reusable_widgets - widgetbook_brg_button.dart - widgetbook_brg_dropdown_form_field - main.dart - widgetbook.dart (optional) ``` Editor Settings --- * Set line max length as 120 character * Activate "Format code on save" setting * Activate "Organize imports on save" setting * Do not use relative path for imports. Example; * Do not: import '../../../burgan_core.dart'; * Do: import 'package:burgan_core/core/bus/widget_event_bus/brg_widget_event.dart'; Custom Linter Rules --- Create analysis_options.yaml if not exist, and add these configurations below; ```gherkin= linter: rules: - always_use_package_imports - avoid_empty_else - avoid_print - avoid_relative_lib_imports - avoid_slow_async_io - avoid_type_to_string - avoid_types_as_parameter_names - avoid_web_libraries_in_flutter - cancel_subscriptions - close_sinks - collection_methods_unrelated_type - control_flow_in_finally - empty_statements - hash_and_equals - invalid_case_patterns - literal_only_boolean_expressions - no_adjacent_strings_in_list - no_duplicate_case_values - no_logic_in_create_state - prefer_void_to_null - test_types_in_equals - throw_in_finally - unnecessary_statements - unrelated_type_equality_checks - use_build_context_synchronously - use_key_in_widget_constructors - valid_regexps # If you are using Dart 3.1+, enable these rules too # - no_self_assignments # - no_wildcard_variable_uses # Style rules - always_put_control_body_on_new_line - always_put_required_named_parameters_first - annotate_overrides - avoid_bool_literals_in_conditional_expressions - avoid_double_and_int_checks - avoid_equals_and_hash_code_on_mutable_classes - avoid_escaping_inner_quotes - avoid_field_initializers_in_const_classes - avoid_final_parameters - avoid_function_literals_in_foreach_calls - avoid_implementing_value_types - avoid_init_to_null - avoid_js_rounded_ints - avoid_multiple_declarations_per_line - avoid_null_checks_in_equality_operators - avoid_positional_boolean_parameters - avoid_private_typedef_functions - avoid_redundant_argument_values - avoid_renaming_method_parameters - avoid_return_types_on_setters - avoid_returning_null_for_void - avoid_returning_this - avoid_shadowing_type_parameters - avoid_single_cascade_in_expression_statements - avoid_unused_constructor_parameters - avoid_void_async - await_only_futures - camel_case_extensions - camel_case_types - cascade_invocations - cast_nullable_to_non_nullable - conditional_uri_does_not_exist - constant_identifier_names - curly_braces_in_flow_control_structures - dangling_library_doc_comments - deprecated_consistency - directives_ordering - do_not_use_environment - empty_catches - empty_constructor_bodies - eol_at_end_of_file - exhaustive_cases - file_names - implementation_imports - implicit_call_tearoffs - join_return_with_assignment - leading_newlines_in_multiline_strings - library_annotations - library_names - library_prefixes - library_private_types_in_public_api - matching_super_parameters - no_default_cases - no_leading_underscores_for_library_prefixes - no_leading_underscores_for_local_identifiers - no_literal_bool_comparisons - no_runtimeType_toString - non_constant_identifier_names - noop_primitive_operations - null_check_on_nullable_type_parameter - null_closures - overridden_fields - package_prefixed_library_names - parameter_assignments - prefer_adjacent_string_concatenation - prefer_asserts_in_initializer_lists - prefer_conditional_assignment - prefer_const_constructors - prefer_const_constructors_in_immutables - prefer_const_declarations - prefer_const_literals_to_create_immutables - prefer_constructors_over_static_methods - prefer_contains - prefer_final_fields - prefer_final_in_for_each - prefer_final_locals - prefer_for_elements_to_map_fromIterable - prefer_function_declarations_over_variables - prefer_generic_function_type_aliases - prefer_if_null_operators - prefer_initializing_formals - prefer_inlined_adds - prefer_interpolation_to_compose_strings - prefer_is_empty - prefer_is_not_empty - prefer_is_not_operator - prefer_iterable_whereType - prefer_null_aware_method_calls - prefer_null_aware_operators - prefer_spread_collections - prefer_typing_uninitialized_variables - provide_deprecation_message - recursive_getters - require_trailing_commas - sized_box_for_whitespace - sort_child_properties_last - type_annotate_public_apis - type_init_formals - type_literal_in_constant_pattern - unawaited_futures - unnecessary_await_in_return - unnecessary_brace_in_string_interps - unnecessary_const - unnecessary_constructor_name - unnecessary_getters_setters - unnecessary_lambdas - unnecessary_late - unnecessary_new - unnecessary_null_aware_assignments - unnecessary_null_aware_operator_on_extension_on_nullable - unnecessary_null_checks - unnecessary_null_in_if_null_operators - unnecessary_nullable_for_final_variable_declarations - unnecessary_overrides - unnecessary_parenthesis - unnecessary_raw_strings - unnecessary_string_escapes - unnecessary_string_interpolations - unnecessary_to_list_in_spreads - use_colored_box - use_decorated_box - use_enums - use_full_hex_values_for_flutter_colors - use_function_type_syntax_for_parameters - use_if_null_to_convert_nulls_to_bools - use_is_even_rather_than_modulo - use_named_constants - use_to_and_as_if_applicable - void_checks - depend_on_referenced_packages - package_names - secure_pubspec_urls analyzer: errors: lines_longer_than_80_chars: ignore exclude: - lib/**.g.dart - lib/**.pb.dart - lib/**.pbenum.dart - lib/**.pbjson.dart - lib/**.pbserver.dart ``` If you have to ignore any rule(s) to fix it later, use ignore comment at related part of the code. * i.e.: ```gherkin= // STOPSHIP: Delete this ignore later // ignore: must_be_immutable, avoid_print class AccountSliderWidget extends StatelessWidget { ... } ``` Plugins --- * Android Studio * Flutter * Dart * Bloc * Rainbow Brackets