├── lib ├── l10n │ ├── intl_bn.arb │ ├── intl_bo.arb │ ├── intl_ca.arb │ ├── intl_cs.arb │ ├── intl_et.arb │ ├── intl_eu.arb │ ├── intl_fa.arb │ ├── intl_gl.arb │ ├── intl_he.arb │ ├── intl_hi.arb │ ├── intl_hr.arb │ ├── intl_hu.arb │ ├── intl_ie.arb │ ├── intl_ja.arb │ ├── intl_lt.arb │ ├── intl_nl.arb │ ├── intl_pl.arb │ ├── intl_ro.arb │ ├── intl_si.arb │ ├── intl_sk.arb │ ├── intl_sl.arb │ ├── intl_sr.arb │ ├── intl_sv.arb │ ├── intl_th.arb │ ├── intl_tr.arb │ ├── intl_pt_PT.arb │ ├── intl_zh_Hant.arb │ ├── intl_ko.arb │ ├── intl_pt.arb │ └── intl_fi.arb ├── main │ ├── universal_import │ │ ├── html_web.dart │ │ ├── html_io.dart │ │ └── html_stub.dart │ ├── exceptions │ │ ├── isolate_exception.dart │ │ └── exception_thrower.dart │ ├── deep_links │ │ ├── deep_link_action_type.dart │ │ └── deep_link_data.dart │ ├── routes │ │ └── router_arguments.dart │ ├── bindings │ │ └── network │ │ │ └── binding_tag.dart │ └── localizations │ │ └── language_code_constants.dart └── features │ ├── base │ ├── state │ │ ├── banner_state.dart │ │ ├── base_ui_state.dart │ │ └── button_state.dart │ ├── shortcut │ │ ├── search │ │ │ └── search_action_shortcut_type.dart │ │ └── composer │ │ │ └── composer_action_shortcut_type.dart │ ├── before_reconnect_handler.dart │ ├── isolate │ │ └── background_isolate_binary_messenger │ │ │ ├── background_isolate_binary_messenger_mobile.dart │ │ │ ├── background_isolate_binary_messenger_web.dart │ │ │ └── background_isolate_binary_messenger.dart │ ├── upgradeable │ │ └── upgrade_database_steps.dart │ └── styles │ │ ├── hyper_link_widget_styles.dart │ │ └── circle_loading_widget_styles.dart │ ├── email │ ├── domain │ │ ├── model │ │ │ ├── move_action.dart │ │ │ └── mark_read_action.dart │ │ ├── state │ │ │ ├── get_list_detailed_email_by_id_state.dart │ │ │ ├── print_email_state.dart │ │ │ └── store_new_email_state.dart │ │ ├── exceptions │ │ │ └── email_cache_exceptions.dart │ │ ├── extensions │ │ │ ├── email_header_hive_cache_extension.dart │ │ │ └── email_header_extension.dart │ │ └── repository │ │ │ └── mdn_repository.dart │ ├── presentation │ │ ├── model │ │ │ └── page_view_navigator_state.dart │ │ ├── utils │ │ │ └── smime_signature_constant.dart │ │ ├── styles │ │ │ ├── event_title_widget_styles.dart │ │ │ ├── email_view_styles.dart │ │ │ ├── calendar_event_action_banner_styles.dart │ │ │ ├── email_view_empty_styles.dart │ │ │ ├── attendee_widget_styles.dart │ │ │ └── organizer_widget_styles.dart │ │ └── extensions │ │ │ └── calendar_organier_extension.dart │ └── data │ │ └── datasource │ │ ├── print_file_datasource.dart │ │ └── mdn_datasource.dart │ ├── push_notification │ ├── domain │ │ ├── model │ │ │ └── web_socket_action.dart │ │ ├── utils │ │ │ └── fcm_constants.dart │ │ ├── exceptions │ │ │ └── web_socket_exceptions.dart │ │ └── repository │ │ │ └── web_socket_repository.dart │ ├── data │ │ ├── model │ │ │ └── web_socket_request.dart │ │ └── datasource │ │ │ └── web_socket_datasource.dart │ └── presentation │ │ └── extensions │ │ └── state_change_extension.dart │ ├── login │ ├── presentation │ │ ├── model │ │ │ └── login_navigate_type.dart │ │ └── login_form_type.dart │ ├── domain │ │ ├── exceptions │ │ │ └── logout_exception.dart │ │ ├── extensions │ │ │ └── uri_extension.dart │ │ ├── model │ │ │ ├── login_constants.dart │ │ │ ├── company_server_login_info.dart │ │ │ └── base_url_oidc_response.dart │ │ ├── repository │ │ │ ├── authentication_repository.dart │ │ │ └── account_repository.dart │ │ └── state │ │ │ ├── delete_credential_state.dart │ │ │ ├── save_recent_login_url_state.dart │ │ │ ├── delete_authority_oidc_state.dart │ │ │ └── save_recent_login_username_state.dart │ └── data │ │ ├── utils │ │ └── library_platform │ │ │ └── app_auth_plugin │ │ │ ├── app_auth_web_plugin.dart │ │ │ ├── app_auth_plugin.dart │ │ │ └── app_auth_mobile_plugin.dart │ │ ├── network │ │ ├── endpoint.dart │ │ └── oidc_error.dart │ │ ├── datasource │ │ ├── authentication_datasource.dart │ │ └── account_datasource.dart │ │ └── extensions │ │ ├── token_oidc_extension.dart │ │ └── token_oidc_cache_extension.dart │ ├── thread │ ├── presentation │ │ └── model │ │ │ ├── search_status.dart │ │ │ └── loading_more_status.dart │ ├── domain │ │ ├── exceptions │ │ │ └── thread_exceptions.dart │ │ ├── model │ │ │ └── search_query.dart │ │ └── state │ │ │ └── clean_and_get_all_email_state.dart │ └── data │ │ └── extensions │ │ ├── map_mailbox_id_extension.dart │ │ ├── map_keywords_extension.dart │ │ ├── map_header_identifier_id_extension.dart │ │ ├── email_address_extension.dart │ │ └── email_address_hive_cache_extension.dart │ ├── upload │ ├── domain │ │ ├── exceptions │ │ │ ├── pick_file_exception.dart │ │ │ └── upload_exception.dart │ │ ├── extensions │ │ │ └── list_platform_file_extensions.dart │ │ └── model │ │ │ └── upload_task_id.dart │ ├── presentation │ │ └── model │ │ │ └── upload_file_status.dart │ └── data │ │ └── datasource │ │ └── attachment_upload_datasource.dart │ ├── caching │ ├── config │ │ └── cache_version.dart │ ├── exceptions │ │ └── local_storage_exception.dart │ ├── interaction │ │ └── cache_manager_interaction.dart │ └── clients │ │ ├── cache_version_client.dart │ │ ├── email_cache_client.dart │ │ ├── state_cache_client.dart │ │ ├── account_cache_client.dart │ │ ├── mailbox_cache_client.dart │ │ ├── fcm_cache_client.dart │ │ ├── encryption_key_cache_client.dart │ │ ├── recent_login_url_cache_client.dart │ │ ├── recent_search_cache_client.dart │ │ ├── recent_login_username_cache_client.dart │ │ └── token_oidc_cache_client.dart │ ├── composer │ ├── presentation │ │ ├── model │ │ │ ├── code_view_state.dart │ │ │ ├── dropdown_menu_font_status.dart │ │ │ ├── prefix_recipient_state.dart │ │ │ ├── formatting_options_state.dart │ │ │ ├── compose_action_mode.dart │ │ │ └── screen_display_mode.dart │ │ ├── extensions │ │ │ ├── list_identities_extension.dart │ │ │ ├── identity_extension.dart │ │ │ └── setup_email_request_read_receipt_flag_for_edit_draft_extension.dart │ │ └── styles │ │ │ ├── web │ │ │ └── mobile_responsive_container_view_style.dart │ │ │ └── title_composer_widget_style.dart │ ├── domain │ │ ├── model │ │ │ └── contact_suggestion_source.dart │ │ ├── exceptions │ │ │ ├── compose_email_exception.dart │ │ │ └── set_method_exception.dart │ │ ├── repository │ │ │ ├── contact_repository.dart │ │ │ └── auto_complete_repository.dart │ │ └── state │ │ │ ├── generate_email_state.dart │ │ │ └── save_email_address_state.dart │ └── data │ │ └── datasource │ │ ├── contact_datasource.dart │ │ └── composer_datasource.dart │ ├── mailbox_dashboard │ ├── presentation │ │ ├── model │ │ │ ├── loader_status.dart │ │ │ ├── draggable_app_state.dart │ │ │ ├── dashboard_routes.dart │ │ │ └── refresh_action_view_event.dart │ │ └── styles │ │ │ ├── navigation_bar_style.dart │ │ │ ├── mark_mailbox_as_read_loading_banner_style.dart │ │ │ └── top_bar_thread_selection_style.dart │ └── domain │ │ ├── exceptions │ │ ├── linagora_ecosystem_exceptions.dart │ │ └── spam_report_exception.dart │ │ ├── linagora_ecosystem │ │ └── linagora_ecosystem_properties.dart │ │ ├── model │ │ └── spam_report_state.dart │ │ └── state │ │ ├── save_composer_cache_state.dart │ │ └── save_recent_search_state.dart │ ├── download │ └── domain │ │ ├── model │ │ └── download_source_view.dart │ │ └── exceptions │ │ └── download_attachment_exceptions.dart │ ├── mailbox │ ├── domain │ │ ├── model │ │ │ ├── mailbox_subscribe_state.dart │ │ │ ├── mailbox_subaddressing_action.dart │ │ │ ├── jmap_mailbox_response.dart │ │ │ └── cache_mailbox_response.dart │ │ └── exceptions │ │ │ ├── set_mailbox_method_exception.dart │ │ │ ├── set_mailbox_rights_exception.dart │ │ │ ├── invalid_mail_format_exception.dart │ │ │ ├── null_session_or_accountid_exception.dart │ │ │ ├── mailbox_exception.dart │ │ │ └── empty_folder_name_exception.dart │ ├── presentation │ │ ├── model │ │ │ └── mailbox_displayed.dart │ │ └── styles │ │ │ ├── mailbox_icon_widget_styles.dart │ │ │ ├── mailbox_loading_bar_widget_styles.dart │ │ │ └── empty_mailbox_popup_dialog_widget_styles.dart │ └── data │ │ └── extensions │ │ └── state_cache_extension.dart │ ├── manage_account │ ├── presentation │ │ ├── model │ │ │ ├── reading_pane.dart │ │ │ └── settings_page_level.dart │ │ ├── mailbox_visibility │ │ │ └── state │ │ │ │ └── mailbox_visibility_state.dart │ │ ├── vacation │ │ │ └── styles │ │ │ │ └── vacation_notification_message_widget_style.dart │ │ ├── storage │ │ │ └── storage_bindings.dart │ │ ├── forward │ │ │ └── bindings │ │ │ │ └── forward_bindings.dart │ │ ├── email_rules │ │ │ └── bindings │ │ │ │ └── email_rules_bindings.dart │ │ └── menu │ │ │ └── manage_account_menu_bindings.dart │ ├── domain │ │ ├── exceptions │ │ │ ├── rule_filter_exception.dart │ │ │ └── forward_exception.dart │ │ ├── model │ │ │ └── preferences │ │ │ │ ├── preferences_config.dart │ │ │ │ └── empty_preferences_config.dart │ │ ├── repository │ │ │ └── notification_repository.dart │ │ └── state │ │ │ ├── notification_setting_state.dart │ │ │ ├── log_out_oidc_state.dart │ │ │ └── toggle_notification_setting_state.dart │ └── data │ │ ├── datasource │ │ ├── trace_log_datasource.dart │ │ └── notification_datasource.dart │ │ └── repository │ │ └── trace_log_repository.dart │ ├── thread_detail │ ├── domain │ │ └── exceptions │ │ │ ├── empty_thread_detail_exception.dart │ │ │ └── thread_detail_overload_exception.dart │ └── presentation │ │ └── model │ │ ├── thread_detail_setting_status.dart │ │ └── thread_detail_arguments.dart │ ├── search │ └── email │ │ └── presentation │ │ ├── model │ │ └── search_more_state.dart │ │ └── styles │ │ ├── email_sort_by_action_tile_widget_style.dart │ │ └── email_sort_by_cupertino_action_sheet_action_builder_style.dart │ ├── identity_creator │ └── presentation │ │ ├── extesions │ │ └── size_extension.dart │ │ └── utils │ │ └── identity_creator_constants.dart │ ├── quotas │ ├── domain │ │ ├── exceptions │ │ │ └── quotas_exception.dart │ │ ├── repository │ │ │ └── quotas_repository.dart │ │ └── extensions │ │ │ └── list_quotas_extensions.dart │ └── data │ │ └── datasource │ │ └── quotas_data_source.dart │ ├── sending_queue │ ├── data │ │ └── exceptions │ │ │ └── sending_queue_exceptions.dart │ └── presentation │ │ └── utils │ │ └── sending_queue_isolate_manager.dart │ ├── mailbox_creator │ └── domain │ │ ├── model │ │ └── verification │ │ │ ├── validator.dart │ │ │ └── new_name_request.dart │ │ └── state │ │ └── verify_name_view_state.dart │ ├── paywall │ ├── data │ │ └── datasource │ │ │ └── paywall_datasource.dart │ └── domain │ │ └── repository │ │ └── paywall_repository.dart │ ├── server_settings │ └── domain │ │ └── exceptions │ │ └── server_settings_exception.dart │ ├── offline_mode │ └── manager │ │ ├── new_email_cache_worker_queue.dart │ │ └── opened_email_cache_worker_queue.dart │ ├── home │ ├── data │ │ ├── datasource │ │ │ └── session_datasource.dart │ │ └── exceptions │ │ │ └── session_exceptions.dart │ └── domain │ │ ├── repository │ │ └── session_repository.dart │ │ └── state │ │ └── store_session_state.dart │ ├── contact │ ├── data │ │ └── datasource │ │ │ └── auto_complete_datasource.dart │ └── presentation │ │ └── contact_bindings.dart │ ├── mailto │ └── presentation │ │ └── mailto_url_bindings.dart │ ├── email_recovery │ └── presentation │ │ └── email_recovery_bindings.dart │ ├── cleanup │ └── domain │ │ ├── model │ │ ├── email_cleanup_rule.dart │ │ ├── recent_login_url_cleanup_rule.dart │ │ └── recent_login_username_cleanup_rule.dart │ │ └── state │ │ ├── cleanup_email_cache_state.dart │ │ └── cleanup_recent_login_url_cache_state.dart │ └── starting_page │ ├── domain │ └── repository │ │ └── saas_authentication_repository.dart │ └── data │ └── datasource │ └── saas_authentication_datasource.dart ├── core ├── README.md ├── lib │ ├── utils │ │ ├── web_renderer │ │ │ ├── canvas_kit.dart │ │ │ ├── canvas_kit_stub.dart │ │ │ └── canvas_kit_web.dart │ │ ├── html │ │ │ └── js_interop_stub.dart │ │ ├── config │ │ │ ├── app_config_parser.dart │ │ │ └── errors.dart │ │ ├── double_convert.dart │ │ ├── build_utils.dart │ │ ├── option_param_mixin.dart │ │ ├── list_utils.dart │ │ ├── logger │ │ │ └── trace_log.dart │ │ └── mail │ │ │ └── named_address.dart │ ├── data │ │ ├── model │ │ │ └── source_type │ │ │ │ └── data_source_type.dart │ │ ├── network │ │ │ ├── config │ │ │ │ └── service_path.dart │ │ │ └── download │ │ │ │ └── downloaded_response.dart │ │ └── extensions │ │ │ └── options_extensions.dart │ ├── presentation │ │ ├── extensions │ │ │ ├── compare_string_extension.dart │ │ │ ├── list_nullable_extensions.dart │ │ │ ├── compare_list_extensions.dart │ │ │ ├── capitalize_extension.dart │ │ │ └── map_extensions.dart │ │ ├── utils │ │ │ ├── icon_utils.dart │ │ │ ├── style_utils.dart │ │ │ ├── html_transformer │ │ │ │ └── base │ │ │ │ │ └── text_transformer.dart │ │ │ └── keyboard_utils.dart │ │ ├── resources │ │ │ └── assets_paths.dart │ │ ├── action │ │ │ └── action_callback_define.dart │ │ └── views │ │ │ ├── loading │ │ │ └── cupertino_loading_widget_styles.dart │ │ │ └── list │ │ │ └── no_stretch_scroll_behavior.dart │ └── domain │ │ ├── exceptions │ │ ├── string_exception.dart │ │ └── address_exception.dart │ │ └── preview │ │ └── document_uti.dart └── .metadata ├── fcm ├── README.md ├── lib │ ├── model │ │ ├── fcm_token.dart │ │ ├── firebase_capability.dart │ │ ├── device_client_id.dart │ │ ├── firebase_registration_id.dart │ │ ├── firebase_registration_expired_time.dart │ │ └── type_name.dart │ └── converter │ │ └── type_name_converter.dart └── .metadata ├── contact ├── README.md ├── lib │ └── contact │ │ └── model │ │ ├── contact.dart │ │ └── capability_contact.dart └── .metadata ├── forward ├── README.md ├── lib │ └── forward │ │ ├── forward.dart │ │ └── capability_forward.dart └── .metadata ├── cozy ├── README.md ├── analysis_options.yaml └── lib │ └── cozy_config_manager │ └── cozy_config_manager.dart ├── model ├── README.md ├── lib │ ├── mailbox │ │ ├── expand_mode.dart │ │ ├── select_mode.dart │ │ ├── mailbox_state.dart │ │ └── mailbox_constants.dart │ ├── account │ │ ├── account_type.dart │ │ ├── authentication_type.dart │ │ └── password.dart │ ├── email │ │ ├── email_in_thread_status.dart │ │ ├── mark_star_action.dart │ │ ├── read_actions.dart │ │ ├── email_content_type.dart │ │ ├── prefix_email_address.dart │ │ ├── presentation_email_address.dart │ │ └── eml_attachment.dart │ ├── error_type_handler │ │ ├── unknown_uri_exception.dart │ │ ├── account_exception.dart │ │ ├── unknown_address_exception.dart │ │ └── set_method_error_handler_mixin.dart │ ├── mixin │ │ └── search_snippet_mixin.dart │ ├── extensions │ │ ├── account_id_extensions.dart │ │ ├── identity_id_extension.dart │ │ ├── properties_extension.dart │ │ ├── oidc_user_info_extension.dart │ │ ├── list_id_extension.dart │ │ ├── list_extension.dart │ │ ├── list_email_content_extension.dart │ │ ├── list_mailbox_extension.dart │ │ ├── set_email_body_part_extension.dart │ │ └── contact_support_capability_extension.dart │ ├── principals │ │ └── capability_principals.dart │ ├── oidc │ │ ├── token_id.dart │ │ └── converter │ │ │ ├── uri_converter.dart │ │ │ └── token_id_converter.dart │ ├── download │ │ └── download_task_id.dart │ ├── contact │ │ └── device_contact.dart │ ├── exceptions │ │ └── token_oidc_exceptions.dart │ └── fcm │ │ └── fcm_token_dto.dart └── .metadata ├── android ├── Gemfile ├── fastlane │ └── Appfile ├── gradle │ └── wrapper │ │ ├── gradle-wrapper 2.jar │ │ └── gradle-wrapper.properties ├── app │ └── src │ │ ├── main │ │ ├── ic_launcher-playstore.png │ │ └── res │ │ │ ├── drawable │ │ │ ├── background.png │ │ │ └── ic_large_notification.png │ │ │ ├── drawable-v21 │ │ │ └── background.png │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── raw │ │ │ └── keep.xml │ │ │ ├── drawable-hdpi │ │ │ └── notification_icon.png │ │ │ ├── drawable-mdpi │ │ │ └── notification_icon.png │ │ │ ├── drawable-xhdpi │ │ │ └── notification_icon.png │ │ │ ├── drawable-xxhdpi │ │ │ └── notification_icon.png │ │ │ ├── values │ │ │ └── colors.xml │ │ │ └── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── debug │ │ └── AndroidManifest.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── .gitignore └── gradle.properties ├── ios ├── Gemfile ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── 16.png │ │ │ ├── 20.png │ │ │ ├── 29.png │ │ │ ├── 32.png │ │ │ ├── 40.png │ │ │ ├── 48.png │ │ │ ├── 50.png │ │ │ ├── 55.png │ │ │ ├── 57.png │ │ │ ├── 58.png │ │ │ ├── 60.png │ │ │ ├── 64.png │ │ │ ├── 66.png │ │ │ ├── 72.png │ │ │ ├── 76.png │ │ │ ├── 80.png │ │ │ ├── 87.png │ │ │ ├── 88.png │ │ │ ├── 92.png │ │ │ ├── 100.png │ │ │ ├── 102.png │ │ │ ├── 1024.png │ │ │ ├── 114.png │ │ │ ├── 120.png │ │ │ ├── 128.png │ │ │ ├── 144.png │ │ │ ├── 152.png │ │ │ ├── 167.png │ │ │ ├── 172.png │ │ │ ├── 180.png │ │ │ ├── 196.png │ │ │ ├── 216.png │ │ │ ├── 256.png │ │ │ └── 512.png │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ └── LaunchImage@3x.png │ │ ├── BrandingImage.imageset │ │ │ ├── BrandingImage.png │ │ │ ├── BrandingImage@2x.png │ │ │ └── BrandingImage@3x.png │ │ └── LaunchBackground.imageset │ │ │ └── background.png │ ├── vi.lproj │ │ └── Localizable.strings │ ├── en.lproj │ │ └── Localizable.strings │ ├── ru.lproj │ │ └── Localizable.strings │ └── fr.lproj │ │ └── Localizable.strings ├── Flutter │ ├── Debug.xcconfig │ └── Release.xcconfig ├── TeamMailShareExtension │ ├── ShareViewController.swift │ └── TeamMailShareExtension.entitlements ├── TwakeCore │ ├── Network │ │ └── Model │ │ │ ├── AuthenticationType.swift │ │ │ ├── Authentication.swift │ │ │ └── TokenOidc.swift │ ├── Jmap │ │ └── Model │ │ │ └── Email │ │ │ └── EmailAddress.swift │ ├── Logger │ │ └── TwakeLogger.swift │ └── Exceptions │ │ └── NetworkExceptions.swift ├── TwakeMailNSE │ └── Model │ │ └── TypeName.swift ├── fastlane │ └── Appfile ├── Runner.xcodeproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist └── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ ├── WorkspaceSettings.xcsettings │ └── IDEWorkspaceChecks.plist ├── rule_filter ├── README.md ├── lib │ └── rule_filter │ │ ├── rule.dart │ │ └── capability_rule_filter.dart └── .metadata ├── email_recovery ├── README.md ├── lib │ └── email_recovery │ │ ├── email_recovery_status.dart.dart │ │ └── capability_deleted_messages_vault.dart └── .metadata ├── server_settings ├── README.md ├── lib │ └── server_settings │ │ ├── server_settings.dart │ │ └── tmail_server_settings_extension.dart └── .metadata ├── scripts ├── build-dev.sh ├── build-release.sh ├── setup-firebase.sh ├── setup-ios.sh ├── build-web.sh ├── setup-android.sh ├── test.sh └── configure-web-environment.sh ├── web ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png ├── splash │ └── img │ │ └── icon_twp.png ├── worker_service │ └── img │ │ ├── tmail-1x.png │ │ ├── tmail-2x.png │ │ ├── tmail-3x.png │ │ ├── tmail-4x.png │ │ ├── ic-close-1x.png │ │ ├── ic-close-2x.png │ │ ├── ic-close-3x.png │ │ └── ic-close-4x.png └── i18n │ ├── vi.json │ ├── en.json │ ├── de.json │ └── fr.json ├── assets ├── icons │ ├── icon_twp.png │ ├── icon_android.png │ ├── icon_launcher.png │ ├── icon_logo_ios.png │ └── icon_twp_android12.png ├── fonts │ ├── Inter │ │ ├── Inter-Bold.ttf │ │ ├── Inter-Medium.ttf │ │ ├── Inter-Regular.ttf │ │ └── Inter-SemiBold.ttf │ └── fallback │ │ ├── Roboto-Regular.ttf │ │ ├── NotoSans-Regular.ttf │ │ ├── NotoEmoji-Regular.ttf │ │ ├── NotoSansKR-Regular.ttf │ │ ├── NotoSansSC-Regular.ttf │ │ ├── NotoSansMath-Regular.ttf │ │ ├── NotoSansTamil-Regular.ttf │ │ ├── NotoSansThai-Regular.ttf │ │ ├── NotoSansArabic-Regular.ttf │ │ ├── NotoSansSymbols-Regular.ttf │ │ ├── NotoSansSymbols2-Regular.ttf │ │ └── NotoSansEgyptianHieroglyphs-Regular.ttf └── images │ ├── ic_unread_status.svg │ ├── ic_unselected.svg │ ├── ic_download.svg │ ├── ic_arrow_back.svg │ ├── ic_collapse_attachment.svg │ ├── ic_close_dialog.svg │ ├── ic_checked.svg │ ├── ic_radio_selected.svg │ ├── ic_format_quote.svg │ ├── ic_composer_close.svg │ ├── ic_radio.svg │ ├── ic_photo_library.svg │ ├── ic_remove_rule.svg │ ├── ic_switch_off.svg │ ├── ic_switch_on.svg │ ├── ic_minimize.svg │ └── ic_more.svg ├── integration_test ├── exceptions │ └── mailbox │ │ ├── null_quota_exception.dart │ │ └── null_inbox_unread_count_exception.dart ├── base │ └── core_robot.dart ├── models │ ├── provisioning_identity.dart │ └── provisioning_email.dart ├── tests │ ├── misc │ │ └── log_out_test.dart │ ├── app_grid │ │ └── app_grid_test.dart │ ├── composer │ │ ├── send_email_test.dart │ │ ├── save_as_template_test.dart │ │ ├── forward_email_test.dart │ │ └── reply_to_own_sent_email_test.dart │ ├── mailbox │ │ ├── switch_mailbox_test.dart │ │ ├── pull_to_refresh_test.dart │ │ ├── quota_count_test.dart │ │ ├── create_personal_folder_test.dart │ │ ├── empty_and_recover_spam_test.dart │ │ ├── empty_and_recover_trash_test.dart │ │ ├── empty_trash_test.dart │ │ ├── mailbox_move_email_test.dart │ │ ├── search_mailbox_inbox_test.dart │ │ ├── mark_mailbox_as_read_test.dart │ │ ├── quick_filter_test.dart │ │ ├── create_and_hide_sub_folder_test.dart │ │ ├── mailbox_count_real_time_update_test.dart │ │ ├── team_mailbox_receive_email_test.dart │ │ ├── long_press_empty_and_recover_spam_test.dart │ │ ├── long_press_empty_and_recover_trash_test.dart │ │ ├── mark_single_selected_email_as_read_test.dart │ │ ├── mark_single_selected_email_as_spam_test.dart │ │ ├── mark_single_selected_email_as_star_test.dart │ │ ├── create_rename_move_and_delete_mailbox_test.dart │ │ ├── display_empty_view_for_favorite_folder_test.dart │ │ └── move_folder_content_test.dart │ ├── web_socket │ │ └── web_socket_test.dart │ ├── search │ │ ├── search_result_highlights_test.dart │ │ ├── search_suggestion_highlights_test.dart │ │ ├── search_email_with_sort_order_test.dart │ │ └── search_snippets_with_html_escape_test.dart │ ├── email_detailed │ │ ├── view_inline_image_test.dart │ │ ├── export_attachment_test.dart │ │ ├── delete_email_test.dart │ │ ├── archive_email_test.dart │ │ ├── mark_as_spam_email_test.dart │ │ ├── deformed_inlined_image_test.dart │ │ ├── display_email_with_short_content_test.dart │ │ ├── mark_as_star_email_test.dart │ │ ├── display_email_with_xss_content_test.dart │ │ └── mark_as_unread_email_test.dart │ ├── attachments │ │ ├── download_all_attachments_test.dart │ │ └── no_disposition_inline_test.dart │ ├── thread_detail │ │ └── thread_detail_reply_real_time_update_test.dart │ └── setting │ │ ├── identity │ │ └── select_identity_as_default_test.dart │ │ └── language │ │ └── change_language_test.dart └── robots │ ├── app_grid_robot.dart │ └── identities_list_menu_robot.dart ├── docs ├── user-guide │ ├── images │ │ ├── main.png │ │ ├── oidc.png │ │ ├── open.png │ │ ├── read.png │ │ ├── action1.png │ │ ├── action2.png │ │ ├── action3.png │ │ ├── filters.png │ │ ├── folders.png │ │ ├── auth-mobile-1.jpg │ │ ├── auth-mobile-2.jpg │ │ ├── create-folder.png │ │ ├── folder-search.png │ │ ├── main-mobile-2.jpg │ │ ├── main-mobile.jpg │ │ ├── quick-search.png │ │ ├── advanced-search.png │ │ ├── folder-actions.png │ │ └── read-receipt-open.png │ └── build.sh ├── images │ ├── after-flutter-3.22.png │ ├── before-flutter-3.22.png │ └── handle_task_with_isolate.png └── configuration │ ├── ws_echo_ping_configuration.md │ └── cozy_integration_configuration.md ├── backend-docker ├── jmap.properties ├── listeners.xml └── deletedMessageVault.properties ├── configurations └── env.fcm ├── test ├── fixtures │ └── state_fixtures.dart └── features │ └── offline_mode │ └── mailbox_state_worker_queue.dart ├── .metadata └── env.file /lib/l10n/intl_bn.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_bo.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_ca.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_cs.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_et.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_eu.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_fa.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_gl.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_he.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_hi.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_hr.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_hu.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_ie.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_ja.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_lt.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_nl.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_pl.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_ro.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_si.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_sk.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_sl.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_sr.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_sv.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_th.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_tr.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_pt_PT.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /lib/l10n/intl_zh_Hant.arb: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /core/README.md: -------------------------------------------------------------------------------- 1 | # core 2 | 3 | Core Module -------------------------------------------------------------------------------- /fcm/README.md: -------------------------------------------------------------------------------- 1 | # fcm 2 | 3 | TwakeMail FCM extension -------------------------------------------------------------------------------- /contact/README.md: -------------------------------------------------------------------------------- 1 | # contact 2 | 3 | TMail Contact extension -------------------------------------------------------------------------------- /forward/README.md: -------------------------------------------------------------------------------- 1 | # forward 2 | 3 | TMail Forward extension -------------------------------------------------------------------------------- /cozy/README.md: -------------------------------------------------------------------------------- 1 | # cozy 2 | 3 | Cozy config for Cozy integration 4 | -------------------------------------------------------------------------------- /model/README.md: -------------------------------------------------------------------------------- 1 | # model 2 | 3 | A model module contains entities -------------------------------------------------------------------------------- /android/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /ios/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /model/lib/mailbox/expand_mode.dart: -------------------------------------------------------------------------------- 1 | enum ExpandMode { COLLAPSE, EXPAND } -------------------------------------------------------------------------------- /model/lib/mailbox/select_mode.dart: -------------------------------------------------------------------------------- 1 | enum SelectMode { ACTIVE, INACTIVE } -------------------------------------------------------------------------------- /rule_filter/README.md: -------------------------------------------------------------------------------- 1 | # rule filter 2 | 3 | TMail Rule Filter extension -------------------------------------------------------------------------------- /cozy/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /email_recovery/README.md: -------------------------------------------------------------------------------- 1 | # email recovery 2 | 3 | TMail Email Recovery extension -------------------------------------------------------------------------------- /lib/main/universal_import/html_web.dart: -------------------------------------------------------------------------------- 1 | export 'package:universal_html/html.dart'; -------------------------------------------------------------------------------- /lib/main/universal_import/html_io.dart: -------------------------------------------------------------------------------- 1 | export 'package:universal_html/src/html.dart'; -------------------------------------------------------------------------------- /server_settings/README.md: -------------------------------------------------------------------------------- 1 | # server_settings 2 | 3 | TMail Server settings extension 4 | -------------------------------------------------------------------------------- /model/lib/account/account_type.dart: -------------------------------------------------------------------------------- 1 | 2 | enum AccountType { 3 | oauth, 4 | email 5 | } -------------------------------------------------------------------------------- /scripts/build-dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -eux 4 | bundle exec fastlane dev 5 | -------------------------------------------------------------------------------- /android/fastlane/Appfile: -------------------------------------------------------------------------------- 1 | package_name("com.linagora.android.teammail") # e.g. com.krausefx.app 2 | -------------------------------------------------------------------------------- /model/lib/email/email_in_thread_status.dart: -------------------------------------------------------------------------------- 1 | enum EmailInThreadStatus { collapsed, expanded } 2 | -------------------------------------------------------------------------------- /scripts/build-release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -eux 4 | bundle exec fastlane release 5 | -------------------------------------------------------------------------------- /lib/features/base/state/banner_state.dart: -------------------------------------------------------------------------------- 1 | 2 | enum BannerState { 3 | enabled, 4 | disabled; 5 | } -------------------------------------------------------------------------------- /lib/features/email/domain/model/move_action.dart: -------------------------------------------------------------------------------- 1 | 2 | enum MoveAction { 3 | moving, 4 | undo 5 | } -------------------------------------------------------------------------------- /lib/main/exceptions/isolate_exception.dart: -------------------------------------------------------------------------------- 1 | class CanNotGetRootIsolateToken implements Exception {} 2 | -------------------------------------------------------------------------------- /lib/main/universal_import/html_stub.dart: -------------------------------------------------------------------------------- 1 | export 'html_io.dart' if (dart.library.html) 'html_web.dart'; -------------------------------------------------------------------------------- /model/lib/email/mark_star_action.dart: -------------------------------------------------------------------------------- 1 | 2 | enum MarkStarAction { 3 | markStar, 4 | unMarkStar 5 | } -------------------------------------------------------------------------------- /model/lib/email/read_actions.dart: -------------------------------------------------------------------------------- 1 | 2 | enum ReadActions { 3 | markAsRead, 4 | markAsUnread 5 | } -------------------------------------------------------------------------------- /model/lib/mailbox/mailbox_state.dart: -------------------------------------------------------------------------------- 1 | 2 | enum MailboxState { 3 | activated, 4 | deactivated 5 | } -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/icons/Icon-512.png -------------------------------------------------------------------------------- /assets/icons/icon_twp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/icons/icon_twp.png -------------------------------------------------------------------------------- /lib/features/push_notification/domain/model/web_socket_action.dart: -------------------------------------------------------------------------------- 1 | enum WebSocketAction {connect, disconnect} -------------------------------------------------------------------------------- /scripts/setup-firebase.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | echo "$FIREBASE_ENV" > ./configurations/env.fcm 4 | -------------------------------------------------------------------------------- /integration_test/exceptions/mailbox/null_quota_exception.dart: -------------------------------------------------------------------------------- 1 | class NullQuotaException implements Exception {} -------------------------------------------------------------------------------- /lib/features/login/presentation/model/login_navigate_type.dart: -------------------------------------------------------------------------------- 1 | enum LoginNavigateType { 2 | autoSignIn 3 | } -------------------------------------------------------------------------------- /lib/features/thread/presentation/model/search_status.dart: -------------------------------------------------------------------------------- 1 | 2 | enum SearchStatus { 3 | ACTIVE, INACTIVE 4 | } -------------------------------------------------------------------------------- /lib/main/deep_links/deep_link_action_type.dart: -------------------------------------------------------------------------------- 1 | 2 | enum DeepLinkActionType { 3 | openApp, 4 | unknown; 5 | } -------------------------------------------------------------------------------- /model/lib/account/authentication_type.dart: -------------------------------------------------------------------------------- 1 | enum AuthenticationType { 2 | basic, 3 | oidc, 4 | none; 5 | } -------------------------------------------------------------------------------- /model/lib/error_type_handler/unknown_uri_exception.dart: -------------------------------------------------------------------------------- 1 | class UnknownUriException implements Exception {} 2 | -------------------------------------------------------------------------------- /web/splash/img/icon_twp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/splash/img/icon_twp.png -------------------------------------------------------------------------------- /assets/icons/icon_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/icons/icon_android.png -------------------------------------------------------------------------------- /assets/icons/icon_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/icons/icon_launcher.png -------------------------------------------------------------------------------- /assets/icons/icon_logo_ios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/icons/icon_logo_ios.png -------------------------------------------------------------------------------- /core/lib/utils/web_renderer/canvas_kit.dart: -------------------------------------------------------------------------------- 1 | export 'canvas_kit_stub.dart' if (dart.library.html) 'canvas_kit_web.dart'; -------------------------------------------------------------------------------- /lib/features/upload/domain/exceptions/pick_file_exception.dart: -------------------------------------------------------------------------------- 1 | class PickFileCanceledException implements Exception {} -------------------------------------------------------------------------------- /lib/features/upload/domain/exceptions/upload_exception.dart: -------------------------------------------------------------------------------- 1 | class DataResponseIsNullException implements Exception {} -------------------------------------------------------------------------------- /model/lib/email/email_content_type.dart: -------------------------------------------------------------------------------- 1 | 2 | enum EmailContentType { 3 | textHtml, 4 | textPlain, 5 | other 6 | } -------------------------------------------------------------------------------- /model/lib/error_type_handler/account_exception.dart: -------------------------------------------------------------------------------- 1 | 2 | class NotFoundPersonalAccountException implements Exception {} -------------------------------------------------------------------------------- /model/lib/error_type_handler/unknown_address_exception.dart: -------------------------------------------------------------------------------- 1 | class UnknownAddressException implements Exception {} 2 | -------------------------------------------------------------------------------- /scripts/setup-ios.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -eux 4 | 5 | flutter pub get 6 | pod install && pod update 7 | -------------------------------------------------------------------------------- /docs/user-guide/images/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/main.png -------------------------------------------------------------------------------- /docs/user-guide/images/oidc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/oidc.png -------------------------------------------------------------------------------- /docs/user-guide/images/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/open.png -------------------------------------------------------------------------------- /docs/user-guide/images/read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/read.png -------------------------------------------------------------------------------- /lib/features/base/shortcut/search/search_action_shortcut_type.dart: -------------------------------------------------------------------------------- 1 | 2 | enum SearchActionShortcutType { 3 | unFocus; 4 | } -------------------------------------------------------------------------------- /lib/features/caching/config/cache_version.dart: -------------------------------------------------------------------------------- 1 | 2 | class CacheVersion { 3 | static const int hiveDBVersion = 21; 4 | } -------------------------------------------------------------------------------- /lib/features/caching/exceptions/local_storage_exception.dart: -------------------------------------------------------------------------------- 1 | class NotFoundDataWithThisKeyException implements Exception {} -------------------------------------------------------------------------------- /lib/features/composer/presentation/model/code_view_state.dart: -------------------------------------------------------------------------------- 1 | 2 | enum CodeViewState { 3 | enabled, 4 | disabled 5 | } -------------------------------------------------------------------------------- /lib/features/email/domain/model/mark_read_action.dart: -------------------------------------------------------------------------------- 1 | enum MarkReadAction { 2 | tap, 3 | swipeOnThread, 4 | undo 5 | } -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/presentation/model/loader_status.dart: -------------------------------------------------------------------------------- 1 | enum LoaderStatus { idle, loading, completed } 2 | -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /assets/fonts/Inter/Inter-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/Inter/Inter-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter/Inter-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/Inter/Inter-Medium.ttf -------------------------------------------------------------------------------- /assets/icons/icon_twp_android12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/icons/icon_twp_android12.png -------------------------------------------------------------------------------- /docs/images/after-flutter-3.22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/images/after-flutter-3.22.png -------------------------------------------------------------------------------- /docs/images/before-flutter-3.22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/images/before-flutter-3.22.png -------------------------------------------------------------------------------- /docs/user-guide/images/action1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/action1.png -------------------------------------------------------------------------------- /docs/user-guide/images/action2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/action2.png -------------------------------------------------------------------------------- /docs/user-guide/images/action3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/action3.png -------------------------------------------------------------------------------- /docs/user-guide/images/filters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/filters.png -------------------------------------------------------------------------------- /docs/user-guide/images/folders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/folders.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /lib/features/download/domain/model/download_source_view.dart: -------------------------------------------------------------------------------- 1 | enum DownloadSourceView { 2 | emailView, 3 | composerView; 4 | } -------------------------------------------------------------------------------- /lib/features/login/domain/exceptions/logout_exception.dart: -------------------------------------------------------------------------------- 1 | class UserCancelledLogoutOIDCFlowException implements Exception {} -------------------------------------------------------------------------------- /lib/features/mailbox/domain/model/mailbox_subscribe_state.dart: -------------------------------------------------------------------------------- 1 | enum MailboxSubscribeState { 2 | enabled, 3 | disabled 4 | } -------------------------------------------------------------------------------- /lib/features/manage_account/presentation/model/reading_pane.dart: -------------------------------------------------------------------------------- 1 | 2 | enum ReadingPane { 3 | noSplit, 4 | rightOfInbox, 5 | } -------------------------------------------------------------------------------- /lib/features/thread/domain/exceptions/thread_exceptions.dart: -------------------------------------------------------------------------------- 1 | 2 | class NotFoundEmailsDeletedException implements Exception {} -------------------------------------------------------------------------------- /web/worker_service/img/tmail-1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/worker_service/img/tmail-1x.png -------------------------------------------------------------------------------- /web/worker_service/img/tmail-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/worker_service/img/tmail-2x.png -------------------------------------------------------------------------------- /web/worker_service/img/tmail-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/worker_service/img/tmail-3x.png -------------------------------------------------------------------------------- /web/worker_service/img/tmail-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/worker_service/img/tmail-4x.png -------------------------------------------------------------------------------- /assets/fonts/Inter/Inter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/Inter/Inter-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter/Inter-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/Inter/Inter-SemiBold.ttf -------------------------------------------------------------------------------- /lib/features/base/before_reconnect_handler.dart: -------------------------------------------------------------------------------- 1 | abstract class BeforeReconnectHandler { 2 | Future onBeforeReconnect(); 3 | } -------------------------------------------------------------------------------- /lib/features/base/shortcut/composer/composer_action_shortcut_type.dart: -------------------------------------------------------------------------------- 1 | 2 | enum ComposerActionShortcutType { 3 | closeView; 4 | } -------------------------------------------------------------------------------- /lib/features/manage_account/presentation/model/settings_page_level.dart: -------------------------------------------------------------------------------- 1 | enum SettingsPageLevel { 2 | universal, 3 | level1, 4 | } -------------------------------------------------------------------------------- /assets/fonts/fallback/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/Roboto-Regular.ttf -------------------------------------------------------------------------------- /docs/images/handle_task_with_isolate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/images/handle_task_with_isolate.png -------------------------------------------------------------------------------- /docs/user-guide/images/auth-mobile-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/auth-mobile-1.jpg -------------------------------------------------------------------------------- /docs/user-guide/images/auth-mobile-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/auth-mobile-2.jpg -------------------------------------------------------------------------------- /docs/user-guide/images/create-folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/create-folder.png -------------------------------------------------------------------------------- /docs/user-guide/images/folder-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/folder-search.png -------------------------------------------------------------------------------- /docs/user-guide/images/main-mobile-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/main-mobile-2.jpg -------------------------------------------------------------------------------- /docs/user-guide/images/main-mobile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/main-mobile.jpg -------------------------------------------------------------------------------- /docs/user-guide/images/quick-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/quick-search.png -------------------------------------------------------------------------------- /integration_test/exceptions/mailbox/null_inbox_unread_count_exception.dart: -------------------------------------------------------------------------------- 1 | class NullInboxUnreadCountException implements Exception {} 2 | -------------------------------------------------------------------------------- /lib/features/composer/presentation/model/dropdown_menu_font_status.dart: -------------------------------------------------------------------------------- 1 | 2 | enum DropdownMenuFontStatus { 3 | open, 4 | closed 5 | } -------------------------------------------------------------------------------- /lib/features/composer/presentation/model/prefix_recipient_state.dart: -------------------------------------------------------------------------------- 1 | 2 | enum PrefixRecipientState { 3 | enabled, 4 | disabled 5 | } -------------------------------------------------------------------------------- /lib/features/mailbox/domain/model/mailbox_subaddressing_action.dart: -------------------------------------------------------------------------------- 1 | enum MailboxSubaddressingAction { 2 | allow, 3 | disallow, 4 | } -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/presentation/model/draggable_app_state.dart: -------------------------------------------------------------------------------- 1 | 2 | enum DraggableAppState { 3 | active, 4 | inActive 5 | } -------------------------------------------------------------------------------- /lib/features/manage_account/domain/exceptions/rule_filter_exception.dart: -------------------------------------------------------------------------------- 1 | 2 | class RuleFilterNotBindingException implements Exception {} -------------------------------------------------------------------------------- /lib/features/thread_detail/domain/exceptions/empty_thread_detail_exception.dart: -------------------------------------------------------------------------------- 1 | class EmptyThreadDetailException implements Exception {} -------------------------------------------------------------------------------- /model/lib/email/prefix_email_address.dart: -------------------------------------------------------------------------------- 1 | 2 | enum PrefixEmailAddress { 3 | from, 4 | to, 5 | cc, 6 | bcc, 7 | replyTo 8 | } -------------------------------------------------------------------------------- /web/i18n/vi.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Tải ứng dụng Twake Mail", 3 | "description": "Nhanh hơn và thuận tiện hơn", 4 | "open": "Mở" 5 | } -------------------------------------------------------------------------------- /web/worker_service/img/ic-close-1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/worker_service/img/ic-close-1x.png -------------------------------------------------------------------------------- /web/worker_service/img/ic-close-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/worker_service/img/ic-close-2x.png -------------------------------------------------------------------------------- /web/worker_service/img/ic-close-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/worker_service/img/ic-close-3x.png -------------------------------------------------------------------------------- /web/worker_service/img/ic-close-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/web/worker_service/img/ic-close-4x.png -------------------------------------------------------------------------------- /assets/fonts/fallback/NotoSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/NotoSans-Regular.ttf -------------------------------------------------------------------------------- /docs/user-guide/images/advanced-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/advanced-search.png -------------------------------------------------------------------------------- /docs/user-guide/images/folder-actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/folder-actions.png -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Runner/vi.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | "newMessageInTwakeMail" = "Bạn có email mới"; 2 | "newNotificationInTwakeMail" = "Bạn có thông báo mới"; -------------------------------------------------------------------------------- /lib/features/composer/presentation/model/formatting_options_state.dart: -------------------------------------------------------------------------------- 1 | 2 | enum FormattingOptionsState { 3 | enabled, 4 | disabled 5 | } -------------------------------------------------------------------------------- /lib/features/thread_detail/domain/exceptions/thread_detail_overload_exception.dart: -------------------------------------------------------------------------------- 1 | class ThreadDetailOverloadException implements Exception {} -------------------------------------------------------------------------------- /lib/features/thread_detail/presentation/model/thread_detail_setting_status.dart: -------------------------------------------------------------------------------- 1 | enum ThreadDetailSettingStatus { loading, enabled, disabled } -------------------------------------------------------------------------------- /lib/main/routes/router_arguments.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class RouterArguments with EquatableMixin {} -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper 2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/gradle/wrapper/gradle-wrapper 2.jar -------------------------------------------------------------------------------- /assets/fonts/fallback/NotoEmoji-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/NotoEmoji-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/fallback/NotoSansKR-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/NotoSansKR-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/fallback/NotoSansSC-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/NotoSansSC-Regular.ttf -------------------------------------------------------------------------------- /core/lib/data/model/source_type/data_source_type.dart: -------------------------------------------------------------------------------- 1 | 2 | enum DataSourceType { 3 | network, 4 | local, 5 | session, 6 | hiveCache; 7 | } -------------------------------------------------------------------------------- /cozy/lib/cozy_config_manager/cozy_config_manager.dart: -------------------------------------------------------------------------------- 1 | export 'cozy_config_manager_stub.dart' if (dart.library.html) 'cozy_config_manager_web.dart'; -------------------------------------------------------------------------------- /docs/user-guide/images/read-receipt-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/docs/user-guide/images/read-receipt-open.png -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /lib/features/composer/domain/model/contact_suggestion_source.dart: -------------------------------------------------------------------------------- 1 | 2 | enum ContactSuggestionSource { 3 | all, tMailContact, deviceContact 4 | } -------------------------------------------------------------------------------- /lib/features/composer/presentation/model/compose_action_mode.dart: -------------------------------------------------------------------------------- 1 | 2 | enum ComposeActionMode { 3 | pushQueue, 4 | editQueue, 5 | sent 6 | } -------------------------------------------------------------------------------- /lib/features/login/domain/extensions/uri_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | extension UriExtension on Uri { 3 | bool isBaseUrlValid() => origin.isNotEmpty; 4 | } -------------------------------------------------------------------------------- /lib/features/search/email/presentation/model/search_more_state.dart: -------------------------------------------------------------------------------- 1 | 2 | enum SearchMoreState { 3 | idle, 4 | waiting, 5 | completed; 6 | } -------------------------------------------------------------------------------- /lib/main/exceptions/exception_thrower.dart: -------------------------------------------------------------------------------- 1 | 2 | abstract class ExceptionThrower { 3 | throwException(dynamic error, dynamic stackTrace); 4 | } 5 | -------------------------------------------------------------------------------- /model/lib/mixin/search_snippet_mixin.dart: -------------------------------------------------------------------------------- 1 | mixin SearchSnippetMixin { 2 | String? searchSnippetSubject; 3 | String? searchSnippetPreview; 4 | } -------------------------------------------------------------------------------- /web/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Download Twake Mail application", 3 | "description": "Faster and more convenient", 4 | "open": "Open" 5 | } -------------------------------------------------------------------------------- /android/app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /assets/fonts/fallback/NotoSansMath-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/NotoSansMath-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/fallback/NotoSansTamil-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/NotoSansTamil-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/fallback/NotoSansThai-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/NotoSansThai-Regular.ttf -------------------------------------------------------------------------------- /ios/Runner/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | "newMessageInTwakeMail" = "You have new emails"; 2 | "newNotificationInTwakeMail" = "You have a new notification"; -------------------------------------------------------------------------------- /ios/TeamMailShareExtension/ShareViewController.swift: -------------------------------------------------------------------------------- 1 | import receive_sharing_intent 2 | 3 | class ShareViewController: RSIShareViewController { 4 | } 5 | -------------------------------------------------------------------------------- /lib/features/base/isolate/background_isolate_binary_messenger/background_isolate_binary_messenger_mobile.dart: -------------------------------------------------------------------------------- 1 | 2 | export 'package:flutter/services.dart'; -------------------------------------------------------------------------------- /web/i18n/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Lade die Twake Mail-App herunter.", 3 | "description": "Schneller und bequemer", 4 | "open": "Öffnen" 5 | } 6 | -------------------------------------------------------------------------------- /web/i18n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Télécharger l’application Twake Mail", 3 | "description": "Plus rapide et pratique", 4 | "open": "Ouvrir" 5 | } -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/drawable/background.png -------------------------------------------------------------------------------- /assets/fonts/fallback/NotoSansArabic-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/NotoSansArabic-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/fallback/NotoSansSymbols-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/NotoSansSymbols-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/fallback/NotoSansSymbols2-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/NotoSansSymbols2-Regular.ttf -------------------------------------------------------------------------------- /lib/features/email/presentation/model/page_view_navigator_state.dart: -------------------------------------------------------------------------------- 1 | enum PageViewNavigatorState { 2 | all, 3 | previous, 4 | next, 5 | none, 6 | } -------------------------------------------------------------------------------- /lib/features/identity_creator/presentation/extesions/size_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | extension SizeExtension on int { 3 | 4 | int get toBytes => this * 1024; 5 | } -------------------------------------------------------------------------------- /lib/features/login/data/utils/library_platform/app_auth_plugin/app_auth_web_plugin.dart: -------------------------------------------------------------------------------- 1 | 2 | export 'package:flutter_appauth_web/flutter_appauth_web.dart'; -------------------------------------------------------------------------------- /lib/features/mailbox/presentation/model/mailbox_displayed.dart: -------------------------------------------------------------------------------- 1 | 2 | enum MailboxDisplayed { 3 | mailbox, 4 | destinationPicker, 5 | modalFolder; 6 | } -------------------------------------------------------------------------------- /lib/features/mailbox/presentation/styles/mailbox_icon_widget_styles.dart: -------------------------------------------------------------------------------- 1 | 2 | class MailboxIconWidgetStyles { 3 | static const double iconSize = 20.0; 4 | } -------------------------------------------------------------------------------- /lib/features/manage_account/data/datasource/trace_log_datasource.dart: -------------------------------------------------------------------------------- 1 | 2 | abstract class TraceLogDataSource { 3 | Future exportTraceLog(); 4 | } -------------------------------------------------------------------------------- /lib/features/manage_account/data/repository/trace_log_repository.dart: -------------------------------------------------------------------------------- 1 | 2 | abstract class TraceLogRepository { 3 | Future exportTraceLog(); 4 | } -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/drawable-v21/background.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/66.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/66.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/92.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/92.png -------------------------------------------------------------------------------- /ios/TwakeCore/Network/Model/AuthenticationType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum AuthenticationType: String, Codable { 4 | case basic, oidc, none 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/caching/interaction/cache_manager_interaction.dart: -------------------------------------------------------------------------------- 1 | 2 | abstract class CacheManagerInteraction { 3 | Future migrateHiveToIsolatedHive(); 4 | } -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/102.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/102.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png -------------------------------------------------------------------------------- /ios/Runner/ru.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | "newMessageInTwakeMail" = "У вас есть новые электронные письма"; 2 | "newNotificationInTwakeMail" = "У вас новое объявление"; -------------------------------------------------------------------------------- /lib/features/base/upgradeable/upgrade_database_steps.dart: -------------------------------------------------------------------------------- 1 | 2 | abstract class UpgradeDatabaseSteps { 3 | Future onUpgrade(int oldVersion, int newVersion); 4 | } -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/raw/keep.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /core/lib/presentation/extensions/compare_string_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | extension CompareStringExtension on String? { 3 | bool isSame(String? value) => this == value; 4 | } -------------------------------------------------------------------------------- /ios/Runner/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | "newMessageInTwakeMail" = "Vous avez de nouveaux e-mails"; 2 | "newNotificationInTwakeMail" = "Vous avez une nouvelle notification"; -------------------------------------------------------------------------------- /ios/TwakeCore/Jmap/Model/Email/EmailAddress.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct EmailAddress: Codable { 4 | let name: String? 5 | let email: String? 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/notification_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/drawable-hdpi/notification_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/notification_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/drawable-mdpi/notification_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_large_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/drawable/ic_large_notification.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /core/lib/utils/html/js_interop_stub.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | extension Uint8ListExtension on Uint8List { 4 | dynamic get toJS => throw UnimplementedError(); 5 | } -------------------------------------------------------------------------------- /email_recovery/lib/email_recovery/email_recovery_status.dart.dart: -------------------------------------------------------------------------------- 1 | enum EmailRecoveryStatus { 2 | waiting, 3 | inProgress, 4 | completed, 5 | failed, 6 | canceled, 7 | } -------------------------------------------------------------------------------- /lib/features/login/data/utils/library_platform/app_auth_plugin/app_auth_plugin.dart: -------------------------------------------------------------------------------- 1 | 2 | export 'app_auth_mobile_plugin.dart' if (dart.library.html) 'app_auth_web_plugin.dart'; -------------------------------------------------------------------------------- /lib/features/push_notification/data/model/web_socket_request.dart: -------------------------------------------------------------------------------- 1 | abstract class WebSocketRequest { 2 | const WebSocketRequest(); 3 | 4 | Map toJson(); 5 | } -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/notification_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/drawable-xhdpi/notification_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/notification_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/drawable-xxhdpi/notification_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /assets/fonts/fallback/NotoSansEgyptianHieroglyphs-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/assets/fonts/fallback/NotoSansEgyptianHieroglyphs-Regular.ttf -------------------------------------------------------------------------------- /forward/lib/forward/forward.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class Forward with EquatableMixin { 4 | @override 5 | List get props => []; 6 | } -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /lib/features/login/presentation/login_form_type.dart: -------------------------------------------------------------------------------- 1 | enum LoginFormType { 2 | none, 3 | retry, 4 | baseUrlForm, 5 | credentialForm, 6 | passwordForm, 7 | dnsLookupForm; 8 | } -------------------------------------------------------------------------------- /lib/features/quotas/domain/exceptions/quotas_exception.dart: -------------------------------------------------------------------------------- 1 | class NotFoundQuotasException implements Exception {} 2 | 3 | class QuotasNotSupportedException implements Exception {} 4 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /model/lib/mailbox/mailbox_constants.dart: -------------------------------------------------------------------------------- 1 | const String anyoneIdentifier = 'anyone'; 2 | const String postingRight = 'p'; 3 | const String subaddressingSupported = "subaddressingSupported"; 4 | -------------------------------------------------------------------------------- /rule_filter/lib/rule_filter/rule.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class Rule with EquatableMixin { 4 | @override 5 | List get props => []; 6 | } -------------------------------------------------------------------------------- /assets/images/ic_unread_status.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/ic_unselected.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /backend-docker/jmap.properties: -------------------------------------------------------------------------------- 1 | authentication.strategy.rfc8621=BasicAuthenticationStrategy,com.linagora.tmail.james.jmap.ticket.TicketAuthenticationStrategy 2 | url.prefix= 3 | websocket.url.prefix= -------------------------------------------------------------------------------- /contact/lib/contact/model/contact.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class Contact with EquatableMixin { 5 | @override 6 | List get props => []; 7 | } -------------------------------------------------------------------------------- /core/lib/utils/web_renderer/canvas_kit_stub.dart: -------------------------------------------------------------------------------- 1 | /// Whether the CanvasKit renderer is being used on web. 2 | /// 3 | /// Always returns `false` on non-web. 4 | bool get isRendererCanvasKit => false; -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linagora/tmail-flutter/HEAD/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@3x.png -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/presentation/model/dashboard_routes.dart: -------------------------------------------------------------------------------- 1 | 2 | enum DashboardRoutes { 3 | thread, 4 | threadDetailed, 5 | searchEmail, 6 | waiting, 7 | sendingQueue; 8 | } -------------------------------------------------------------------------------- /lib/l10n/intl_ko.arb: -------------------------------------------------------------------------------- 1 | { 2 | "initializing_data": "데이터 초기화...", 3 | "@initializing_data": { 4 | "type": "text", 5 | "placeholders_order": [], 6 | "placeholders": {} 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /core/lib/presentation/utils/icon_utils.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:core/utils/platform_info.dart'; 3 | 4 | class IconUtils { 5 | static double defaultIconSize = PlatformInfo.isWeb ? 20.0 : 24.0; 6 | } -------------------------------------------------------------------------------- /lib/features/base/state/base_ui_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/success.dart'; 2 | 3 | abstract class BaseUIState extends UIState {} 4 | 5 | class UIClosedState extends BaseUIState {} -------------------------------------------------------------------------------- /lib/features/composer/domain/exceptions/compose_email_exception.dart: -------------------------------------------------------------------------------- 1 | class SendingEmailCanceledException implements Exception {} 2 | 3 | class SavingEmailToDraftsCanceledException implements Exception {} -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/domain/exceptions/linagora_ecosystem_exceptions.dart: -------------------------------------------------------------------------------- 1 | 2 | class NotFoundLinagoraEcosystem implements Exception {} 3 | 4 | class NotFoundPaywallUrl implements Exception {} -------------------------------------------------------------------------------- /lib/l10n/intl_pt.arb: -------------------------------------------------------------------------------- 1 | { 2 | "initializing_data": "A inicializar…", 3 | "@initializing_data": { 4 | "type": "text", 5 | "placeholders_order": [], 6 | "placeholders": {} 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /scripts/build-web.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -eux 4 | 5 | # Build web in release mode (lightweight, optimized) 6 | flutter build web --release --base-href "/${GITHUB_REPOSITORY##*/}/$FOLDER/" 7 | -------------------------------------------------------------------------------- /scripts/setup-android.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | echo "$PLAY_STORE_UPLOAD_KEY_BASE64" | base64 --decode > app/keystore.jks 4 | echo "$PLAY_STORE_KEY_INFO_BASE64" | base64 --decode > key.properties 5 | -------------------------------------------------------------------------------- /ios/TwakeMailNSE/Model/TypeName.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum TypeName: String { 4 | case mailbox = "Mailbox" 5 | case email = "Email" 6 | case emailDelivery = "EmailDelivery" 7 | } 8 | -------------------------------------------------------------------------------- /lib/features/mailbox/domain/exceptions/set_mailbox_method_exception.dart: -------------------------------------------------------------------------------- 1 | class NotFoundMailboxCreatedException implements Exception {} 2 | 3 | class NotFoundMailboxUpdatedRoleException implements Exception {} -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/presentation/styles/navigation_bar_style.dart: -------------------------------------------------------------------------------- 1 | 2 | class NavigationBarStyle { 3 | static const double barHeight = 80; 4 | static const double horizontalMargin = 30; 5 | } -------------------------------------------------------------------------------- /lib/features/sending_queue/data/exceptions/sending_queue_exceptions.dart: -------------------------------------------------------------------------------- 1 | 2 | class NotFoundSendingEmailHiveObject implements Exception {} 3 | 4 | class ExistSendingEmailHiveObject implements Exception {} -------------------------------------------------------------------------------- /model/lib/extensions/account_id_extensions.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/account_id.dart'; 3 | 4 | extension AccountIdExtension on AccountId { 5 | String get asString => id.value; 6 | } -------------------------------------------------------------------------------- /backend-docker/listeners.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | org.apache.james.vault.DeletedMessageVaultHook 6 | 7 | 8 | -------------------------------------------------------------------------------- /core/lib/presentation/extensions/list_nullable_extensions.dart: -------------------------------------------------------------------------------- 1 | 2 | extension ListNullableExtensions on List? { 3 | bool get validateFilesTransfer => this?.any((type) => type == 'Files') ?? false; 4 | } -------------------------------------------------------------------------------- /ios/TwakeCore/Network/Model/Authentication.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol Authentication { 4 | var type: AuthenticationType { get } 5 | 6 | func getAuthenticationHeader() -> String 7 | } 8 | -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/domain/linagora_ecosystem/linagora_ecosystem_properties.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class LinagoraEcosystemProperties with EquatableMixin {} -------------------------------------------------------------------------------- /lib/features/thread/presentation/model/loading_more_status.dart: -------------------------------------------------------------------------------- 1 | 2 | enum LoadingMoreStatus { 3 | idle, 4 | running, 5 | completed; 6 | 7 | bool get isRunning => this == LoadingMoreStatus.running; 8 | } -------------------------------------------------------------------------------- /lib/features/login/domain/model/login_constants.dart: -------------------------------------------------------------------------------- 1 | 2 | class LoginConstants { 3 | static const String KEY_BASE_URL = 'KEY_BASE_URL'; 4 | static const String AUTH_DESTINATION_KEY = "auth_destination_url"; 5 | } -------------------------------------------------------------------------------- /model/lib/extensions/identity_id_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/identities/identity.dart'; 3 | 4 | extension IdentityIdExtension on IdentityId { 5 | String get asString => id.value; 6 | } -------------------------------------------------------------------------------- /server_settings/lib/server_settings/server_settings.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class ServerSettings with EquatableMixin { 4 | @override 5 | List get props => []; 6 | } -------------------------------------------------------------------------------- /assets/images/ic_download.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ios/fastlane/Appfile: -------------------------------------------------------------------------------- 1 | app_identifier("com.linagora.ios.teammail") # The bundle identifier of your app 2 | 3 | 4 | # For more information about the Appfile, see: 5 | # https://docs.fastlane.tools/advanced/#appfile 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000000 4 | #007AFF 5 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/features/email/presentation/utils/smime_signature_constant.dart: -------------------------------------------------------------------------------- 1 | 2 | class SMimeSignatureConstant { 3 | static const String GOOD_SIGNATURE = 'Good signature'; 4 | static const String BAD_SIGNATURE = 'Bad signature'; 5 | } -------------------------------------------------------------------------------- /forward/lib/forward/capability_forward.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; 2 | 3 | final capabilityForward = CapabilityIdentifier(Uri.parse('com:linagora:params:jmap:forward')); -------------------------------------------------------------------------------- /ios/TwakeCore/Network/Model/TokenOidc.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct TokenOidc: Codable { 4 | let token: String 5 | let tokenId: String? 6 | let expiredTime: String? 7 | let refreshToken: String 8 | } 9 | -------------------------------------------------------------------------------- /lib/features/caching/clients/cache_version_client.dart: -------------------------------------------------------------------------------- 1 | 2 | abstract class CacheVersionClient { 3 | 4 | String get versionKey; 5 | 6 | Future storeVersion(int newVersion); 7 | 8 | Future getLatestVersion(); 9 | } -------------------------------------------------------------------------------- /core/lib/presentation/utils/style_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CommonTextStyle { 4 | static const defaultTextOverFlow = TextOverflow.ellipsis; 5 | 6 | static const defaultSoftWrap = true; 7 | } -------------------------------------------------------------------------------- /lib/features/push_notification/domain/utils/fcm_constants.dart: -------------------------------------------------------------------------------- 1 | 2 | class FcmConstants { 3 | static const String firebaseRegistrationExpiredTimeProperty = 'expires'; 4 | 5 | static const int MAX_NUMBER_NEW_EMAILS_RETRIEVED = 5; 6 | } -------------------------------------------------------------------------------- /assets/images/ic_arrow_back.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /core/lib/utils/config/app_config_parser.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/services.dart'; 4 | 5 | abstract class AppConfigParser { 6 | Future parse(String value); 7 | Future parseData(ByteData data); 8 | } -------------------------------------------------------------------------------- /core/lib/utils/double_convert.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | class DoubleConvert { 4 | static double bytesToGigaBytes(num bytes) { 5 | return double.tryParse((bytes * 9.31 * pow(10, -10)).toStringAsFixed(2)) ?? 0; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /lib/features/composer/data/datasource/contact_datasource.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:model/model.dart'; 3 | 4 | abstract class ContactDataSource { 5 | Future> getContactSuggestions(AutoCompletePattern autoCompletePattern); 6 | } -------------------------------------------------------------------------------- /lib/features/composer/presentation/model/screen_display_mode.dart: -------------------------------------------------------------------------------- 1 | 2 | enum ScreenDisplayMode { 3 | fullScreen, 4 | minimize, 5 | normal, 6 | hidden; 7 | 8 | bool isNotContentVisible() => this == minimize || this == hidden; 9 | } -------------------------------------------------------------------------------- /lib/features/email/data/datasource/print_file_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/email/domain/model/email_print.dart'; 2 | 3 | abstract class PrintFileDataSource { 4 | Future printEmail(EmailPrint emailPrint); 5 | } -------------------------------------------------------------------------------- /lib/features/mailbox_creator/domain/model/verification/validator.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:core/core.dart'; 3 | import 'package:dartz/dartz.dart'; 4 | 5 | abstract class Validator { 6 | Either validate(T value); 7 | } -------------------------------------------------------------------------------- /model/lib/extensions/properties_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; 3 | 4 | extension PropertiesExtension on Properties { 5 | 6 | bool contain(String key) => value.contains(key); 7 | } -------------------------------------------------------------------------------- /model/lib/principals/capability_principals.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; 2 | 3 | final capabilityPrincipals = CapabilityIdentifier(Uri.parse('urn:ietf:params:jmap:principals')); 4 | -------------------------------------------------------------------------------- /rule_filter/lib/rule_filter/capability_rule_filter.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; 2 | 3 | final capabilityRuleFilter = CapabilityIdentifier(Uri.parse('com:linagora:params:jmap:filter')); -------------------------------------------------------------------------------- /lib/features/composer/domain/repository/contact_repository.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:model/model.dart'; 3 | 4 | abstract class ContactRepository { 5 | Future> getContactSuggestions(AutoCompletePattern autoCompletePattern); 6 | } -------------------------------------------------------------------------------- /integration_test/base/core_robot.dart: -------------------------------------------------------------------------------- 1 | import 'package:patrol/patrol.dart'; 2 | 3 | abstract class CoreRobot { 4 | final PatrolIntegrationTester $; 5 | 6 | CoreRobot(this.$); 7 | 8 | dynamic ignoreException() => $.tester.takeException(); 9 | } -------------------------------------------------------------------------------- /lib/features/email/presentation/styles/event_title_widget_styles.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | 4 | class EventTitleWidgetStyles { 5 | static const double textSize = 24; 6 | static const Color textColor = Colors.black; 7 | } -------------------------------------------------------------------------------- /core/lib/domain/exceptions/string_exception.dart: -------------------------------------------------------------------------------- 1 | class UnsupportedCharsetException implements Exception { 2 | const UnsupportedCharsetException(); 3 | } 4 | 5 | class NullCharsetException implements Exception { 6 | const NullCharsetException(); 7 | } -------------------------------------------------------------------------------- /lib/features/login/data/utils/library_platform/app_auth_plugin/app_auth_mobile_plugin.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter_appauth_platform_interface/flutter_appauth_platform_interface.dart'; 3 | 4 | class AppAuthWebPlugin extends FlutterAppAuthPlatform {} 5 | -------------------------------------------------------------------------------- /model/lib/account/password.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class Password with EquatableMixin { 4 | final String value; 5 | 6 | Password(this.value); 7 | 8 | @override 9 | List get props => [value]; 10 | } -------------------------------------------------------------------------------- /model/lib/extensions/oidc_user_info_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:model/oidc/response/oidc_user_info.dart'; 2 | 3 | extension OidcUserInfoExtension on OidcUserInfo { 4 | bool get isWorkplaceFqdnValid => workplaceFqdn?.trim().isNotEmpty == true; 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/email/domain/state/get_list_detailed_email_by_id_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | 3 | class GetListDetailedEmailByIdFailure extends FeatureFailure { 4 | GetListDetailedEmailByIdFailure({super.exception}); 5 | } -------------------------------------------------------------------------------- /lib/features/mailbox/domain/exceptions/set_mailbox_rights_exception.dart: -------------------------------------------------------------------------------- 1 | 2 | class SetMailboxRightsException implements Exception { 3 | 4 | SetMailboxRightsException(); 5 | 6 | @override 7 | String toString() => 'Failed to update mailbox rights.'; 8 | } -------------------------------------------------------------------------------- /lib/features/mailbox/presentation/styles/mailbox_loading_bar_widget_styles.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | 4 | class MailboxLoadingBarWidgetStyles { 5 | static const EdgeInsetsGeometry padding = EdgeInsetsDirectional.only(top: 16); 6 | } -------------------------------------------------------------------------------- /model/lib/oidc/token_id.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | class TokenId with EquatableMixin { 5 | final String uuid; 6 | 7 | TokenId(this.uuid); 8 | 9 | @override 10 | List get props => [uuid]; 11 | } 12 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | if [[ "$MODULES" == "default" ]]; then 6 | flutter test -r json > test-report-"$MODULES".json 7 | else 8 | flutter test -r json "$MODULES" > test-report-"$MODULES".json 9 | fi 10 | -------------------------------------------------------------------------------- /contact/lib/contact/model/capability_contact.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; 3 | 4 | final tmailContactCapabilityIdentifier = CapabilityIdentifier(Uri.parse('com:linagora:params:jmap:contact:autocomplete')); -------------------------------------------------------------------------------- /fcm/lib/model/fcm_token.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | class FcmToken with EquatableMixin { 5 | 6 | final String value; 7 | 8 | FcmToken(this.value); 9 | 10 | @override 11 | List get props => [value]; 12 | } -------------------------------------------------------------------------------- /ios/TwakeCore/Logger/TwakeLogger.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TwakeLogger { 4 | static let shared: TwakeLogger = TwakeLogger() 5 | 6 | func log(message: String) { 7 | debugPrint("[TwakeMail] \(message)") 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/features/paywall/data/datasource/paywall_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/paywall/domain/model/paywall_url_pattern.dart'; 2 | 3 | abstract class PaywallDatasource { 4 | Future getPaywallUrl(String baseUrl); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/paywall/domain/repository/paywall_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/paywall/domain/model/paywall_url_pattern.dart'; 2 | 3 | abstract class PaywallRepository { 4 | Future getPaywallUrl(String baseUrl); 5 | } 6 | -------------------------------------------------------------------------------- /assets/images/ic_collapse_attachment.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /core/lib/utils/config/errors.dart: -------------------------------------------------------------------------------- 1 | class NotInitializedError implements Exception {} 2 | 3 | class ConfigurationNotFoundError implements Exception {} 4 | 5 | class EmptyConfiguration implements Exception {} 6 | 7 | class InvalidConfigurationParser implements Exception {} -------------------------------------------------------------------------------- /email_recovery/lib/email_recovery/capability_deleted_messages_vault.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; 2 | 3 | final capabilityDeletedMessagesVault = CapabilityIdentifier(Uri.parse('com:linagora:params:jmap:messages:vault')); -------------------------------------------------------------------------------- /fcm/lib/model/firebase_capability.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; 3 | 4 | class FirebaseCapability { 5 | static final fcmIdentifier = CapabilityIdentifier(Uri.parse('com:linagora:params:jmap:firebase:push')); 6 | } -------------------------------------------------------------------------------- /lib/features/upload/domain/extensions/list_platform_file_extensions.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:file_picker/file_picker.dart'; 3 | 4 | extension ListPlatformFileExtensions on List { 5 | int get totalFilesSize => fold(0, (sum, file) => sum + file.size); 6 | } -------------------------------------------------------------------------------- /configurations/env.fcm: -------------------------------------------------------------------------------- 1 | FIREBASE_ANDROID_API_KEY=example 2 | FIREBASE_ANDROID_APP_ID=example 3 | FIREBASE_ANDROID_MESSAGING_SENDER_ID=example 4 | FIREBASE_ANDROID_PROJECT_ID=example 5 | FIREBASE_ANDROID_DATABASE_URL=https://example.com 6 | FIREBASE_ANDROID_STORAGE_BUCKET=example.com -------------------------------------------------------------------------------- /core/lib/data/network/config/service_path.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | class ServicePath with EquatableMixin { 5 | final String path; 6 | 7 | ServicePath(this.path); 8 | 9 | @override 10 | List get props => [path]; 11 | } -------------------------------------------------------------------------------- /core/lib/domain/preview/document_uti.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class DocumentUti with EquatableMixin{ 4 | final String? value; 5 | 6 | DocumentUti(this.value); 7 | 8 | @override 9 | List get props => [value]; 10 | } 11 | -------------------------------------------------------------------------------- /core/lib/presentation/utils/html_transformer/base/text_transformer.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:convert'; 3 | 4 | /// Transforms plain text messages. 5 | abstract class TextTransformer { 6 | const TextTransformer(); 7 | 8 | String process(String text, HtmlEscape htmlEscape); 9 | } -------------------------------------------------------------------------------- /lib/features/mailbox/domain/model/jmap_mailbox_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart'; 2 | 3 | class JmapMailboxResponse extends MailboxResponse { 4 | 5 | JmapMailboxResponse({required super.mailboxes, super.state}); 6 | } -------------------------------------------------------------------------------- /lib/features/server_settings/domain/exceptions/server_settings_exception.dart: -------------------------------------------------------------------------------- 1 | class NotFoundServerSettingsException implements Exception {} 2 | 3 | class NotFoundSettingOptionException implements Exception {} 4 | 5 | class CanNotUpdateServerSettingsException implements Exception {} -------------------------------------------------------------------------------- /lib/l10n/intl_fi.arb: -------------------------------------------------------------------------------- 1 | { 2 | "downloading_file": "Ladataan {fileName}", 3 | "@downloading_file": { 4 | "type": "text", 5 | "placeholders_order": [ 6 | "fileName" 7 | ], 8 | "placeholders": { 9 | "fileName": {} 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /model/lib/download/download_task_id.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class DownloadTaskId with EquatableMixin { 4 | final String taskId; 5 | 6 | DownloadTaskId(this.taskId); 7 | 8 | @override 9 | List get props => [taskId]; 10 | } -------------------------------------------------------------------------------- /assets/images/ic_close_dialog.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /core/lib/presentation/resources/assets_paths.dart: -------------------------------------------------------------------------------- 1 | class AssetsPaths { 2 | static const images = 'assets/images/'; 3 | static const icons = 'assets/icons/'; 4 | static const configurationImages = 'configurations/icons/'; 5 | static const animations = 'assets/animations/'; 6 | } -------------------------------------------------------------------------------- /core/lib/utils/web_renderer/canvas_kit_web.dart: -------------------------------------------------------------------------------- 1 | import 'package:universal_html/js.dart' as js; 2 | 3 | /// Whether the CanvasKit renderer is being used on web. 4 | /// 5 | /// Always returns `false` on non-web. 6 | bool get isRendererCanvasKit => js.context['flutterCanvasKit'] != null; -------------------------------------------------------------------------------- /fcm/lib/model/device_client_id.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | class DeviceClientId with EquatableMixin { 5 | 6 | final String value; 7 | 8 | DeviceClientId(this.value); 9 | 10 | @override 11 | List get props => [value]; 12 | } -------------------------------------------------------------------------------- /lib/features/composer/data/datasource/composer_datasource.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:model/upload/file_info.dart'; 3 | 4 | abstract class ComposerDataSource { 5 | Future downloadImageAsBase64(String url, String cid, FileInfo fileInfo, {double? maxWidth, bool? compress}); 6 | } -------------------------------------------------------------------------------- /lib/features/download/domain/exceptions/download_attachment_exceptions.dart: -------------------------------------------------------------------------------- 1 | class DownloadAttachmentInteractorIsNull implements Exception {} 2 | 3 | class CapabilityDownloadAllNotSupportedException implements Exception {} 4 | 5 | class DownloadUrlIsNullException implements Exception {} -------------------------------------------------------------------------------- /lib/features/mailbox/domain/model/cache_mailbox_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart'; 2 | 3 | class CacheMailboxResponse extends MailboxResponse { 4 | 5 | CacheMailboxResponse({required super.mailboxes, super.state}); 6 | } -------------------------------------------------------------------------------- /lib/features/manage_account/domain/model/preferences/preferences_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class PreferencesConfig with EquatableMixin { 4 | 5 | Map toJson(); 6 | 7 | @override 8 | List get props => []; 9 | } -------------------------------------------------------------------------------- /lib/features/quotas/data/datasource/quotas_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/account_id.dart'; 2 | import 'package:jmap_dart_client/jmap/quotas/quota.dart'; 3 | 4 | abstract class QuotasDataSource { 5 | Future> getQuotas(AccountId accountId); 6 | } 7 | -------------------------------------------------------------------------------- /model/lib/extensions/list_id_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/core/id.dart'; 2 | import 'package:jmap_dart_client/jmap/mail/email/email.dart'; 3 | 4 | extension ListIdExtension on Iterable { 5 | Iterable toEmailIds() => map((id) => EmailId(id)); 6 | } -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/presentation/model/refresh_action_view_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/success.dart'; 2 | 3 | class RefreshActionViewEvent extends ViewEvent { 4 | 5 | RefreshActionViewEvent(); 6 | 7 | @override 8 | List get props => []; 9 | } -------------------------------------------------------------------------------- /lib/features/quotas/domain/repository/quotas_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/account_id.dart'; 2 | import 'package:jmap_dart_client/jmap/quotas/quota.dart'; 3 | 4 | abstract class QuotasRepository { 5 | Future> getQuotas(AccountId accountId); 6 | } 7 | -------------------------------------------------------------------------------- /core/lib/presentation/action/action_callback_define.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | 4 | typedef OnTapActionCallback = void Function(); 5 | typedef OnTapActionAtPositionCallback = void Function(RelativeRect position); 6 | typedef OnLongPressActionCallback = void Function(); -------------------------------------------------------------------------------- /core/lib/utils/build_utils.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/foundation.dart'; 3 | 4 | abstract class BuildUtils { 5 | static const bool isDebugMode = kDebugMode; 6 | 7 | static const bool isReleaseMode = kReleaseMode; 8 | 9 | static const bool isProfileMode = kProfileMode; 10 | } -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/domain/exceptions/spam_report_exception.dart: -------------------------------------------------------------------------------- 1 | 2 | class NotFoundLastTimeDismissedSpamReportException implements Exception {} 3 | 4 | class NotFoundSpamMailboxCachedException implements Exception {} 5 | 6 | class NotFoundSpamMailboxException implements Exception {} -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/presentation/styles/mark_mailbox_as_read_loading_banner_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MarkMailboxAsReadLoadingBannerStyle { 4 | static const EdgeInsetsGeometry bannerMargin = EdgeInsetsDirectional.only(end: 16, bottom: 8); 5 | } -------------------------------------------------------------------------------- /lib/features/manage_account/presentation/mailbox_visibility/state/mailbox_visibility_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/success.dart'; 2 | 3 | class LoadingBuildTreeMailboxVisibility extends LoadingState {} 4 | 5 | class BuildTreeMailboxVisibilitySuccess extends UIState {} 6 | -------------------------------------------------------------------------------- /lib/features/offline_mode/manager/new_email_cache_worker_queue.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:tmail_ui_user/features/offline_mode/hive_worker/hive_worker_queue.dart'; 3 | 4 | class NewEmailCacheWorkerQueue extends WorkerQueue { 5 | 6 | @override 7 | String get workerName => 'NewEmailCache'; 8 | } -------------------------------------------------------------------------------- /test/fixtures/state_fixtures.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/core/state.dart'; 3 | 4 | class StateFixtures { 5 | static final currentMailboxState = State('a1234'); 6 | static final newMailboxState = State('a2345'); 7 | static final currentEmailState = State('e1234'); 8 | } -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip 7 | -------------------------------------------------------------------------------- /lib/features/manage_account/data/datasource/notification_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/core/user_name.dart'; 2 | 3 | abstract class NotificationDataSource { 4 | Future getNotificationSetting(UserName userName); 5 | 6 | Future toggleNotificationSetting(); 7 | } -------------------------------------------------------------------------------- /lib/features/manage_account/domain/repository/notification_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/core/user_name.dart'; 2 | 3 | abstract class NotificationRepository { 4 | Future getNotificationSetting(UserName userName); 5 | 6 | Future toggleNotificationSetting(); 7 | } -------------------------------------------------------------------------------- /lib/features/offline_mode/manager/opened_email_cache_worker_queue.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/offline_mode/hive_worker/hive_worker_queue.dart'; 2 | 3 | class OpenedEmailCacheWorkerQueue extends WorkerQueue { 4 | 5 | @override 6 | String get workerName => 'OpenedEmailCache'; 7 | } -------------------------------------------------------------------------------- /model/lib/contact/device_contact.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | import 'package:model/contact/contact.dart'; 4 | 5 | class DeviceContact extends Contact implements EquatableMixin { 6 | DeviceContact(String displayName, String email) : super(displayName, email); 7 | } 8 | -------------------------------------------------------------------------------- /model/lib/exceptions/token_oidc_exceptions.dart: -------------------------------------------------------------------------------- 1 | class AccessTokenIsNullException implements Exception {} 2 | 3 | class RefreshTokenIsNullException implements Exception {} 4 | 5 | class TokenIdIsNullException implements Exception {} 6 | 7 | class ExpiresTimeIsNullException implements Exception {} 8 | -------------------------------------------------------------------------------- /test/features/offline_mode/mailbox_state_worker_queue.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | import 'package:tmail_ui_user/features/offline_mode/hive_worker/hive_worker_queue.dart'; 4 | 5 | class MailboxStateWorkerQueue extends WorkerQueue { 6 | 7 | @override 8 | String get workerName => 'MailboxStateWorkerQueue'; 9 | } -------------------------------------------------------------------------------- /assets/images/ic_checked.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /lib/features/base/state/button_state.dart: -------------------------------------------------------------------------------- 1 | 2 | enum ButtonState { 3 | enabled, 4 | disabled; 5 | 6 | double get opacity { 7 | switch(this) { 8 | case ButtonState.enabled: 9 | return 1.0; 10 | case ButtonState.disabled: 11 | return 0.4; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /lib/features/base/styles/hyper_link_widget_styles.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/extensions/color_extension.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class HyperLinkWidgetStyles { 5 | static const Color textColor = AppColor.primaryColor; 6 | static const double textSize = 16; 7 | } -------------------------------------------------------------------------------- /lib/features/home/data/datasource/session_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/core/session/session.dart'; 2 | 3 | abstract class SessionDataSource { 4 | Future getSession(); 5 | 6 | Future storeSession(Session session); 7 | 8 | Future getStoredSession(); 9 | } -------------------------------------------------------------------------------- /lib/features/home/data/exceptions/session_exceptions.dart: -------------------------------------------------------------------------------- 1 | 2 | class NotFoundSessionException implements Exception {} 3 | 4 | class NotFoundAccountIdException implements Exception {} 5 | 6 | class NotFoundContextException implements Exception {} 7 | 8 | class ParametersIsNullException implements Exception {} -------------------------------------------------------------------------------- /lib/features/home/domain/repository/session_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/core/session/session.dart'; 2 | 3 | abstract class SessionRepository { 4 | Future getSession(); 5 | 6 | Future storeSession(Session session); 7 | 8 | Future getStoredSession(); 9 | } -------------------------------------------------------------------------------- /model/lib/email/presentation_email_address.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | class PresentationEmailAddress with EquatableMixin { 5 | final String email; 6 | 7 | PresentationEmailAddress(this.email); 8 | 9 | @override 10 | List get props => [email]; 11 | } -------------------------------------------------------------------------------- /assets/images/ic_radio_selected.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/user-guide/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # sudo apt-get install pandoc texlive texlive-xetex texlive-fonts-recommended 4 | 5 | pandoc index.md antispam.md auth.md composer.md extra-features.md install.md manage-folders.md profile.md pro-tips.md quota.md read.md search.md -o output.pdf --pdf-engine=xelatex 6 | -------------------------------------------------------------------------------- /lib/features/base/isolate/background_isolate_binary_messenger/background_isolate_binary_messenger_web.dart: -------------------------------------------------------------------------------- 1 | 2 | class RootIsolateToken { 3 | static final RootIsolateToken? instance = () {}(); 4 | } 5 | 6 | class BackgroundIsolateBinaryMessenger { 7 | static void ensureInitialized(RootIsolateToken token) {} 8 | } -------------------------------------------------------------------------------- /lib/features/mailbox/domain/exceptions/invalid_mail_format_exception.dart: -------------------------------------------------------------------------------- 1 | 2 | class InvalidMailFormatException implements Exception { 3 | final String mail; 4 | 5 | InvalidMailFormatException(this.mail); 6 | 7 | @override 8 | String toString() => 'InvalidMailFormatException: $mail'; 9 | } 10 | -------------------------------------------------------------------------------- /lib/features/sending_queue/presentation/utils/sending_queue_isolate_manager.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:tmail_ui_user/features/base/isolate/isolate_manager.dart'; 3 | 4 | class SendingQueueIsolateManager extends IsolateManager { 5 | 6 | @override 7 | String get isolateIdentityName => 'sending_queue_isolate'; 8 | } -------------------------------------------------------------------------------- /model/lib/extensions/list_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | extension ListExtension on List? { 3 | 4 | List? unite(List? other) { 5 | if (other != null) { 6 | this?.addAll(other); 7 | } 8 | return this; 9 | } 10 | 11 | bool notContains(T value) => this?.contains(value) != true; 12 | } -------------------------------------------------------------------------------- /core/lib/utils/option_param_mixin.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | 3 | mixin OptionParamMixin { 4 | T? getOptionParam(Option? option, T? defaultValue) { 5 | if (option != null) { 6 | return option.toNullable(); 7 | } else { 8 | return defaultValue; 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/features/composer/presentation/extensions/list_identities_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/identities/identity.dart'; 3 | 4 | extension ListIdentitiesExtension on List { 5 | 6 | List toListMayDeleted() => where((identity) => identity.mayDelete == true).toList(); 7 | } -------------------------------------------------------------------------------- /lib/features/login/data/network/endpoint.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/data/network/config/service_path.dart'; 2 | 3 | class Endpoint { 4 | static final ServicePath webFinger = ServicePath('.well-known/webfinger'); 5 | static final ServicePath linagoraEcosystem = ServicePath('.well-known/linagora-ecosystem'); 6 | } 7 | -------------------------------------------------------------------------------- /lib/features/mailbox_creator/domain/model/verification/new_name_request.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | class NewNameRequest with EquatableMixin { 5 | final String? value; 6 | 7 | NewNameRequest(this.value); 8 | 9 | @override 10 | List get props => [value]; 11 | } -------------------------------------------------------------------------------- /core/lib/presentation/extensions/compare_list_extensions.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:collection/collection.dart'; 3 | 4 | extension CompareListExtension on List { 5 | bool isSame(List value) { 6 | Function unOrdDeepEq = const DeepCollectionEquality.unordered().equals; 7 | return unOrdDeepEq(this, value); 8 | } 9 | } -------------------------------------------------------------------------------- /lib/features/login/data/datasource/authentication_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/core/user_name.dart'; 2 | import 'package:model/account/password.dart'; 3 | 4 | abstract class AuthenticationDataSource { 5 | Future authenticationUser(Uri baseUrl, UserName userName, Password password); 6 | } -------------------------------------------------------------------------------- /lib/features/mailbox/data/extensions/state_cache_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/core/state.dart'; 3 | import 'package:tmail_ui_user/features/mailbox/data/model/state_cache.dart'; 4 | 5 | extension StateCacheExtension on StateCache { 6 | State toState() { 7 | return State(state); 8 | } 9 | } -------------------------------------------------------------------------------- /lib/features/mailbox/domain/exceptions/null_session_or_accountid_exception.dart: -------------------------------------------------------------------------------- 1 | 2 | class NullSessionOrAccountIdException implements Exception { 3 | 4 | NullSessionOrAccountIdException(); 5 | 6 | @override 7 | String toString() => 'NullSessionOrAccountIdException: session and accountId should not be null'; 8 | } 9 | -------------------------------------------------------------------------------- /lib/features/manage_account/presentation/vacation/styles/vacation_notification_message_widget_style.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/material.dart'; 3 | 4 | class VacationNotificationMessageWidgetStyle { 5 | static const EdgeInsetsGeometry bannerMargin = EdgeInsetsDirectional.only( 6 | end: 16, 7 | bottom: 8); 8 | } -------------------------------------------------------------------------------- /lib/features/thread/data/extensions/map_mailbox_id_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; 3 | 4 | extension MapMailboxIdExtension on Map { 5 | 6 | Map toMapString() => Map.fromIterables(keys.map((mailboxId) => mailboxId.id.value), values); 7 | } -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/features/base/isolate/background_isolate_binary_messenger/background_isolate_binary_messenger.dart: -------------------------------------------------------------------------------- 1 | 2 | export 'background_isolate_binary_messenger_web.dart' 3 | if (dart.library.html) 'background_isolate_binary_messenger_web.dart' // Browser 4 | if (dart.library.io) 'background_isolate_binary_messenger_mobile.dart'; // VM -------------------------------------------------------------------------------- /lib/features/composer/presentation/extensions/identity_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/identities/identity.dart'; 2 | import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; 3 | 4 | extension IdentityExtension on Identity { 5 | EmailAddress toEmailAddress() => EmailAddress(name, email); 6 | } -------------------------------------------------------------------------------- /lib/features/login/domain/repository/authentication_repository.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/core/user_name.dart'; 3 | import 'package:model/account/password.dart'; 4 | 5 | abstract class AuthenticationRepository { 6 | Future authenticationUser(Uri baseUrl, UserName userName, Password password); 7 | } -------------------------------------------------------------------------------- /lib/features/manage_account/domain/exceptions/forward_exception.dart: -------------------------------------------------------------------------------- 1 | class NotFoundForwardException implements Exception {} 2 | 3 | class UpdateForwardException implements Exception {} 4 | 5 | class RecipientListIsEmptyException implements Exception {} 6 | 7 | class RecipientListWithInvalidEmailsException implements Exception {} -------------------------------------------------------------------------------- /lib/features/thread/data/extensions/map_keywords_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; 3 | 4 | extension MapKeywordsExtension on Map { 5 | 6 | Map toMapString() => Map.fromIterables(keys.map((keyword) => keyword.value), values); 7 | } -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /core/lib/presentation/views/loading/cupertino_loading_widget_styles.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/extensions/color_extension.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class CupertinoLoadingWidgetStyles { 5 | static const Color progressColor = AppColor.colorLoading; 6 | static const double size = 24; 7 | } -------------------------------------------------------------------------------- /integration_test/models/provisioning_identity.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/identities/identity.dart'; 2 | 3 | class ProvisioningIdentity { 4 | final Identity identity; 5 | final bool isDefault; 6 | 7 | ProvisioningIdentity({ 8 | required this.identity, 9 | this.isDefault = false, 10 | }); 11 | } -------------------------------------------------------------------------------- /lib/features/composer/presentation/styles/web/mobile_responsive_container_view_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MobileResponsiveContainerViewStyle { 4 | static const double radius = 28; 5 | static const double elevation = 16; 6 | 7 | static const Color outSideBackgroundColor = Colors.white; 8 | } -------------------------------------------------------------------------------- /lib/features/mailbox/domain/exceptions/mailbox_exception.dart: -------------------------------------------------------------------------------- 1 | 2 | class NotFoundInboxMailboxException implements Exception {} 3 | 4 | class NotFoundMailboxException implements Exception {} 5 | 6 | class NotFoundClearMailboxResponseException implements Exception {} 7 | 8 | class CannotMoveAllEmailException implements Exception {} 9 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4096M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | android.jetifier.ignorelist=bcprov-jdk15on-1.68.jar 5 | android.defaults.buildfeatures.buildconfig=true 6 | android.nonTransitiveRClass=false 7 | android.nonFinalResIds=false 8 | kotlin.jvm.target.validation.mode = IGNORE -------------------------------------------------------------------------------- /integration_test/tests/misc/log_out_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/misc/log_out_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see Twake welcome screen when log out successfully', 7 | scenarioBuilder: ($) => LogOutScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/TwakeCore/Exceptions/NetworkExceptions.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class NetworkExceptions: Error { 4 | static let requestUrlInvalid = NetworkExceptions(value: "Request url invalid") 5 | 6 | var value: String? 7 | 8 | init(value: String? = nil) { 9 | self.value = value 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /model/lib/email/eml_attachment.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:model/email/attachment.dart'; 3 | 4 | class EMLAttachment extends Attachment { 5 | 6 | EMLAttachment({ 7 | super.partId, 8 | super.blobId, 9 | super.size, 10 | super.name, 11 | super.type, 12 | super.cid, 13 | super.disposition, 14 | }); 15 | } -------------------------------------------------------------------------------- /model/lib/extensions/list_email_content_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:model/model.dart'; 2 | 3 | extension ListEmailContentExtension on List { 4 | 5 | String get asHtmlString { 6 | if (isNotEmpty) { 7 | return map((content) => content.asHtml).join('
'); 8 | } 9 | return ''; 10 | } 11 | } -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /integration_test/tests/app_grid/app_grid_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/app_grid_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should display and navigate app grid correctly when clicked', 7 | scenarioBuilder: ($) => AppGridScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/composer/send_email_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/send_email_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see success toast when send email successfully', 7 | scenarioBuilder: ($) => SendEmailScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/features/composer/presentation/styles/title_composer_widget_style.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:core/presentation/utils/theme_utils.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class TitleComposerWidgetStyle { 6 | static final TextStyle textStyle = ThemeUtils.textStyleHeadingHeadingSmall( 7 | color: Colors.black 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/email/domain/exceptions/email_cache_exceptions.dart: -------------------------------------------------------------------------------- 1 | 2 | class NotFoundStoredOpenedEmailException implements Exception {} 3 | 4 | class NotFoundStoredNewEmailException implements Exception {} 5 | 6 | class NotFoundStoredEmailException implements Exception {} 7 | 8 | class OpenedEmailAlreadyStoredException implements Exception {} -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/images/ic_format_quote.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /integration_test/tests/composer/save_as_template_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/save_as_template_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should save email as template successfully', 7 | scenarioBuilder: ($) => SaveAsTemplateScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/switch_mailbox_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/switch_mailbox_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should switch and see emails in mailboxes', 7 | scenarioBuilder: ($) => SwitchMailboxScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/login/data/network/oidc_error.dart: -------------------------------------------------------------------------------- 1 | class CanNotFoundOIDCAuthority implements Exception {} 2 | 3 | class CanNotFoundOIDCLinks implements Exception {} 4 | 5 | class CanNotFindToken implements Exception {} 6 | 7 | class CanRetryOIDCException implements Exception {} 8 | 9 | class NotFoundUserInfoEndpointException implements Exception {} -------------------------------------------------------------------------------- /lib/features/push_notification/domain/exceptions/web_socket_exceptions.dart: -------------------------------------------------------------------------------- 1 | class WebSocketPushNotSupportedException implements Exception {} 2 | 3 | class WebSocketUriUnavailableException implements Exception {} 4 | 5 | class WebSocketTicketUnavailableException implements Exception {} 6 | 7 | class WebSocketClosedException implements Exception {} -------------------------------------------------------------------------------- /model/lib/oidc/converter/uri_converter.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | class UriConverter implements JsonConverter { 5 | const UriConverter(); 6 | 7 | @override 8 | Uri fromJson(String json) => Uri.parse(json); 9 | 10 | @override 11 | String toJson(Uri uri) => uri.path; 12 | } -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /fcm/lib/model/firebase_registration_id.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | import 'package:jmap_dart_client/jmap/core/id.dart'; 4 | 5 | class FirebaseRegistrationId with EquatableMixin { 6 | 7 | final Id id; 8 | 9 | FirebaseRegistrationId(this.id); 10 | 11 | @override 12 | List get props => [id]; 13 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/pull_to_refresh_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/pull_to_refresh_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should refresh email list when pull to refresh', 7 | scenarioBuilder: ($) => PullToRefreshScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/quota_count_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/quota_count_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see quota increase when send email successfully', 7 | scenarioBuilder: ($) => QuotaCountScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/base/styles/circle_loading_widget_styles.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/extensions/color_extension.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class CircleLoadingWidgetStyles { 5 | static const Color progressColor = AppColor.primaryColor; 6 | static const double size = 24; 7 | static const double width = 2; 8 | } -------------------------------------------------------------------------------- /lib/features/caching/clients/email_cache_client.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart'; 3 | import 'package:tmail_ui_user/features/thread/data/model/email_cache.dart'; 4 | 5 | class EmailCacheClient extends HiveCacheClient { 6 | 7 | @override 8 | String get tableName => 'EmailCache'; 9 | } -------------------------------------------------------------------------------- /lib/features/caching/clients/state_cache_client.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart'; 3 | import 'package:tmail_ui_user/features/mailbox/data/model/state_cache.dart'; 4 | 5 | class StateCacheClient extends HiveCacheClient { 6 | 7 | @override 8 | String get tableName => 'StateCache'; 9 | } -------------------------------------------------------------------------------- /lib/features/composer/domain/exceptions/set_method_exception.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; 3 | import 'package:jmap_dart_client/jmap/core/id.dart'; 4 | 5 | class SetMethodException implements Exception { 6 | 7 | final Map mapErrors; 8 | 9 | SetMethodException(this.mapErrors); 10 | } -------------------------------------------------------------------------------- /lib/features/composer/domain/repository/auto_complete_repository.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; 3 | import 'package:model/autocomplete/auto_complete_pattern.dart'; 4 | 5 | abstract class AutoCompleteRepository { 6 | Future> getAutoComplete(AutoCompletePattern autoCompletePattern); 7 | } -------------------------------------------------------------------------------- /lib/features/contact/data/datasource/auto_complete_datasource.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; 3 | import 'package:model/autocomplete/auto_complete_pattern.dart'; 4 | 5 | abstract class AutoCompleteDataSource { 6 | Future> getAutoComplete(AutoCompletePattern autoCompletePattern); 7 | } -------------------------------------------------------------------------------- /lib/features/login/data/datasource/account_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:model/account/personal_account.dart'; 2 | 3 | abstract class AccountDatasource { 4 | Future getCurrentAccount(); 5 | 6 | Future setCurrentAccount(PersonalAccount newCurrentAccount); 7 | 8 | Future deleteCurrentAccount(String accountId); 9 | } -------------------------------------------------------------------------------- /lib/features/login/domain/model/company_server_login_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class CompanyServerLoginInfo with EquatableMixin { 4 | final String email; 5 | 6 | const CompanyServerLoginInfo({ 7 | required this.email, 8 | }); 9 | 10 | @override 11 | List get props => [email]; 12 | } 13 | -------------------------------------------------------------------------------- /lib/features/mailbox/domain/exceptions/empty_folder_name_exception.dart: -------------------------------------------------------------------------------- 1 | 2 | class EmptyFolderNameException implements Exception { 3 | final String folderName; 4 | 5 | EmptyFolderNameException(this.folderName); 6 | 7 | @override 8 | String toString() => 'EmptyFolderNameException: Folder name should not be empty: $folderName'; 9 | } 10 | -------------------------------------------------------------------------------- /lib/features/mailto/presentation/mailto_url_bindings.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get.dart'; 2 | import 'package:tmail_ui_user/features/mailto/presentation/mailto_url_controller.dart'; 3 | 4 | class MailtoUrlBindings extends Bindings { 5 | 6 | @override 7 | void dependencies() { 8 | Get.lazyPut(() => MailtoUrlController()); 9 | } 10 | } -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/images/ic_composer_close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /integration_test/robots/app_grid_robot.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter_test/flutter_test.dart'; 3 | 4 | import '../base/core_robot.dart'; 5 | 6 | class AppGridRobot extends CoreRobot { 7 | AppGridRobot(super.$); 8 | 9 | Future openAppInAppGridByAppName(String appName) async { 10 | await $(find.text(appName)).tap(); 11 | } 12 | } -------------------------------------------------------------------------------- /lib/features/caching/clients/account_cache_client.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart'; 2 | import 'package:tmail_ui_user/features/login/data/model/account_cache.dart'; 3 | 4 | class AccountCacheClient extends HiveCacheClient { 5 | 6 | @override 7 | String get tableName => 'AccountCache'; 8 | } -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/presentation/styles/top_bar_thread_selection_style.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:core/presentation/extensions/color_extension.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class TopBarThreadSelectionStyle { 6 | static const Color iconColor = AppColor.steelGrayA540; 7 | 8 | static const double iconSize = 20.0; 9 | } -------------------------------------------------------------------------------- /lib/features/upload/domain/model/upload_task_id.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | class UploadTaskId extends Equatable { 5 | final String id; 6 | 7 | const UploadTaskId(this.id); 8 | 9 | factory UploadTaskId.undefined() => const UploadTaskId(''); 10 | 11 | @override 12 | List get props => [id]; 13 | } -------------------------------------------------------------------------------- /lib/features/upload/presentation/model/upload_file_status.dart: -------------------------------------------------------------------------------- 1 | 2 | enum UploadFileStatus { 3 | waiting, 4 | uploading, 5 | uploadFailed, 6 | succeed 7 | } 8 | 9 | extension UploadFileStatusExtension on UploadFileStatus { 10 | bool get completed => 11 | this == UploadFileStatus.uploadFailed || this == UploadFileStatus.succeed; 12 | } -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: d79295af24c3ed621c33713ecda14ad196fd9c31 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /docs/configuration/ws_echo_ping_configuration.md: -------------------------------------------------------------------------------- 1 | ## Configuration Web Socket Echo Ping 2 | 3 | ### Context 4 | - Echo ping method is optional 5 | ### How to config 6 | In [env.file]: 7 | - If you want to use Echo ping: 8 | ```WS_ECHO_PING=true``` 9 | - If you don't want to use Echo ping: 10 | ```WS_ECHO_PING=false``` 11 | or 12 | ```WS_ECHO_PING=``` -------------------------------------------------------------------------------- /integration_test/tests/web_socket/web_socket_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/web_socket_update_ui_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see thread view updated per web socket message', 7 | scenarioBuilder: ($) => WebSocketUpdateUiScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/caching/clients/mailbox_cache_client.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart'; 3 | import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache.dart'; 4 | 5 | class MailboxCacheClient extends HiveCacheClient { 6 | 7 | @override 8 | String get tableName => 'MailboxCache'; 9 | } -------------------------------------------------------------------------------- /lib/features/login/domain/repository/account_repository.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:model/account/personal_account.dart'; 3 | 4 | abstract class AccountRepository { 5 | Future getCurrentAccount(); 6 | 7 | Future setCurrentAccount(PersonalAccount newCurrentAccount); 8 | 9 | Future deleteCurrentAccount(String hashId); 10 | } -------------------------------------------------------------------------------- /assets/images/ic_radio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /core/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: d79295af24c3ed621c33713ecda14ad196fd9c31 8 | channel: stable 9 | 10 | project_type: module 11 | -------------------------------------------------------------------------------- /core/lib/presentation/extensions/capitalize_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | extension CapitalizeExtension on String { 3 | String get inCaps => length > 0 ?'${this[0].toUpperCase()}${toLowerCase().substring(1)}':''; 4 | String get allInCaps => toUpperCase(); 5 | String get capitalizeFirstEach => replaceAll(RegExp(' +'), ' ').split(" ").map((str) => str.inCaps).join(" "); 6 | } -------------------------------------------------------------------------------- /core/lib/presentation/views/list/no_stretch_scroll_behavior.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NoStretchScrollBehavior extends ScrollBehavior { 4 | @override 5 | Widget buildOverscrollIndicator( 6 | BuildContext context, 7 | Widget child, 8 | ScrollableDetails details, 9 | ) { 10 | return child; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /fcm/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: fb57da5f945d02ef4f98dfd9409a72b7cce74268 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /lib/features/caching/clients/fcm_cache_client.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart'; 3 | import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart'; 4 | 5 | class FcmCacheClient extends HiveCacheClient { 6 | 7 | @override 8 | String get tableName => CachingConstants.fcmCacheBoxName; 9 | } -------------------------------------------------------------------------------- /lib/features/email_recovery/presentation/email_recovery_bindings.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get.dart'; 2 | import 'package:tmail_ui_user/features/email_recovery/presentation/email_recovery_controller.dart'; 3 | 4 | class EmailRecoveryBindings extends Bindings { 5 | @override 6 | void dependencies() { 7 | Get.lazyPut(() => EmailRecoveryController()); 8 | } 9 | } -------------------------------------------------------------------------------- /assets/images/ic_photo_library.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /contact/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: db747aa1331bd95bc9b3874c842261ca2d302cd5 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /email_recovery/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f1875d570e39de09040c8f79aa13cc56baab8db1 8 | channel: stable 9 | 10 | project_type: package -------------------------------------------------------------------------------- /forward/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f1875d570e39de09040c8f79aa13cc56baab8db1 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /integration_test/tests/composer/forward_email_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/forward_email_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see HTML content contain enough: Subject, From, To, Cc, Bcc, Reply to', 7 | scenarioBuilder: ($) => ForwardEmailScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/create_personal_folder_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/create_personal_folder_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should create personal mailbox successfully', 7 | scenarioBuilder: ($) => CreatePersonalFolderScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/empty_and_recover_spam_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/empty_and_recover_spam_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should empty and recover spam successfully', 7 | scenarioBuilder: ($) => EmptyAndRecoverSpamScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/empty_and_recover_trash_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/empty_and_recover_trash_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should empty and recover trash successfully', 7 | scenarioBuilder: ($) => EmptyAndRecoverTrashScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/empty_trash_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/empty_trash_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should empty view and hide empty trash banner when empty trash successfully', 7 | scenarioBuilder: ($) => EmptyTrashScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/mailbox_move_email_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/mailbox_move_email_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should move email to mailbox successfully', 7 | scenarioBuilder: ($) => MailboxMoveEmailScenario($), 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /integration_test/tests/search/search_result_highlights_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/search_result_highlights_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see highlighted keyword in search result', 7 | scenarioBuilder: ($) => SearchResultHighlightsScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/domain/model/spam_report_state.dart: -------------------------------------------------------------------------------- 1 | enum SpamReportState { 2 | enabled, 3 | disabled; 4 | 5 | String get keyValue { 6 | switch(this) { 7 | case SpamReportState.enabled: 8 | return 'enabled'; 9 | case SpamReportState.disabled: 10 | return 'disabled'; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /lib/features/manage_account/presentation/storage/storage_bindings.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get.dart'; 2 | import 'package:tmail_ui_user/features/manage_account/presentation/storage/storage_controller.dart'; 3 | 4 | class StorageBindings extends Bindings { 5 | @override 6 | void dependencies() { 7 | Get.lazyPut(() => StorageController()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/features/thread/domain/model/search_query.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | class SearchQuery with EquatableMixin { 5 | final String value; 6 | 7 | SearchQuery(this.value); 8 | 9 | factory SearchQuery.initial() { 10 | return SearchQuery(''); 11 | } 12 | 13 | @override 14 | List get props => [value]; 15 | } -------------------------------------------------------------------------------- /model/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: d79295af24c3ed621c33713ecda14ad196fd9c31 8 | channel: stable 9 | 10 | project_type: module 11 | -------------------------------------------------------------------------------- /core/lib/domain/exceptions/address_exception.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class AddressException with EquatableMixin implements Exception { 4 | final String message; 5 | 6 | AddressException(this.message); 7 | 8 | @override 9 | String toString() => message; 10 | 11 | @override 12 | List get props => [message]; 13 | } 14 | -------------------------------------------------------------------------------- /docs/configuration/cozy_integration_configuration.md: -------------------------------------------------------------------------------- 1 | ## Configuration Cozy Integration 2 | 3 | ### Context 4 | - Cozy script load is optional 5 | ### How to config 6 | In [env.file]: 7 | - If you want to load Cozy script: 8 | ```COZY_INTEGRATION=true``` 9 | - If you don't want to load Cozy script: 10 | ```COZY_INTEGRATION=false``` 11 | or 12 | ```COZY_INTEGRATION=``` -------------------------------------------------------------------------------- /integration_test/robots/identities_list_menu_robot.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter_test/flutter_test.dart'; 3 | 4 | import '../base/core_robot.dart'; 5 | 6 | class IdentitiesListMenuRobot extends CoreRobot { 7 | IdentitiesListMenuRobot(super.$); 8 | 9 | Future selectIdentityByName(String name) async { 10 | await $(find.text(name)).tap(); 11 | } 12 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/search_mailbox_inbox_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/search_mailbox_inbox_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see expected mailbox when searching mailboxes', 7 | scenarioBuilder: ($) => SearchMailboxInboxScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/composer/domain/state/generate_email_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class GenerateEmailLoading extends LoadingState {} 5 | 6 | class GenerateEmailFailure extends FeatureFailure { 7 | 8 | GenerateEmailFailure(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /lib/features/email/domain/extensions/email_header_hive_cache_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/mail/email/email_header.dart'; 2 | import 'package:tmail_ui_user/features/offline_mode/model/email_header_hive_cache.dart'; 3 | 4 | extension EmailHeaderHiveCacheExtension on EmailHeaderHiveCache { 5 | EmailHeader toEmailHeader() => EmailHeader(name, value); 6 | } -------------------------------------------------------------------------------- /lib/features/mailbox_creator/domain/state/verify_name_view_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class VerifyNameViewState extends UIState {} 5 | 6 | class VerifyNameFailure extends FeatureFailure { 7 | 8 | VerifyNameFailure(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /lib/features/manage_account/domain/state/notification_setting_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class NotificationSettingHandling extends LoadingState {} 5 | 6 | class NotificationSettingSuccess extends UIState {} 7 | 8 | class NotificationSettingFailure extends FeatureFailure {} -------------------------------------------------------------------------------- /rule_filter/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f1875d570e39de09040c8f79aa13cc56baab8db1 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /assets/images/ic_remove_rule.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/lib/data/extensions/options_extensions.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | 3 | extension OptionsExtension on Options { 4 | Options appendHeaders(Map additionalHeaders) { 5 | if (headers != null) { 6 | headers?.addAll(additionalHeaders); 7 | } else { 8 | headers = additionalHeaders; 9 | } 10 | return this; 11 | } 12 | } -------------------------------------------------------------------------------- /env.file: -------------------------------------------------------------------------------- 1 | SERVER_URL=http://localhost/ 2 | DOMAIN_REDIRECT_URL=http://localhost:3000 3 | WEB_OIDC_CLIENT_ID=teammail-web 4 | OIDC_SCOPES=openid,profile,email,offline_access 5 | APP_GRID_AVAILABLE=supported 6 | FCM_AVAILABLE=supported 7 | IOS_FCM=supported 8 | FORWARD_WARNING_MESSAGE= 9 | PLATFORM=other 10 | WS_ECHO_PING= 11 | COZY_INTEGRATION= 12 | COZY_EXTERNAL_BRIDGE_VERSION= -------------------------------------------------------------------------------- /integration_test/tests/composer/reply_to_own_sent_email_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/email/reply_to_own_sent_email_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should all To recipients when reply to own sent email', 7 | scenarioBuilder: ($) => ReplyToOwnSentEmailScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/email/domain/extensions/email_header_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/mail/email/email_header.dart'; 3 | import 'package:tmail_ui_user/features/offline_mode/model/email_header_hive_cache.dart'; 4 | 5 | extension EmailHeaderExtension on EmailHeader { 6 | EmailHeaderHiveCache toHiveCache() => EmailHeaderHiveCache(name: name, value: value); 7 | } -------------------------------------------------------------------------------- /lib/features/login/domain/state/delete_credential_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class DeleteCredentialSuccess extends UIState {} 5 | 6 | class DeleteCredentialFailure extends FeatureFailure { 7 | 8 | DeleteCredentialFailure(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /lib/features/manage_account/domain/state/log_out_oidc_state.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:core/presentation/state/failure.dart'; 3 | import 'package:core/presentation/state/success.dart'; 4 | 5 | class LogoutOidcSuccess extends UIState {} 6 | 7 | class LogoutOidcFailure extends FeatureFailure { 8 | 9 | LogoutOidcFailure(dynamic exception) : super(exception: exception); 10 | } -------------------------------------------------------------------------------- /lib/features/manage_account/presentation/forward/bindings/forward_bindings.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get.dart'; 2 | import 'package:tmail_ui_user/features/manage_account/presentation/forward/forward_controller.dart'; 3 | 4 | class ForwardBindings extends Bindings { 5 | 6 | @override 7 | void dependencies() { 8 | Get.lazyPut(() => ForwardController()); 9 | } 10 | } -------------------------------------------------------------------------------- /lib/features/thread/data/extensions/map_header_identifier_id_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.dart'; 3 | 4 | extension MapHeaderIdentifierExtension on Map { 5 | 6 | Map toMapString() => Map.fromIterables(keys.map((identifier) => identifier.value), values); 7 | } -------------------------------------------------------------------------------- /model/lib/fcm/fcm_token_dto.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class FCMTokenDto with EquatableMixin { 4 | final String token; 5 | final String accountId; 6 | 7 | FCMTokenDto( 8 | this.token, 9 | this.accountId, 10 | ); 11 | 12 | @override 13 | List get props => [ 14 | token, 15 | accountId, 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /server_settings/lib/server_settings/tmail_server_settings_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:server_settings/server_settings/tmail_server_settings.dart'; 3 | 4 | extension TmailServerSettingsExtension on TMailServerSettingOptions { 5 | bool get isDisplaySenderPriority => displaySenderPriority ?? true; 6 | 7 | bool get isAlwaysReadReceipts => alwaysReadReceipts ?? false; 8 | } -------------------------------------------------------------------------------- /assets/images/ic_switch_off.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /assets/images/ic_switch_on.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /integration_test/models/provisioning_email.dart: -------------------------------------------------------------------------------- 1 | class ProvisioningEmail { 2 | final String toEmail; 3 | final String subject; 4 | final String content; 5 | final List attachmentPaths; 6 | 7 | ProvisioningEmail({ 8 | required this.toEmail, 9 | required this.subject, 10 | required this.content, 11 | this.attachmentPaths = const [], 12 | }); 13 | } -------------------------------------------------------------------------------- /integration_test/tests/email_detailed/view_inline_image_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/email_detailed/view_inline_image_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see inline image when open email with inline image', 7 | scenarioBuilder: ($) => ViewInlineImageScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/search/search_suggestion_highlights_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/search_suggestion_highlights_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see highlighted keyword in search suggestion', 7 | scenarioBuilder: ($) => SearchSuggestionHighlightsScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/caching/clients/encryption_key_cache_client.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart'; 2 | import 'package:tmail_ui_user/features/login/data/model/encryption_key_cache.dart'; 3 | 4 | class EncryptionKeyCacheClient extends HiveCacheClient { 5 | 6 | @override 7 | String get tableName => 'EncryptionKeyCache'; 8 | } -------------------------------------------------------------------------------- /lib/features/cleanup/domain/model/email_cleanup_rule.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:tmail_ui_user/features/cleanup/domain/model/cleanup_rule.dart'; 3 | 4 | class EmailCleanupRule extends CleanupRule { 5 | final Duration cachingEmailPeriod; 6 | 7 | EmailCleanupRule(this.cachingEmailPeriod) : super(); 8 | 9 | @override 10 | List get props => [cachingEmailPeriod]; 11 | } -------------------------------------------------------------------------------- /lib/features/cleanup/domain/state/cleanup_email_cache_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class CleanupEmailCacheSuccess extends UIState {} 5 | 6 | class CleanupEmailCacheFailure extends FeatureFailure { 7 | 8 | CleanupEmailCacheFailure(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /lib/features/composer/domain/state/save_email_address_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class SaveEmailAddressSuccess extends UIState {} 5 | 6 | class SaveEmailAddressFailure extends FeatureFailure { 7 | 8 | SaveEmailAddressFailure(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /lib/features/email/presentation/styles/email_view_styles.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class EmailViewStyles { 4 | static const EdgeInsetsGeometry emailContentPadding = 5 | EdgeInsetsDirectional.symmetric(horizontal: 16); 6 | static const EdgeInsetsGeometry mobileEmailContentPadding = 7 | EdgeInsetsDirectional.only(start: 12, end: 12, top: 12); 8 | } -------------------------------------------------------------------------------- /lib/features/login/data/extensions/token_oidc_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:model/oidc/token_oidc.dart'; 2 | import 'package:tmail_ui_user/features/login/data/model/token_oidc_cache.dart'; 3 | 4 | extension TokenOidcExtension on TokenOIDC { 5 | TokenOidcCache toTokenOidcCache() { 6 | return TokenOidcCache(token, tokenId.uuid, refreshToken, expiredTime: expiredTime); 7 | } 8 | } -------------------------------------------------------------------------------- /lib/features/mailbox/presentation/styles/empty_mailbox_popup_dialog_widget_styles.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class EmptyMailboxPopupDialogWidgetStyles { 4 | static const EdgeInsetsGeometry emptyButtonPadding = 5 | EdgeInsetsDirectional.symmetric(vertical: 4, horizontal: 8); 6 | 7 | static const Offset dialogOverlayOffset = Offset(0.0, 50.0); 8 | } 9 | -------------------------------------------------------------------------------- /lib/features/manage_account/domain/model/preferences/empty_preferences_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.dart'; 2 | 3 | class EmptyPreferencesConfig extends PreferencesConfig { 4 | @override 5 | List get props => []; 6 | 7 | @override 8 | Map toJson() => {}; 9 | } 10 | -------------------------------------------------------------------------------- /server_settings/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9" 8 | channel: "stable" 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /integration_test/tests/mailbox/mark_mailbox_as_read_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/mark_mailbox_as_read_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should not see unread counter when mark mailbox as read', 7 | scenarioBuilder: ($) => MarkMailboxAsReadScenario($), 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /lib/features/login/domain/state/save_recent_login_url_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class SaveRecentLoginUrlSuccess extends UIState {} 5 | 6 | class SaveRecentLoginUrlFailed extends FeatureFailure { 7 | 8 | SaveRecentLoginUrlFailed(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /lib/features/thread/data/extensions/email_address_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; 3 | import 'package:tmail_ui_user/features/thread/data/model/email_address_hive_cache.dart'; 4 | 5 | extension EmailAddressExtension on EmailAddress { 6 | 7 | EmailAddressHiveCache toEmailAddressHiveCache() => EmailAddressHiveCache(name, email); 8 | } -------------------------------------------------------------------------------- /lib/features/thread/data/extensions/email_address_hive_cache_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; 3 | import 'package:tmail_ui_user/features/thread/data/model/email_address_hive_cache.dart'; 4 | 5 | extension EmailAddressHiveCacheExtension on EmailAddressHiveCache { 6 | 7 | EmailAddress toEmailAddress() => EmailAddress(name, email); 8 | } -------------------------------------------------------------------------------- /lib/main/bindings/network/binding_tag.dart: -------------------------------------------------------------------------------- 1 | class BindingTag { 2 | static const isolateTag = 'isolateTag'; 3 | static const cleanUpPublicAssetsInteractorBindingsTag = 'CleanUpPublicAssetsInteractorBindingsTag'; 4 | static const publicAssetBindingsTag = 'PublicAssetBindingsTag'; 5 | static const restoreIdentityCacheInteractorBindingsTag = 'RestoreIdentityCacheInteractorBindingsTag'; 6 | } -------------------------------------------------------------------------------- /lib/main/deep_links/deep_link_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tmail_ui_user/main/deep_links/deep_link_action_type.dart'; 3 | 4 | class DeepLinkData with EquatableMixin { 5 | final DeepLinkActionType actionType; 6 | 7 | DeepLinkData({required this.actionType}); 8 | 9 | @override 10 | List get props => [actionType]; 11 | } 12 | -------------------------------------------------------------------------------- /model/lib/extensions/list_mailbox_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; 3 | 4 | extension ListMailboxExtension on List { 5 | 6 | Mailbox? findMailbox(MailboxId mailboxId) { 7 | try { 8 | return firstWhere((element) => element.id == mailboxId); 9 | } catch (e) { 10 | return null; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /fcm/lib/model/firebase_registration_expired_time.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | import 'package:jmap_dart_client/jmap/core/utc_date.dart'; 4 | 5 | class FirebaseRegistrationExpiredTime with EquatableMixin { 6 | 7 | final UTCDate value; 8 | 9 | FirebaseRegistrationExpiredTime(this.value); 10 | 11 | @override 12 | List get props => [value]; 13 | } -------------------------------------------------------------------------------- /integration_test/tests/attachments/download_all_attachments_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/download_all_attachments_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see save dialog when download all attachments successfully', 7 | scenarioBuilder: ($) => DownloadAllAttachmentsScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/attachments/no_disposition_inline_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/no_disposition_inline_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see base64 inline image when attachment has no disposition but has cid', 7 | scenarioBuilder: ($) => NoDispositionInlineScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/email_detailed/export_attachment_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/email_detailed/export_attachment_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should auto preview attachment when export attachment successfully', 7 | scenarioBuilder: ($) => ExportAttachmentScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/quick_filter_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/quick_filter_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see email with expected condition ' 7 | 'when quick filter email changed', 8 | scenarioBuilder: ($) => QuickFilterScenario($), 9 | ); 10 | } -------------------------------------------------------------------------------- /lib/features/caching/clients/recent_login_url_cache_client.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart'; 2 | import 'package:tmail_ui_user/features/login/data/model/recent_login_url_cache.dart'; 3 | 4 | class RecentLoginUrlCacheClient extends HiveCacheClient { 5 | 6 | @override 7 | String get tableName => 'RecentLoginUrlCache'; 8 | } -------------------------------------------------------------------------------- /lib/features/identity_creator/presentation/utils/identity_creator_constants.dart: -------------------------------------------------------------------------------- 1 | 2 | class IdentityCreatorConstants { 3 | static const double maxWidthInlineImageDesktop = 800; // Pixel 4 | static const double maxWidthInlineImageOther = 700; // Pixel 5 | static const String prefixCompressedInlineImageTemp = 'compressed_'; 6 | static const int qualityCompressedInlineImage = 80; // 0 - 100 7 | } -------------------------------------------------------------------------------- /lib/features/login/domain/state/delete_authority_oidc_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class DeleteAuthorityOidcSuccess extends UIState {} 5 | 6 | class DeleteAuthorityOidcFailure extends FeatureFailure { 7 | 8 | DeleteAuthorityOidcFailure(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/domain/state/save_composer_cache_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class SaveComposerCacheSuccess extends UIState {} 5 | 6 | class SaveComposerCacheFailure extends FeatureFailure { 7 | 8 | SaveComposerCacheFailure(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /lib/features/mailbox_dashboard/domain/state/save_recent_search_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class SaveRecentSearchSuccess extends UIState {} 5 | 6 | class SaveRecentSearchFailure extends FeatureFailure { 7 | 8 | SaveRecentSearchFailure(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /lib/main/localizations/language_code_constants.dart: -------------------------------------------------------------------------------- 1 | 2 | class LanguageCodeConstants { 3 | static const String english = 'en'; 4 | static const String french = 'fr'; 5 | static const String german = 'de'; 6 | static const String vietnamese = 'vi'; 7 | static const String italian = 'it'; 8 | static const String russian = 'ru'; 9 | static const String arabic = 'ar'; 10 | } 11 | -------------------------------------------------------------------------------- /model/lib/error_type_handler/set_method_error_handler_mixin.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; 2 | import 'package:jmap_dart_client/jmap/core/id.dart'; 3 | 4 | typedef SetMethodErrors = Map; 5 | 6 | /// Returns true if handle [setError] successfully and otherwise 7 | typedef SetMethodErrorHandler = bool Function(MapEntry setError); 8 | -------------------------------------------------------------------------------- /assets/images/ic_minimize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /backend-docker/deletedMessageVault.properties: -------------------------------------------------------------------------------- 1 | # ============================================= Deleted Messages Vault Configuration ================================== 2 | 3 | enabled=true 4 | restoreLocation=Restored-Messages 5 | 6 | # Retention period for your deleted messages into the vault, after which they expire and can be potentially cleaned up 7 | # Optional, default 1y 8 | # retentionPeriod=1y -------------------------------------------------------------------------------- /integration_test/tests/email_detailed/delete_email_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/email_detailed/delete_email_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see email in Trash folder when open detailed email and delete email successfully', 7 | scenarioBuilder: ($) => DeleteEmailScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/create_and_hide_sub_folder_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/create_and_hide_sub_folder_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should create and hide sub folder successfully', 7 | scenarioBuilder: ($) => CreateAndHideSubFolderScenario($), 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /lib/features/caching/clients/recent_search_cache_client.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart'; 3 | import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/recent_search_cache.dart'; 4 | 5 | class RecentSearchCacheClient extends HiveCacheClient { 6 | 7 | @override 8 | String get tableName => 'RecentSearchCache'; 9 | } -------------------------------------------------------------------------------- /lib/features/cleanup/domain/model/recent_login_url_cleanup_rule.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:tmail_ui_user/features/cleanup/domain/model/cleanup_rule.dart'; 3 | 4 | class RecentLoginUrlCleanupRule extends CleanupRule { 5 | final int storageLimit; 6 | 7 | RecentLoginUrlCleanupRule({this.storageLimit = 10}) : super(); 8 | 9 | @override 10 | List get props => [storageLimit]; 11 | } -------------------------------------------------------------------------------- /lib/features/login/domain/model/base_url_oidc_response.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:model/oidc/response/oidc_link_dto.dart'; 3 | import 'package:model/oidc/response/oidc_response.dart'; 4 | 5 | class BaseUrlOidcResponse extends OIDCResponse { 6 | 7 | BaseUrlOidcResponse(Uri baseUri) : super( 8 | '', 9 | [ 10 | OIDCLinkDto(baseUri, baseUri) 11 | ], 12 | ); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /lib/features/manage_account/presentation/email_rules/bindings/email_rules_bindings.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get.dart'; 2 | import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/email_rules_controller.dart'; 3 | 4 | class EmailRulesBindings extends Bindings { 5 | 6 | @override 7 | void dependencies() { 8 | Get.lazyPut(() => EmailRulesController()); 9 | } 10 | } -------------------------------------------------------------------------------- /lib/features/manage_account/presentation/menu/manage_account_menu_bindings.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get.dart'; 2 | import 'package:tmail_ui_user/features/manage_account/presentation/menu/manage_account_menu_controller.dart'; 3 | 4 | class ManageAccountMenuBindings extends Bindings { 5 | 6 | @override 7 | void dependencies() { 8 | Get.put(ManageAccountMenuController()); 9 | } 10 | } -------------------------------------------------------------------------------- /lib/features/thread/domain/state/clean_and_get_all_email_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class CleanAndGetAllEmailLoading extends LoadingState {} 5 | 6 | class CleanAndGetAllEmailFailure extends FeatureFailure { 7 | 8 | CleanAndGetAllEmailFailure(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /core/lib/presentation/extensions/map_extensions.dart: -------------------------------------------------------------------------------- 1 | 2 | extension MapExtensions on Map { 3 | 4 | Map where(bool Function(K, V) condition) { 5 | Map result = {}; 6 | for (var element in entries) { 7 | if (condition(element.key, element.value)) { 8 | result[element.key] = element.value; 9 | } 10 | } 11 | return result; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/lib/presentation/utils/keyboard_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/services.dart'; 3 | 4 | class KeyboardUtils { 5 | static void hideKeyboard(BuildContext context) { 6 | FocusScope.of(context).unfocus(); 7 | } 8 | 9 | static void hideSystemKeyboardMobile() { 10 | SystemChannels.textInput.invokeMethod('TextInput.hide'); 11 | } 12 | } -------------------------------------------------------------------------------- /integration_test/tests/email_detailed/archive_email_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/email_detailed/archive_email_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see email in Archive folder when open detailed email and archive email successfully', 7 | scenarioBuilder: ($) => ArchiveEmailScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/email/presentation/styles/calendar_event_action_banner_styles.dart: -------------------------------------------------------------------------------- 1 | 2 | class CalendarEventActionBannerStyles { 3 | static const double borderRadius = 12; 4 | static const double contentPadding = 12; 5 | static const double viewHorizontalMargin = 16; 6 | static const double viewVerticalMargin = 12; 7 | static const double titleTextSize = 16; 8 | static const double iconSize = 20; 9 | } -------------------------------------------------------------------------------- /lib/features/email/presentation/styles/email_view_empty_styles.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:core/presentation/extensions/color_extension.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class EmailViewEmptyStyles { 6 | static const double textSize = 25; 7 | 8 | static const Color textColor = AppColor.mailboxTextColor; 9 | 10 | static const FontWeight fontWeight = FontWeight.bold; 11 | } -------------------------------------------------------------------------------- /lib/features/starting_page/domain/repository/saas_authentication_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:model/oidc/oidc_configuration.dart'; 2 | import 'package:model/oidc/token_oidc.dart'; 3 | 4 | abstract class SaasAuthenticationRepository { 5 | Future signInTwakeWorkplace(OIDCConfiguration oidcConfiguration); 6 | 7 | Future signUpTwakeWorkplace(OIDCConfiguration oidcConfiguration); 8 | } -------------------------------------------------------------------------------- /lib/features/upload/data/datasource/attachment_upload_datasource.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:dio/dio.dart'; 3 | import 'package:model/upload/file_info.dart'; 4 | import 'package:tmail_ui_user/features/upload/domain/model/upload_attachment.dart'; 5 | 6 | abstract class AttachmentUploadDataSource { 7 | Future uploadAttachment(FileInfo fileInfo, Uri uploadUri, {CancelToken? cancelToken}); 8 | } -------------------------------------------------------------------------------- /model/lib/extensions/set_email_body_part_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart'; 2 | import 'package:model/extensions/email_body_part_extension.dart'; 3 | 4 | extension SetEmailBodyPartExtension on Set { 5 | Set onlyUseBlobIdOrPartId() => 6 | map((emailBodyPart) => emailBodyPart.onlyUseBlobIdOrPartId()).toSet(); 7 | } 8 | -------------------------------------------------------------------------------- /integration_test/tests/mailbox/mailbox_count_real_time_update_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/mailbox_count_real_time_update_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see mailbox unread count update real time', 7 | scenarioBuilder: ($) => MailboxCountRealTimeUpdateScenario($), 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /integration_test/tests/thread_detail/thread_detail_reply_real_time_update_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/thread_detail/thread_detail_reply_real_time_update_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see reply of thread detail', 7 | scenarioBuilder: ($) => ThreadDetailReplyRealTimeUpdateScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /ios/TeamMailShareExtension/TeamMailShareExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.com.linagora.teammail 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /lib/features/cleanup/domain/model/recent_login_username_cleanup_rule.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/cleanup/domain/model/cleanup_rule.dart'; 2 | 3 | class RecentLoginUsernameCleanupRule extends CleanupRule { 4 | final int storageLimit; 5 | 6 | RecentLoginUsernameCleanupRule({this.storageLimit = 10}) : super(); 7 | 8 | @override 9 | List get props => [storageLimit]; 10 | } -------------------------------------------------------------------------------- /lib/features/login/domain/state/save_recent_login_username_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class SaveRecentLoginUsernameSuccess extends UIState {} 5 | 6 | class SaveRecentLoginUsernameFailed extends FeatureFailure { 7 | 8 | SaveRecentLoginUsernameFailed(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /lib/features/quotas/domain/extensions/list_quotas_extensions.dart: -------------------------------------------------------------------------------- 1 | import 'package:collection/collection.dart'; 2 | import 'package:jmap_dart_client/jmap/quotas/data_types.dart'; 3 | import 'package:jmap_dart_client/jmap/quotas/quota.dart'; 4 | 5 | extension ListQuotasExtensions on List { 6 | Quota? get octetsQuota => 7 | firstWhereOrNull((quota) => quota.resourceType == ResourceType.octets); 8 | } -------------------------------------------------------------------------------- /lib/features/search/email/presentation/styles/email_sort_by_action_tile_widget_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class EmailSortByActionTitleWidgetStyle { 4 | static const EdgeInsetsGeometry padding = EdgeInsets.symmetric(horizontal: 24, vertical: 16); 5 | 6 | static const double width = 332.0; 7 | static const double space = 12.0; 8 | static const double iconSize = 24.0; 9 | } -------------------------------------------------------------------------------- /lib/features/search/email/presentation/styles/email_sort_by_cupertino_action_sheet_action_builder_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class EmailSortByCupertinoActionSheetActionBuilderStyle { 4 | static const double space = 16.0; 5 | 6 | static const EdgeInsetsDirectional iconPadding = EdgeInsetsDirectional.only(end: space); 7 | 8 | static const backgroundColor = Colors.white; 9 | } -------------------------------------------------------------------------------- /lib/features/starting_page/data/datasource/saas_authentication_datasource.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:model/oidc/oidc_configuration.dart'; 3 | import 'package:model/oidc/token_oidc.dart'; 4 | 5 | abstract class SaasAuthenticationDataSource { 6 | Future signInTwakeWorkplace(OIDCConfiguration oidcConfiguration); 7 | 8 | Future signUpTwakeWorkplace(OIDCConfiguration oidcConfiguration); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/team_mailbox_receive_email_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/team_mailbox_receive_email_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see email in team mailbox INBOX after sending to team mailbox address', 7 | scenarioBuilder: ($) => TeamMailboxReceiveEmailScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/push_notification/data/datasource/web_socket_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/account_id.dart'; 2 | import 'package:jmap_dart_client/jmap/core/session/session.dart'; 3 | import 'package:web_socket_channel/web_socket_channel.dart'; 4 | 5 | abstract class WebSocketDatasource { 6 | Future getWebSocketChannel( 7 | Session session, 8 | AccountId accountId); 9 | } -------------------------------------------------------------------------------- /lib/features/push_notification/presentation/extensions/state_change_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/account_id.dart'; 3 | import 'package:jmap_dart_client/jmap/push/state_change.dart'; 4 | 5 | extension StateChangeExtension on StateChange? { 6 | 7 | Map getMapTypeState(AccountId accountId) { 8 | return this?.changed[accountId]?.typeState ?? {}; 9 | } 10 | } -------------------------------------------------------------------------------- /lib/features/thread_detail/presentation/model/thread_detail_arguments.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:jmap_dart_client/jmap/mail/email/email.dart'; 3 | 4 | class ThreadDetailArguments with EquatableMixin { 5 | final ThreadId threadId; 6 | 7 | const ThreadDetailArguments({required this.threadId}); 8 | 9 | @override 10 | List get props => [threadId]; 11 | } -------------------------------------------------------------------------------- /model/lib/extensions/contact_support_capability_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:model/support/contact_support_capability.dart'; 3 | 4 | extension ContactSupportCapabilityExtension on ContactSupportCapability { 5 | 6 | bool get isMailAddressSupported => 7 | supportMailAddress?.trim().isNotEmpty == true; 8 | 9 | bool get isHttpLinkSupported => 10 | httpLink?.trim().isNotEmpty == true; 11 | } -------------------------------------------------------------------------------- /core/lib/data/network/download/downloaded_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:http_parser/http_parser.dart'; 3 | 4 | class DownloadedResponse with EquatableMixin { 5 | final String filePath; 6 | final MediaType? mediaType; 7 | 8 | DownloadedResponse(this.filePath, {this.mediaType}); 9 | 10 | @override 11 | List get props => [filePath, mediaType]; 12 | } -------------------------------------------------------------------------------- /integration_test/tests/email_detailed/mark_as_spam_email_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/email_detailed/mark_as_spam_email_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see email in Spam folder when open detailed email and mark as spam email successfully', 7 | scenarioBuilder: ($) => MarkAsSpamEmailScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/long_press_empty_and_recover_spam_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/long_press_empty_and_recover_spam_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should empty and recover spam by long press mailbox successfully', 7 | scenarioBuilder: ($) => LongPressEmptyAndRecoverSpamScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/search/search_email_with_sort_order_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/search_email_with_sort_order_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see list email displayed by sort order selected when search email successfully', 7 | scenarioBuilder: ($) => SearchEmailWithSortOrderScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/search/search_snippets_with_html_escape_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/search/search_snippets_with_html_escape_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see email with subject escaped when search email successfully', 7 | scenarioBuilder: ($) => SearchSnippetsWithHtmlEscapeScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/setting/identity/select_identity_as_default_test.dart: -------------------------------------------------------------------------------- 1 | import '../../../base/test_base.dart'; 2 | import '../../../scenarios/setting/identity/set_identity_as_default_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see identity as default when select identity as default', 7 | scenarioBuilder: ($) => SetIdentityAsDefaultScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/setting/language/change_language_test.dart: -------------------------------------------------------------------------------- 1 | import '../../../base/test_base.dart'; 2 | import '../../../scenarios/setting/language/change_language_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see title in Setting change language when successfully selecting another language', 7 | scenarioBuilder: ($) => ChangeLanguageScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/caching/clients/recent_login_username_cache_client.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart'; 2 | import 'package:tmail_ui_user/features/login/data/model/recent_login_username_cache.dart'; 3 | 4 | class RecentLoginUsernameCacheClient extends HiveCacheClient { 5 | 6 | @override 7 | String get tableName => 'RecentLoginUsernameCache'; 8 | } -------------------------------------------------------------------------------- /lib/features/push_notification/domain/repository/web_socket_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:jmap_dart_client/jmap/account_id.dart'; 2 | import 'package:jmap_dart_client/jmap/core/session/session.dart'; 3 | import 'package:web_socket_channel/web_socket_channel.dart'; 4 | 5 | abstract class WebSocketRepository { 6 | Future getWebSocketChannel( 7 | Session session, 8 | AccountId accountId); 9 | } -------------------------------------------------------------------------------- /scripts/configure-web-environment.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -eux 4 | sed -i "s|SERVER_URL=.*|SERVER_URL=https://apisix.upn.integration-open-paas.org/|g" env.file 5 | sed -i "s|DOMAIN_REDIRECT_URL=.*|DOMAIN_REDIRECT_URL=https://$GITHUB_REPOSITORY_OWNER.github.io/${GITHUB_REPOSITORY##*/}/$FOLDER|g" env.file 6 | echo "URL=https://$GITHUB_REPOSITORY_OWNER.github.io/${GITHUB_REPOSITORY##*/}/$FOLDER" >> $GITHUB_OUTPUT 7 | -------------------------------------------------------------------------------- /fcm/lib/converter/type_name_converter.dart: -------------------------------------------------------------------------------- 1 | import 'package:fcm/model/type_name.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | class TypeNameConverter implements JsonConverter { 5 | const TypeNameConverter(); 6 | 7 | @override 8 | TypeName fromJson(String json) => TypeName(json); 9 | 10 | @override 11 | String toJson(TypeName object) => object.value; 12 | } 13 | -------------------------------------------------------------------------------- /integration_test/tests/email_detailed/deformed_inlined_image_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/email_detailed/deformed_inlined_image_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see normalized inline image when open email with content contain inline image', 7 | scenarioBuilder: ($) => DeformedInlinedImageScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/email_detailed/display_email_with_short_content_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/email_detailed/display_email_with_short_content_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should display full content when opening a short email', 7 | scenarioBuilder: ($) => DisplayEmailWithShortContentScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/long_press_empty_and_recover_trash_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/long_press_empty_and_recover_trash_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should empty and recover trash by long press mailbox successfully', 7 | scenarioBuilder: ($) => LongPressEmptyAndRecoverTrashScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/mark_single_selected_email_as_read_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/mark_single_selected_email_as_read_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see selected email mark as read successfully', 7 | scenarioBuilder: ($) => MarkSingleSelectedEmailAsReadScenario($), 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /integration_test/tests/mailbox/mark_single_selected_email_as_spam_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/mark_single_selected_email_as_spam_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see selected email mark as spam successfully', 7 | scenarioBuilder: ($) => MarkSingleSelectedEmailAsSpamScenario($), 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /integration_test/tests/mailbox/mark_single_selected_email_as_star_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/mark_single_selected_email_as_star_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see selected email mark as star successfully', 7 | scenarioBuilder: ($) => MarkSingleSelectedEmailAsStarScenario($), 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /lib/features/cleanup/domain/state/cleanup_recent_login_url_cache_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class CleanupRecentLoginUrlCacheSuccess extends UIState {} 5 | 6 | class CleanupRecentLoginUrlCacheFailure extends FeatureFailure { 7 | 8 | CleanupRecentLoginUrlCacheFailure(dynamic exception) : super(exception: exception); 9 | } -------------------------------------------------------------------------------- /lib/features/contact/presentation/contact_bindings.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:get/get.dart'; 3 | import 'package:tmail_ui_user/features/contact/presentation/contact_controller.dart'; 4 | 5 | class ContactBindings extends Bindings { 6 | 7 | @override 8 | void dependencies() { 9 | Get.lazyPut(() => ContactController()); 10 | } 11 | 12 | void dispose() { 13 | Get.delete(); 14 | } 15 | } -------------------------------------------------------------------------------- /lib/features/email/domain/state/print_email_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class PrintEmailLoading extends LoadingState {} 5 | 6 | class PrintEmailSuccess extends UIState {} 7 | 8 | class PrintEmailFailure extends FeatureFailure { 9 | 10 | PrintEmailFailure({dynamic exception}) : super(exception: exception); 11 | } -------------------------------------------------------------------------------- /lib/features/email/presentation/styles/attendee_widget_styles.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:core/presentation/extensions/color_extension.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class AttendeeWidgetStyles { 6 | static const double maxWidth = 100; 7 | static const double textSize = 16; 8 | static const Color textColor = Colors.black; 9 | static const Color mailtoColor = AppColor.colorMailto; 10 | } -------------------------------------------------------------------------------- /lib/features/email/presentation/styles/organizer_widget_styles.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:core/presentation/extensions/color_extension.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class OrganizerWidgetStyles { 6 | static const double maxWidth = 100; 7 | static const double textSize = 16; 8 | static const Color textColor = Colors.black; 9 | static const Color mailtoColor = AppColor.colorMailto; 10 | } -------------------------------------------------------------------------------- /lib/features/manage_account/domain/state/toggle_notification_setting_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/manage_account/domain/state/notification_setting_state.dart'; 2 | 3 | class TogglingNotificationSetting extends NotificationSettingHandling {} 4 | 5 | class ToggleNotificationSettingSuccess extends NotificationSettingSuccess {} 6 | 7 | class ToggleNotificationSettingFailure extends NotificationSettingFailure {} -------------------------------------------------------------------------------- /model/lib/oidc/converter/token_id_converter.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:model/oidc/token_id.dart'; 4 | 5 | class TokenIdConverter implements JsonConverter { 6 | const TokenIdConverter(); 7 | 8 | @override 9 | TokenId fromJson(String json) => TokenId(json); 10 | 11 | @override 12 | String toJson(TokenId tokenId) => tokenId.uuid; 13 | } -------------------------------------------------------------------------------- /integration_test/tests/email_detailed/mark_as_star_email_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/email_detailed/mark_as_star_email_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see star and unStar icon when open detailed email and mark as star and unStar email successfully', 7 | scenarioBuilder: ($) => MarkAsStarEmailScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/create_rename_move_and_delete_mailbox_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/create_rename_move_and_delete_mailbox_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should create, rename, move and delete mailbox successfully', 7 | scenarioBuilder: ($) => CreateRenameMoveAndDeleteMailboxScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /assets/images/ic_more.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /core/lib/utils/list_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | 3 | Tuple2, List> partition(List list, bool Function(T) predicate) { 4 | List trueList = []; 5 | List falseList = []; 6 | 7 | for (var element in list) { 8 | if (predicate(element)) { 9 | trueList.add(element); 10 | } else { 11 | falseList.add(element); 12 | } 13 | } 14 | 15 | return Tuple2(trueList, falseList); 16 | } -------------------------------------------------------------------------------- /core/lib/utils/logger/trace_log.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class TraceLog with EquatableMixin { 4 | final String path; 5 | final int size; 6 | final List listFilePaths; 7 | 8 | TraceLog({ 9 | required this.path, 10 | required this.size, 11 | required this.listFilePaths 12 | }); 13 | 14 | @override 15 | List get props => [path, size, listFilePaths]; 16 | } -------------------------------------------------------------------------------- /core/lib/utils/mail/named_address.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class NamedAddress with EquatableMixin { 4 | final String name; 5 | final String address; 6 | 7 | NamedAddress({required this.name, required this.address}); 8 | 9 | @override 10 | List get props => [name, address]; 11 | 12 | @override 13 | String toString() => name.isNotEmpty ? '$name <$address>' : address; 14 | } -------------------------------------------------------------------------------- /fcm/lib/model/type_name.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | class TypeName with EquatableMixin { 5 | static const mailboxType = TypeName('Mailbox'); 6 | static const emailType = TypeName('Email'); 7 | static const emailDelivery = TypeName('EmailDelivery'); 8 | 9 | final String value; 10 | 11 | const TypeName(this.value); 12 | 13 | @override 14 | List get props => [value]; 15 | } -------------------------------------------------------------------------------- /integration_test/tests/mailbox/display_empty_view_for_favorite_folder_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/display_empty_view_for_favorite_folder_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should display empty view when no mail favorites', 7 | scenarioBuilder: ($) => DisplayEmptyViewForFavoriteFolderScenario($), 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /integration_test/tests/mailbox/move_folder_content_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/mailbox/move_folder_content_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see all Inbox emails in the Templates folder when perform move folder content action successfully', 7 | scenarioBuilder: ($) => MoveFolderContentScenario($), 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /lib/features/caching/clients/token_oidc_cache_client.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmail_ui_user/features/caching/config/hive_cache_client.dart'; 2 | import 'package:tmail_ui_user/features/login/data/model/token_oidc_cache.dart'; 3 | 4 | class TokenOidcCacheClient extends HiveCacheClient { 5 | 6 | @override 7 | String get tableName => 'TokenOidcCache'; 8 | 9 | @override 10 | bool get encryption => true; 11 | } -------------------------------------------------------------------------------- /lib/features/composer/presentation/extensions/setup_email_request_read_receipt_flag_for_edit_draft_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; 3 | 4 | extension SetupEmailRequestReadReceiptFlagExtension on ComposerController { 5 | 6 | void setupEmailRequestReadReceiptFlag(bool isRequestReadReceipt) { 7 | hasRequestReadReceipt.value = isRequestReadReceipt; 8 | } 9 | } -------------------------------------------------------------------------------- /lib/features/email/data/datasource/mdn_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:jmap_dart_client/jmap/account_id.dart'; 4 | import 'package:jmap_dart_client/jmap/mdn/mdn.dart'; 5 | import 'package:tmail_ui_user/features/email/domain/model/send_receipt_to_sender_request.dart'; 6 | 7 | abstract class MdnDataSource { 8 | Future sendReceiptToSender(AccountId accountId, SendReceiptToSenderRequest request); 9 | } -------------------------------------------------------------------------------- /lib/features/email/domain/repository/mdn_repository.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:jmap_dart_client/jmap/account_id.dart'; 4 | import 'package:jmap_dart_client/jmap/mdn/mdn.dart'; 5 | import 'package:tmail_ui_user/features/email/domain/model/send_receipt_to_sender_request.dart'; 6 | 7 | abstract class MdnRepository { 8 | Future sendReceiptToSender(AccountId accountId, SendReceiptToSenderRequest request); 9 | } -------------------------------------------------------------------------------- /lib/features/email/domain/state/store_new_email_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class StoreNewEmailLoading extends UIState {} 5 | 6 | class StoreNewEmailSuccess extends UIState {} 7 | 8 | class StoreNewEmailFailure extends FeatureFailure { 9 | 10 | StoreNewEmailFailure(dynamic exception) : super(exception: exception); 11 | } -------------------------------------------------------------------------------- /lib/features/home/domain/state/store_session_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/presentation/state/failure.dart'; 2 | import 'package:core/presentation/state/success.dart'; 3 | 4 | class StoreSessionLoading extends LoadingState {} 5 | 6 | class StoreSessionSuccess extends UIState {} 7 | 8 | class StoreSessionFailure extends FeatureFailure { 9 | 10 | StoreSessionFailure(dynamic exception) : super(exception: exception); 11 | } -------------------------------------------------------------------------------- /lib/features/login/data/extensions/token_oidc_cache_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:model/oidc/token_id.dart'; 2 | import 'package:model/oidc/token_oidc.dart'; 3 | import 'package:tmail_ui_user/features/login/data/model/token_oidc_cache.dart'; 4 | 5 | extension TokenOidcCacheExtension on TokenOidcCache { 6 | TokenOIDC toTokenOidc() { 7 | return TokenOIDC(token, TokenId(tokenId), refreshToken, expiredTime: expiredTime); 8 | } 9 | } -------------------------------------------------------------------------------- /integration_test/tests/email_detailed/display_email_with_xss_content_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/email_detailed/display_email_with_xss_content_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should not display alert dialog when opening an email containing content xss', 7 | scenarioBuilder: ($) => DisplayEmailWithXssContentScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /integration_test/tests/email_detailed/mark_as_unread_email_test.dart: -------------------------------------------------------------------------------- 1 | import '../../base/test_base.dart'; 2 | import '../../scenarios/email_detailed/mark_as_unread_email_scenario.dart'; 3 | 4 | void main() { 5 | TestBase().runPatrolTest( 6 | description: 'Should see email item has unread icon when open detailed email and select mark as unread email successfully', 7 | scenarioBuilder: ($) => MarkAsUnreadEmailScenario($), 8 | ); 9 | } -------------------------------------------------------------------------------- /lib/features/email/presentation/extensions/calendar_organier_extension.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:jmap_dart_client/jmap/mail/calendar/properties/calendar_organizer.dart'; 3 | import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; 4 | 5 | extension CalendarOrganierExtension on CalendarOrganizer { 6 | EmailAddress toEmailAddress() { 7 | return EmailAddress( 8 | name, mailto?.value, 9 | ); 10 | } 11 | } --------------------------------------------------------------------------------