From eefac431e5a4c62386e38600327bdca151f14ee6 Mon Sep 17 00:00:00 2001 From: Mikhail Kilin Date: Wed, 20 May 2026 00:31:18 +0300 Subject: [PATCH] Split core and TUI crates --- Cargo.lock | 17 +++ Cargo.toml | 69 +-------- DEVELOPMENT.md | 8 +- README.md | 7 +- crates/tele-core/Cargo.toml | 29 ++++ crates/tele-core/src/accounts/mod.rs | 5 + crates/tele-core/src/accounts/profile.rs | 114 ++++++++++++++ crates/tele-core/src/constants.rs | 6 + crates/tele-core/src/lib.rs | 11 ++ .../tele-core/src}/message_grouping.rs | 6 +- {src => crates/tele-core/src}/tdlib/auth.rs | 0 .../tele-core/src}/tdlib/chat_helpers.rs | 0 {src => crates/tele-core/src}/tdlib/chats.rs | 0 {src => crates/tele-core/src}/tdlib/client.rs | 93 ++++++------ .../tele-core/src}/tdlib/client_impl.rs | 17 +-- .../src}/tdlib/message_conversion.rs | 0 .../tele-core/src}/tdlib/message_converter.rs | 0 .../tele-core/src}/tdlib/messages/convert.rs | 0 .../tele-core/src}/tdlib/messages/mod.rs | 0 .../src}/tdlib/messages/operations.rs | 0 {src => crates/tele-core/src}/tdlib/mod.rs | 5 +- .../tele-core/src}/tdlib/reactions.rs | 0 {src => crates/tele-core/src}/tdlib/trait.rs | 14 +- {src => crates/tele-core/src}/tdlib/types.rs | 4 +- .../tele-core/src}/tdlib/update_handlers.rs | 7 +- {src => crates/tele-core/src}/tdlib/users.rs | 0 .../src}/test_support/fake_tdclient.rs | 0 .../test_support/fake_tdclient/builders.rs | 0 .../test_support/fake_tdclient/inspect.rs | 0 .../test_support/fake_tdclient/operations.rs | 0 .../src}/test_support/fake_tdclient/state.rs | 0 .../src}/test_support/fake_tdclient_impl.rs | 12 +- crates/tele-core/src/test_support/mod.rs | 7 + .../tele-core/src}/test_support/test_data.rs | 0 {src => crates/tele-core/src}/types.rs | 0 crates/tele-core/src/utils.rs | 9 ++ crates/tele-tui/Cargo.toml | 66 ++++++++ .../tele-tui/benches}/format_markdown.rs | 0 .../tele-tui/benches}/formatting.rs | 0 .../tele-tui/benches}/group_messages.rs | 0 build.rs => crates/tele-tui/build.rs | 7 +- {src => crates/tele-tui/src}/accounts/lock.rs | 0 .../tele-tui/src}/accounts/manager.rs | 0 {src => crates/tele-tui/src}/accounts/mod.rs | 0 .../tele-tui/src}/accounts/profile.rs | 0 .../tele-tui/src}/app/auth_state.rs | 0 .../tele-tui/src}/app/chat_filter.rs | 0 .../tele-tui/src}/app/chat_list_state.rs | 0 .../tele-tui/src}/app/chat_state.rs | 0 .../tele-tui/src}/app/compose_state.rs | 0 .../tele-tui/src}/app/message_service.rs | 0 .../tele-tui/src}/app/message_view_state.rs | 0 .../tele-tui/src}/app/methods/compose.rs | 0 .../tele-tui/src}/app/methods/messages.rs | 0 .../tele-tui/src}/app/methods/mod.rs | 0 .../tele-tui/src}/app/methods/modal.rs | 0 .../tele-tui/src}/app/methods/navigation.rs | 0 .../tele-tui/src}/app/methods/search.rs | 0 {src => crates/tele-tui/src}/app/mod.rs | 19 ++- {src => crates/tele-tui/src}/app/state.rs | 0 {src => crates/tele-tui/src}/app/ui_state.rs | 0 {src => crates/tele-tui/src}/audio/cache.rs | 0 {src => crates/tele-tui/src}/audio/mod.rs | 0 {src => crates/tele-tui/src}/audio/player.rs | 0 .../src}/bin/tele-tui-test-fixture.rs | 0 .../tele-tui/src}/config/keybindings.rs | 0 {src => crates/tele-tui/src}/config/loader.rs | 0 {src => crates/tele-tui/src}/config/mod.rs | 0 .../tele-tui/src}/config/validation.rs | 0 {src => crates/tele-tui/src}/constants.rs | 6 + {src => crates/tele-tui/src}/formatting.rs | 0 {src => crates/tele-tui/src}/input/auth.rs | 0 .../tele-tui/src}/input/handlers/chat.rs | 0 .../src}/input/handlers/chat/media.rs | 0 .../tele-tui/src}/input/handlers/chat_list.rs | 0 .../src}/input/handlers/chat_loader.rs | 0 .../tele-tui/src}/input/handlers/clipboard.rs | 0 .../tele-tui/src}/input/handlers/compose.rs | 0 .../tele-tui/src}/input/handlers/global.rs | 3 +- .../tele-tui/src}/input/handlers/mod.rs | 0 .../tele-tui/src}/input/handlers/modal.rs | 0 .../src}/input/handlers/modal/account.rs | 0 .../src}/input/handlers/modal/delete.rs | 0 .../src}/input/handlers/modal/pinned.rs | 0 .../src}/input/handlers/modal/profile.rs | 0 .../src}/input/handlers/modal/reactions.rs | 0 .../tele-tui/src}/input/handlers/profile.rs | 0 .../tele-tui/src}/input/handlers/search.rs | 0 .../tele-tui/src}/input/main_input.rs | 0 {src => crates/tele-tui/src}/input/mod.rs | 0 {src => crates/tele-tui/src}/lib.rs | 5 +- {src => crates/tele-tui/src}/main.rs | 17 ++- {src => crates/tele-tui/src}/media/cache.rs | 0 .../tele-tui/src}/media/image_renderer.rs | 0 {src => crates/tele-tui/src}/media/mod.rs | 0 {src => crates/tele-tui/src}/notifications.rs | 16 ++ .../tele-tui/src}/test_support/app_builder.rs | 0 .../tele-tui/src}/test_support/mod.rs | 5 +- .../src}/test_support/snapshot_utils.rs | 0 {src => crates/tele-tui/src}/ui/auth.rs | 0 {src => crates/tele-tui/src}/ui/chat_list.rs | 0 .../src}/ui/components/chat_list_item.rs | 0 .../src}/ui/components/emoji_picker.rs | 0 .../src}/ui/components/input_field.rs | 0 .../src}/ui/components/message_bubble.rs | 0 .../src}/ui/components/message_list.rs | 0 .../tele-tui/src}/ui/components/mod.rs | 0 .../tele-tui/src}/ui/components/modal.rs | 0 .../tele-tui/src}/ui/compose_bar.rs | 0 {src => crates/tele-tui/src}/ui/footer.rs | 0 {src => crates/tele-tui/src}/ui/loading.rs | 0 .../tele-tui/src}/ui/main_screen.rs | 0 {src => crates/tele-tui/src}/ui/messages.rs | 0 .../tele-tui/src}/ui/messages/header.rs | 0 .../tele-tui/src}/ui/messages/list.rs | 0 .../tele-tui/src}/ui/messages/pinned.rs | 0 {src => crates/tele-tui/src}/ui/mod.rs | 0 .../src}/ui/modals/account_switcher.rs | 0 .../tele-tui/src}/ui/modals/delete_confirm.rs | 0 .../tele-tui/src}/ui/modals/image_viewer.rs | 0 {src => crates/tele-tui/src}/ui/modals/mod.rs | 0 .../tele-tui/src}/ui/modals/pinned.rs | 0 .../src}/ui/modals/reaction_picker.rs | 0 .../tele-tui/src}/ui/modals/search.rs | 0 {src => crates/tele-tui/src}/ui/profile.rs | 0 .../tele-tui/src}/utils/formatting.rs | 2 + {src => crates/tele-tui/src}/utils/mod.rs | 0 .../tele-tui/src}/utils/modal_handler.rs | 0 {src => crates/tele-tui/src}/utils/retry.rs | 0 {src => crates/tele-tui/src}/utils/tdlib.rs | 0 .../tele-tui/src}/utils/validation.rs | 0 .../tele-tui/tests}/account_switcher.rs | 0 {tests => crates/tele-tui/tests}/accounts.rs | 0 {tests => crates/tele-tui/tests}/chat_list.rs | 0 {tests => crates/tele-tui/tests}/config.rs | 0 {tests => crates/tele-tui/tests}/copy.rs | 0 .../tele-tui/tests}/delete_message.rs | 0 {tests => crates/tele-tui/tests}/drafts.rs | 0 {tests => crates/tele-tui/tests}/e2e_smoke.rs | 0 .../tele-tui/tests}/e2e_termwright.rs | 0 .../tele-tui/tests}/e2e_user_journey.rs | 0 .../tele-tui/tests}/edit_message.rs | 0 {tests => crates/tele-tui/tests}/footer.rs | 0 .../tele-tui/tests}/helpers/app_builder.rs | 0 .../tele-tui/tests}/helpers/fake_tdclient.rs | 0 .../tests}/helpers/fake_tdclient/builders.rs | 0 .../tests}/helpers/fake_tdclient/inspect.rs | 0 .../helpers/fake_tdclient/operations.rs | 0 .../tests}/helpers/fake_tdclient/state.rs | 0 .../tests}/helpers/fake_tdclient_impl.rs | 12 +- .../tele-tui/tests}/helpers/mod.rs | 0 .../tele-tui/tests}/helpers/snapshot_utils.rs | 0 .../tele-tui/tests}/helpers/test_data.rs | 0 .../tele-tui/tests}/input_field.rs | 0 .../tele-tui/tests}/input_navigation.rs | 0 {tests => crates/tele-tui/tests}/messages.rs | 0 {tests => crates/tele-tui/tests}/modals.rs | 0 .../tele-tui/tests}/navigation.rs | 0 .../tele-tui/tests}/network_typing.rs | 0 {tests => crates/tele-tui/tests}/profile.rs | 0 {tests => crates/tele-tui/tests}/reactions.rs | 0 .../tele-tui/tests}/reply_forward.rs | 0 {tests => crates/tele-tui/tests}/screens.rs | 0 {tests => crates/tele-tui/tests}/search.rs | 0 .../tele-tui/tests}/send_message.rs | 0 .../chat_list__chat_list_search_mode.snap | 0 .../chat_list__chat_list_three_chats.snap | 0 .../snapshots/chat_list__chat_long_title.snap | 0 .../snapshots/chat_list__chat_muted.snap | 0 .../snapshots/chat_list__chat_pinned.snap | 0 .../snapshots/chat_list__chat_selected.snap | 0 .../chat_list__chat_with_mentions.snap | 0 .../chat_list__chat_with_online_status.snap | 0 .../chat_list__chat_with_unread.snap | 0 .../snapshots/chat_list__empty_chat_list.snap | 0 .../snapshots/footer__footer_chat_list.snap | 0 .../footer__footer_network_connecting.snap | 0 ...oter__footer_network_connecting_proxy.snap | 0 .../footer__footer_network_waiting.snap | 0 .../snapshots/footer__footer_open_chat.snap | 0 .../snapshots/footer__footer_search_mode.snap | 0 .../snapshots/input_field__empty_input.snap | 0 .../input_field__input_editing_mode.snap | 0 .../input_field__input_long_text_2_lines.snap | 0 ...nput_field__input_long_text_max_lines.snap | 0 .../input_field__input_reply_mode.snap | 0 .../input_field__input_search_mode.snap | 0 .../input_field__input_with_text.snap | 0 .../snapshots/messages__album_incoming.snap | 0 .../snapshots/messages__album_outgoing.snap | 0 .../snapshots/messages__album_selected.snap | 0 ...messages__album_with_regular_messages.snap | 0 .../messages__date_separator_old_date.snap | 0 .../snapshots/messages__edited_message.snap | 0 .../snapshots/messages__empty_chat.snap | 0 .../messages__forwarded_message.snap | 0 .../messages__long_message_wrap.snap | 0 .../messages__markdown_bold_italic_code.snap | 0 .../messages__markdown_link_mention.snap | 0 .../snapshots/messages__markdown_spoiler.snap | 0 .../messages__media_placeholder.snap | 0 .../messages__multiple_reactions.snap | 0 .../snapshots/messages__outgoing_read.snap | 0 .../snapshots/messages__outgoing_sent.snap | 0 .../snapshots/messages__reply_message.snap | 0 .../snapshots/messages__selected_message.snap | 0 .../snapshots/messages__sender_grouping.snap | 0 .../messages__single_incoming_message.snap | 0 .../messages__single_outgoing_message.snap | 0 .../snapshots/messages__single_reaction.snap | 0 .../modals__delete_confirmation_modal.snap | 0 .../modals__emoji_picker_default.snap | 0 .../modals__emoji_picker_with_selection.snap | 0 .../snapshots/modals__forward_mode.snap | 0 .../snapshots/modals__pinned_message.snap | 0 .../snapshots/modals__profile_group_chat.snap | 0 .../modals__profile_personal_chat.snap | 0 .../snapshots/modals__search_in_chat.snap | 0 .../snapshots/screens__auth_screen_code.snap | 0 .../screens__auth_screen_password.snap | 0 .../snapshots/screens__auth_screen_phone.snap | 0 .../screens__loading_screen_default.snap | 0 .../screens__loading_screen_with_status.snap | 0 ..._main_screen_account_switcher_overlay.snap | 0 ...screens__main_screen_chat_list_loaded.snap | 0 ...s__main_screen_chat_open_narrow_valid.snap | 0 ...__main_screen_chat_open_with_messages.snap | 0 .../snapshots/screens__main_screen_empty.snap | 0 ...reens__main_screen_terminal_too_small.snap | 0 ...hots__style_reaction_picker_selection.snap | 0 .../style_snapshots__style_selected_chat.snap | 0 ...yle_snapshots__style_selected_message.snap | 0 .../tele-tui/tests}/style_snapshots.rs | 0 {tests => crates/tele-tui/tests}/vim_mode.rs | 0 docs/IOS_CORE_REUSE.md | 28 ++++ docs/PROJECT_STRUCTURE.md | 42 ++++-- docs/TDLIB_INTEGRATION.md | 5 +- .../plans/2026-05-20-ios-app-roadmap.md | 142 ++++++++++++++++++ 238 files changed, 624 insertions(+), 191 deletions(-) create mode 100644 crates/tele-core/Cargo.toml create mode 100644 crates/tele-core/src/accounts/mod.rs create mode 100644 crates/tele-core/src/accounts/profile.rs create mode 100644 crates/tele-core/src/constants.rs create mode 100644 crates/tele-core/src/lib.rs rename {src => crates/tele-core/src}/message_grouping.rs (99%) rename {src => crates/tele-core/src}/tdlib/auth.rs (100%) rename {src => crates/tele-core/src}/tdlib/chat_helpers.rs (100%) rename {src => crates/tele-core/src}/tdlib/chats.rs (100%) rename {src => crates/tele-core/src}/tdlib/client.rs (93%) rename {src => crates/tele-core/src}/tdlib/client_impl.rs (95%) rename {src => crates/tele-core/src}/tdlib/message_conversion.rs (100%) rename {src => crates/tele-core/src}/tdlib/message_converter.rs (100%) rename {src => crates/tele-core/src}/tdlib/messages/convert.rs (100%) rename {src => crates/tele-core/src}/tdlib/messages/mod.rs (100%) rename {src => crates/tele-core/src}/tdlib/messages/operations.rs (100%) rename {src => crates/tele-core/src}/tdlib/mod.rs (82%) rename {src => crates/tele-core/src}/tdlib/reactions.rs (100%) rename {src => crates/tele-core/src}/tdlib/trait.rs (94%) rename {src => crates/tele-core/src}/tdlib/types.rs (99%) rename {src => crates/tele-core/src}/tdlib/update_handlers.rs (98%) rename {src => crates/tele-core/src}/tdlib/users.rs (100%) rename {src => crates/tele-core/src}/test_support/fake_tdclient.rs (100%) rename {src => crates/tele-core/src}/test_support/fake_tdclient/builders.rs (100%) rename {src => crates/tele-core/src}/test_support/fake_tdclient/inspect.rs (100%) rename {src => crates/tele-core/src}/test_support/fake_tdclient/operations.rs (100%) rename {src => crates/tele-core/src}/test_support/fake_tdclient/state.rs (100%) rename {src => crates/tele-core/src}/test_support/fake_tdclient_impl.rs (97%) create mode 100644 crates/tele-core/src/test_support/mod.rs rename {src => crates/tele-core/src}/test_support/test_data.rs (100%) rename {src => crates/tele-core/src}/types.rs (100%) create mode 100644 crates/tele-core/src/utils.rs create mode 100644 crates/tele-tui/Cargo.toml rename {benches => crates/tele-tui/benches}/format_markdown.rs (100%) rename {benches => crates/tele-tui/benches}/formatting.rs (100%) rename {benches => crates/tele-tui/benches}/group_messages.rs (100%) rename build.rs => crates/tele-tui/build.rs (79%) rename {src => crates/tele-tui/src}/accounts/lock.rs (100%) rename {src => crates/tele-tui/src}/accounts/manager.rs (100%) rename {src => crates/tele-tui/src}/accounts/mod.rs (100%) rename {src => crates/tele-tui/src}/accounts/profile.rs (100%) rename {src => crates/tele-tui/src}/app/auth_state.rs (100%) rename {src => crates/tele-tui/src}/app/chat_filter.rs (100%) rename {src => crates/tele-tui/src}/app/chat_list_state.rs (100%) rename {src => crates/tele-tui/src}/app/chat_state.rs (100%) rename {src => crates/tele-tui/src}/app/compose_state.rs (100%) rename {src => crates/tele-tui/src}/app/message_service.rs (100%) rename {src => crates/tele-tui/src}/app/message_view_state.rs (100%) rename {src => crates/tele-tui/src}/app/methods/compose.rs (100%) rename {src => crates/tele-tui/src}/app/methods/messages.rs (100%) rename {src => crates/tele-tui/src}/app/methods/mod.rs (100%) rename {src => crates/tele-tui/src}/app/methods/modal.rs (100%) rename {src => crates/tele-tui/src}/app/methods/navigation.rs (100%) rename {src => crates/tele-tui/src}/app/methods/search.rs (100%) rename {src => crates/tele-tui/src}/app/mod.rs (96%) rename {src => crates/tele-tui/src}/app/state.rs (100%) rename {src => crates/tele-tui/src}/app/ui_state.rs (100%) rename {src => crates/tele-tui/src}/audio/cache.rs (100%) rename {src => crates/tele-tui/src}/audio/mod.rs (100%) rename {src => crates/tele-tui/src}/audio/player.rs (100%) rename {src => crates/tele-tui/src}/bin/tele-tui-test-fixture.rs (100%) rename {src => crates/tele-tui/src}/config/keybindings.rs (100%) rename {src => crates/tele-tui/src}/config/loader.rs (100%) rename {src => crates/tele-tui/src}/config/mod.rs (100%) rename {src => crates/tele-tui/src}/config/validation.rs (100%) rename {src => crates/tele-tui/src}/constants.rs (96%) rename {src => crates/tele-tui/src}/formatting.rs (100%) rename {src => crates/tele-tui/src}/input/auth.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/chat.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/chat/media.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/chat_list.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/chat_loader.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/clipboard.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/compose.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/global.rs (97%) rename {src => crates/tele-tui/src}/input/handlers/mod.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/modal.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/modal/account.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/modal/delete.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/modal/pinned.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/modal/profile.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/modal/reactions.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/profile.rs (100%) rename {src => crates/tele-tui/src}/input/handlers/search.rs (100%) rename {src => crates/tele-tui/src}/input/main_input.rs (100%) rename {src => crates/tele-tui/src}/input/mod.rs (100%) rename {src => crates/tele-tui/src}/lib.rs (87%) rename {src => crates/tele-tui/src}/main.rs (97%) rename {src => crates/tele-tui/src}/media/cache.rs (100%) rename {src => crates/tele-tui/src}/media/image_renderer.rs (100%) rename {src => crates/tele-tui/src}/media/mod.rs (100%) rename {src => crates/tele-tui/src}/notifications.rs (94%) rename {src => crates/tele-tui/src}/test_support/app_builder.rs (100%) rename {src => crates/tele-tui/src}/test_support/mod.rs (54%) rename {src => crates/tele-tui/src}/test_support/snapshot_utils.rs (100%) rename {src => crates/tele-tui/src}/ui/auth.rs (100%) rename {src => crates/tele-tui/src}/ui/chat_list.rs (100%) rename {src => crates/tele-tui/src}/ui/components/chat_list_item.rs (100%) rename {src => crates/tele-tui/src}/ui/components/emoji_picker.rs (100%) rename {src => crates/tele-tui/src}/ui/components/input_field.rs (100%) rename {src => crates/tele-tui/src}/ui/components/message_bubble.rs (100%) rename {src => crates/tele-tui/src}/ui/components/message_list.rs (100%) rename {src => crates/tele-tui/src}/ui/components/mod.rs (100%) rename {src => crates/tele-tui/src}/ui/components/modal.rs (100%) rename {src => crates/tele-tui/src}/ui/compose_bar.rs (100%) rename {src => crates/tele-tui/src}/ui/footer.rs (100%) rename {src => crates/tele-tui/src}/ui/loading.rs (100%) rename {src => crates/tele-tui/src}/ui/main_screen.rs (100%) rename {src => crates/tele-tui/src}/ui/messages.rs (100%) rename {src => crates/tele-tui/src}/ui/messages/header.rs (100%) rename {src => crates/tele-tui/src}/ui/messages/list.rs (100%) rename {src => crates/tele-tui/src}/ui/messages/pinned.rs (100%) rename {src => crates/tele-tui/src}/ui/mod.rs (100%) rename {src => crates/tele-tui/src}/ui/modals/account_switcher.rs (100%) rename {src => crates/tele-tui/src}/ui/modals/delete_confirm.rs (100%) rename {src => crates/tele-tui/src}/ui/modals/image_viewer.rs (100%) rename {src => crates/tele-tui/src}/ui/modals/mod.rs (100%) rename {src => crates/tele-tui/src}/ui/modals/pinned.rs (100%) rename {src => crates/tele-tui/src}/ui/modals/reaction_picker.rs (100%) rename {src => crates/tele-tui/src}/ui/modals/search.rs (100%) rename {src => crates/tele-tui/src}/ui/profile.rs (100%) rename {src => crates/tele-tui/src}/utils/formatting.rs (99%) rename {src => crates/tele-tui/src}/utils/mod.rs (100%) rename {src => crates/tele-tui/src}/utils/modal_handler.rs (100%) rename {src => crates/tele-tui/src}/utils/retry.rs (100%) rename {src => crates/tele-tui/src}/utils/tdlib.rs (100%) rename {src => crates/tele-tui/src}/utils/validation.rs (100%) rename {tests => crates/tele-tui/tests}/account_switcher.rs (100%) rename {tests => crates/tele-tui/tests}/accounts.rs (100%) rename {tests => crates/tele-tui/tests}/chat_list.rs (100%) rename {tests => crates/tele-tui/tests}/config.rs (100%) rename {tests => crates/tele-tui/tests}/copy.rs (100%) rename {tests => crates/tele-tui/tests}/delete_message.rs (100%) rename {tests => crates/tele-tui/tests}/drafts.rs (100%) rename {tests => crates/tele-tui/tests}/e2e_smoke.rs (100%) rename {tests => crates/tele-tui/tests}/e2e_termwright.rs (100%) rename {tests => crates/tele-tui/tests}/e2e_user_journey.rs (100%) rename {tests => crates/tele-tui/tests}/edit_message.rs (100%) rename {tests => crates/tele-tui/tests}/footer.rs (100%) rename {tests => crates/tele-tui/tests}/helpers/app_builder.rs (100%) rename {tests => crates/tele-tui/tests}/helpers/fake_tdclient.rs (100%) rename {tests => crates/tele-tui/tests}/helpers/fake_tdclient/builders.rs (100%) rename {tests => crates/tele-tui/tests}/helpers/fake_tdclient/inspect.rs (100%) rename {tests => crates/tele-tui/tests}/helpers/fake_tdclient/operations.rs (100%) rename {tests => crates/tele-tui/tests}/helpers/fake_tdclient/state.rs (100%) rename {tests => crates/tele-tui/tests}/helpers/fake_tdclient_impl.rs (97%) rename {tests => crates/tele-tui/tests}/helpers/mod.rs (100%) rename {tests => crates/tele-tui/tests}/helpers/snapshot_utils.rs (100%) rename {tests => crates/tele-tui/tests}/helpers/test_data.rs (100%) rename {tests => crates/tele-tui/tests}/input_field.rs (100%) rename {tests => crates/tele-tui/tests}/input_navigation.rs (100%) rename {tests => crates/tele-tui/tests}/messages.rs (100%) rename {tests => crates/tele-tui/tests}/modals.rs (100%) rename {tests => crates/tele-tui/tests}/navigation.rs (100%) rename {tests => crates/tele-tui/tests}/network_typing.rs (100%) rename {tests => crates/tele-tui/tests}/profile.rs (100%) rename {tests => crates/tele-tui/tests}/reactions.rs (100%) rename {tests => crates/tele-tui/tests}/reply_forward.rs (100%) rename {tests => crates/tele-tui/tests}/screens.rs (100%) rename {tests => crates/tele-tui/tests}/search.rs (100%) rename {tests => crates/tele-tui/tests}/send_message.rs (100%) rename {tests => crates/tele-tui/tests}/snapshots/chat_list__chat_list_search_mode.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/chat_list__chat_list_three_chats.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/chat_list__chat_long_title.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/chat_list__chat_muted.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/chat_list__chat_pinned.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/chat_list__chat_selected.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/chat_list__chat_with_mentions.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/chat_list__chat_with_online_status.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/chat_list__chat_with_unread.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/chat_list__empty_chat_list.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/footer__footer_chat_list.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/footer__footer_network_connecting.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/footer__footer_network_connecting_proxy.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/footer__footer_network_waiting.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/footer__footer_open_chat.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/footer__footer_search_mode.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/input_field__empty_input.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/input_field__input_editing_mode.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/input_field__input_long_text_2_lines.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/input_field__input_long_text_max_lines.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/input_field__input_reply_mode.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/input_field__input_search_mode.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/input_field__input_with_text.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__album_incoming.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__album_outgoing.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__album_selected.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__album_with_regular_messages.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__date_separator_old_date.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__edited_message.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__empty_chat.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__forwarded_message.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__long_message_wrap.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__markdown_bold_italic_code.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__markdown_link_mention.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__markdown_spoiler.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__media_placeholder.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__multiple_reactions.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__outgoing_read.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__outgoing_sent.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__reply_message.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__selected_message.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__sender_grouping.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__single_incoming_message.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__single_outgoing_message.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/messages__single_reaction.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/modals__delete_confirmation_modal.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/modals__emoji_picker_default.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/modals__emoji_picker_with_selection.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/modals__forward_mode.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/modals__pinned_message.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/modals__profile_group_chat.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/modals__profile_personal_chat.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/modals__search_in_chat.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/screens__auth_screen_code.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/screens__auth_screen_password.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/screens__auth_screen_phone.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/screens__loading_screen_default.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/screens__loading_screen_with_status.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/screens__main_screen_account_switcher_overlay.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/screens__main_screen_chat_list_loaded.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/screens__main_screen_chat_open_narrow_valid.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/screens__main_screen_chat_open_with_messages.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/screens__main_screen_empty.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/screens__main_screen_terminal_too_small.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/style_snapshots__style_reaction_picker_selection.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/style_snapshots__style_selected_chat.snap (100%) rename {tests => crates/tele-tui/tests}/snapshots/style_snapshots__style_selected_message.snap (100%) rename {tests => crates/tele-tui/tests}/style_snapshots.rs (100%) rename {tests => crates/tele-tui/tests}/vim_mode.rs (100%) create mode 100644 docs/IOS_CORE_REUSE.md create mode 100644 docs/superpowers/plans/2026-05-20-ios-app-roadmap.md diff --git a/Cargo.lock b/Cargo.lock index f2ef371..3e3118d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3942,6 +3942,22 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20b1c6703d2284b9d4ddb620cd350f726a1c43bb6f7801f4361b55db2421caa8" +[[package]] +name = "tele-core" +version = "0.1.0" +dependencies = [ + "async-trait", + "base64", + "chrono", + "serde", + "serde_json", + "tdlib-rs", + "thiserror 1.0.69", + "tokio", + "tokio-test", + "tracing", +] + [[package]] name = "tele-tui" version = "0.1.0" @@ -3964,6 +3980,7 @@ dependencies = [ "serde", "serde_json", "tdlib-rs", + "tele-core", "termwright", "thiserror 1.0.69", "tokio", diff --git a/Cargo.toml b/Cargo.toml index a8a2c96..fb7c206 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,65 +1,4 @@ -[package] -name = "tele-tui" -version = "0.1.0" -edition = "2021" -authors = ["Your Name "] -description = "Terminal UI for Telegram with Vim-style navigation" -license = "MIT" -repository = "https://github.com/your-username/tele-tui" -keywords = ["telegram", "tui", "terminal", "cli"] -categories = ["command-line-utilities"] -default-run = "tele-tui" - -[features] -default = ["clipboard", "url-open", "notifications", "images"] -clipboard = ["dep:arboard"] -url-open = ["dep:open"] -notifications = ["dep:notify-rust"] -images = ["dep:ratatui-image", "dep:image"] -test-support = [] - -[dependencies] -ratatui = "0.29" -crossterm = "0.28" -tdlib-rs = { version = "1.2.0", features = ["download-tdlib"] } -tokio = { version = "1", features = ["full"] } -async-trait = "0.1" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -dotenvy = "0.15" -chrono = "0.4" -open = { version = "5.0", optional = true } -arboard = { version = "3.4", optional = true } -notify-rust = { version = "4.11", optional = true } -ratatui-image = { version = "8.1", optional = true, features = ["image-defaults"] } -image = { version = "0.25", optional = true } -toml = "0.8" -dirs = "5.0" -thiserror = "1.0" -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["env-filter"] } -base64 = "0.22.1" -fs2 = "0.4" - -[dev-dependencies] -insta = "1.34" -tokio-test = "0.4" -criterion = "0.5" -termwright = "0.2" - -[[bin]] -name = "tele-tui-test-fixture" -path = "src/bin/tele-tui-test-fixture.rs" -required-features = ["test-support"] - -[[bench]] -name = "group_messages" -harness = false - -[[bench]] -name = "formatting" -harness = false - -[[bench]] -name = "format_markdown" -harness = false +[workspace] +members = ["crates/tele-core", "crates/tele-tui"] +default-members = ["crates/tele-tui"] +resolver = "2" diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index e4f3158..4fbeb79 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -27,9 +27,11 @@ cargo check ```bash cargo fmt -- --check -cargo check --all-targets --all-features -cargo clippy --all-targets --all-features -- -D warnings -cargo test --all-features +cargo check -p tele-core +cargo test -p tele-core +cargo check -p tele-tui --all-targets --all-features +cargo clippy --workspace --all-targets --all-features -- -D warnings +cargo test --workspace --all-features git diff --check ``` diff --git a/README.md b/README.md index 6578fa9..0bd3135 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ - Для голосовых сообщений нужен `ffplay` из ffmpeg. ```bash -cargo build --release +cargo build -p tele-tui --release ``` ## Credentials @@ -54,6 +54,10 @@ cargo run --release cargo run --release -- --account work ``` +`Cargo.toml` в корне - workspace manifest. По умолчанию `cargo run` и `cargo test` +работают с `crates/tele-tui`; переиспользуемая TDLib-логика лежит в +`crates/tele-core`. + Runtime-конфиг создаётся в `~/.config/tele-tui/config.toml`; пример лежит в [config.toml.example](config.toml.example). ## Документация @@ -64,6 +68,7 @@ Runtime-конфиг создаётся в `~/.config/tele-tui/config.toml`; п - [docs/HOTKEYS.md](docs/HOTKEYS.md) - горячие клавиши. - [docs/PROJECT_STRUCTURE.md](docs/PROJECT_STRUCTURE.md) - карта подсистем. - [docs/TDLIB_INTEGRATION.md](docs/TDLIB_INTEGRATION.md) - проектные заметки по TDLib. +- [docs/IOS_CORE_REUSE.md](docs/IOS_CORE_REUSE.md) - граница `tele-core` для будущего iOS-клиента. ## Лицензия diff --git a/crates/tele-core/Cargo.toml b/crates/tele-core/Cargo.toml new file mode 100644 index 0000000..23dfaf6 --- /dev/null +++ b/crates/tele-core/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "tele-core" +version = "0.1.0" +edition = "2021" +authors = ["Your Name "] +description = "Reusable Telegram/TDLib core for tele-tui" +license = "MIT" +repository = "https://github.com/your-username/tele-tui" +keywords = ["telegram", "tdlib"] +categories = ["api-bindings"] + +[features] +default = [] +images = [] +test-support = [] + +[dependencies] +tdlib-rs = { version = "1.2.0", features = ["download-tdlib"] } +tokio = { version = "1", features = ["full"] } +async-trait = "0.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +chrono = "0.4" +thiserror = "1.0" +tracing = "0.1" +base64 = "0.22.1" + +[dev-dependencies] +tokio-test = "0.4" diff --git a/crates/tele-core/src/accounts/mod.rs b/crates/tele-core/src/accounts/mod.rs new file mode 100644 index 0000000..9764264 --- /dev/null +++ b/crates/tele-core/src/accounts/mod.rs @@ -0,0 +1,5 @@ +//! Account profile data structures and validation. + +pub mod profile; + +pub use profile::{validate_account_name, AccountProfile, AccountsConfig}; diff --git a/crates/tele-core/src/accounts/profile.rs b/crates/tele-core/src/accounts/profile.rs new file mode 100644 index 0000000..c95d771 --- /dev/null +++ b/crates/tele-core/src/accounts/profile.rs @@ -0,0 +1,114 @@ +//! Account profile data structures and validation. +//! +//! Defines `AccountProfile` and `AccountsConfig` for multi-account support. +//! Account names are validated to contain only alphanumeric characters, hyphens, and underscores. + +use serde::{Deserialize, Serialize}; + +/// Configuration for all accounts, stored in `~/.config/tele-tui/accounts.toml`. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AccountsConfig { + /// Name of the default account to use when no `--account` flag is provided. + pub default_account: String, + + /// List of configured accounts. + pub accounts: Vec, +} + +/// A single account profile. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AccountProfile { + /// Unique identifier (used in directory names and CLI flag). + pub name: String, + + /// Human-readable display name. + pub display_name: String, +} + +impl AccountsConfig { + /// Creates a default config with a single "default" account. + pub fn default_single() -> Self { + Self { + default_account: "default".to_string(), + accounts: vec![AccountProfile { + name: "default".to_string(), + display_name: "Default".to_string(), + }], + } + } + + /// Finds an account by name. + pub fn find_account(&self, name: &str) -> Option<&AccountProfile> { + self.accounts.iter().find(|a| a.name == name) + } +} + +/// Validates an account name. +/// +/// Valid names contain only lowercase alphanumeric characters, hyphens, and underscores. +/// Must be 1-32 characters long. +/// +/// # Errors +/// +/// Returns a descriptive error message if the name is invalid. +pub fn validate_account_name(name: &str) -> Result<(), String> { + if name.is_empty() { + return Err("Account name cannot be empty".to_string()); + } + if name.len() > 32 { + return Err("Account name cannot be longer than 32 characters".to_string()); + } + if !name + .chars() + .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-' || c == '_') + { + return Err( + "Account name can only contain lowercase letters, digits, hyphens, and underscores" + .to_string(), + ); + } + if name.starts_with('-') || name.starts_with('_') { + return Err("Account name cannot start with a hyphen or underscore".to_string()); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_validate_account_name_valid() { + assert!(validate_account_name("default").is_ok()); + assert!(validate_account_name("work").is_ok()); + assert!(validate_account_name("my-account").is_ok()); + assert!(validate_account_name("account_2").is_ok()); + assert!(validate_account_name("a").is_ok()); + } + + #[test] + fn test_validate_account_name_invalid() { + assert!(validate_account_name("").is_err()); + assert!(validate_account_name("My Account").is_err()); + assert!(validate_account_name("UPPER").is_err()); + assert!(validate_account_name("with spaces").is_err()); + assert!(validate_account_name("-starts-with-dash").is_err()); + assert!(validate_account_name("_starts-with-underscore").is_err()); + assert!(validate_account_name(&"a".repeat(33)).is_err()); + } + + #[test] + fn test_default_single_config() { + let config = AccountsConfig::default_single(); + assert_eq!(config.default_account, "default"); + assert_eq!(config.accounts.len(), 1); + assert_eq!(config.accounts[0].name, "default"); + } + + #[test] + fn test_find_account() { + let config = AccountsConfig::default_single(); + assert!(config.find_account("default").is_some()); + assert!(config.find_account("nonexistent").is_none()); + } +} diff --git a/crates/tele-core/src/constants.rs b/crates/tele-core/src/constants.rs new file mode 100644 index 0000000..0e9f879 --- /dev/null +++ b/crates/tele-core/src/constants.rs @@ -0,0 +1,6 @@ +pub const MAX_MESSAGES_IN_CHAT: usize = 500; +pub const MAX_USER_CACHE_SIZE: usize = 500; +pub const MAX_CHATS: usize = 200; +pub const MAX_CHAT_USER_IDS: usize = 500; +pub const LAZY_LOAD_USERS_PER_TICK: usize = 5; +pub const TDLIB_MESSAGE_LIMIT: i32 = 50; diff --git a/crates/tele-core/src/lib.rs b/crates/tele-core/src/lib.rs new file mode 100644 index 0000000..164a093 --- /dev/null +++ b/crates/tele-core/src/lib.rs @@ -0,0 +1,11 @@ +//! Reusable Telegram/TDLib core for tele-tui and future clients. + +mod constants; +mod utils; + +pub mod accounts; +pub mod message_grouping; +pub mod tdlib; +#[cfg(any(test, feature = "test-support"))] +pub mod test_support; +pub mod types; diff --git a/src/message_grouping.rs b/crates/tele-core/src/message_grouping.rs similarity index 99% rename from src/message_grouping.rs rename to crates/tele-core/src/message_grouping.rs index 9df609c..d9b015e 100644 --- a/src/message_grouping.rs +++ b/crates/tele-core/src/message_grouping.rs @@ -35,10 +35,10 @@ pub enum MessageGroup<'a> { /// # Примеры /// /// ```no_run -/// use tele_tui::message_grouping::{group_messages, MessageGroup}; +/// use tele_core::message_grouping::{group_messages, MessageGroup}; /// -/// # use tele_tui::tdlib::types::MessageBuilder; -/// # use tele_tui::types::MessageId; +/// # use tele_core::tdlib::types::MessageBuilder; +/// # use tele_core::types::MessageId; /// # let msg = MessageBuilder::new(MessageId::new(1)).sender_name("Alice").text("Hello").build(); /// let messages = vec![msg]; /// let grouped = group_messages(&messages); diff --git a/src/tdlib/auth.rs b/crates/tele-core/src/tdlib/auth.rs similarity index 100% rename from src/tdlib/auth.rs rename to crates/tele-core/src/tdlib/auth.rs diff --git a/src/tdlib/chat_helpers.rs b/crates/tele-core/src/tdlib/chat_helpers.rs similarity index 100% rename from src/tdlib/chat_helpers.rs rename to crates/tele-core/src/tdlib/chat_helpers.rs diff --git a/src/tdlib/chats.rs b/crates/tele-core/src/tdlib/chats.rs similarity index 100% rename from src/tdlib/chats.rs rename to crates/tele-core/src/tdlib/chats.rs diff --git a/src/tdlib/client.rs b/crates/tele-core/src/tdlib/client.rs similarity index 93% rename from src/tdlib/client.rs rename to crates/tele-core/src/tdlib/client.rs index 94d48f0..185d9e6 100644 --- a/src/tdlib/client.rs +++ b/crates/tele-core/src/tdlib/client.rs @@ -1,5 +1,5 @@ use crate::types::{ChatId, MessageId, UserId}; -use std::env; +use std::collections::VecDeque; use std::path::PathBuf; use tdlib_rs::enums::{Chat as TdChat, ChatList, ConnectionState, Update, UserStatus}; use tdlib_rs::functions; @@ -13,7 +13,25 @@ use super::types::{ ChatInfo, FolderInfo, MessageInfo, NetworkState, ProfileInfo, UserOnlineStatus, }; use super::users::UserCache; -use crate::notifications::NotificationManager; + +#[derive(Debug, Clone)] +pub struct TdCredentials { + pub api_id: i32, + pub api_hash: String, +} + +#[derive(Debug, Clone)] +pub struct TdClientConfig { + pub credentials: TdCredentials, + pub db_path: PathBuf, +} + +#[derive(Debug, Clone)] +pub struct IncomingMessageEvent { + pub chat: ChatInfo, + pub message: MessageInfo, + pub sender_name: String, +} /// TDLib client wrapper for Telegram integration. /// @@ -28,9 +46,15 @@ use crate::notifications::NotificationManager; /// # Examples /// /// ```ignore -/// use tele_tui::tdlib::TdClient; +/// use tele_core::tdlib::TdClient; /// -/// let mut client = TdClient::new(std::path::PathBuf::from("tdlib_data")); +/// let mut client = TdClient::new(tele_core::tdlib::TdClientConfig { +/// credentials: tele_core::tdlib::TdCredentials { +/// api_id: 123, +/// api_hash: "hash".to_string(), +/// }, +/// db_path: std::path::PathBuf::from("tdlib_data"), +/// }); /// /// // Start authorization /// client.send_phone_number("+1234567890".to_string()).await?; @@ -52,7 +76,7 @@ pub struct TdClient { pub message_manager: MessageManager, pub user_cache: UserCache, pub reaction_manager: ReactionManager, - pub notification_manager: NotificationManager, + incoming_message_events: VecDeque, // Состояние сети pub network_state: NetworkState, @@ -62,62 +86,41 @@ pub struct TdClient { impl TdClient { /// Creates a new TDLib client instance. /// - /// Reads API credentials from: - /// 1. ~/.config/tele-tui/credentials file - /// 2. Environment variables `API_ID` and `API_HASH` (fallback) - /// /// Initializes all managers and sets initial network state to Connecting. /// /// # Returns /// /// A new `TdClient` instance ready for authentication. - pub fn new(db_path: PathBuf) -> Self { - // Пробуем загрузить credentials из Config (файл или env) - let (api_id, api_hash) = crate::config::Config::load_credentials().unwrap_or_else(|_| { - // Fallback на прямое чтение из env (старое поведение) - let api_id = env::var("API_ID") - .unwrap_or_else(|_| "0".to_string()) - .parse() - .unwrap_or(0); - let api_hash = env::var("API_HASH").unwrap_or_default(); - (api_id, api_hash) - }); - + pub fn new(config: TdClientConfig) -> Self { let client_id = tdlib_rs::create_client(); Self { - api_id, - api_hash, - db_path, + api_id: config.credentials.api_id, + api_hash: config.credentials.api_hash, + db_path: config.db_path, client_id, auth: AuthManager::new(client_id), chat_manager: ChatManager::new(client_id), message_manager: MessageManager::new(client_id), user_cache: UserCache::new(client_id), reaction_manager: ReactionManager::new(client_id), - notification_manager: NotificationManager::new(), + incoming_message_events: VecDeque::new(), network_state: NetworkState::Connecting, } } - /// Configures notification manager from app config - pub fn configure_notifications(&mut self, config: &crate::config::NotificationsConfig) { - self.notification_manager.set_enabled(config.enabled); - self.notification_manager - .set_only_mentions(config.only_mentions); - self.notification_manager - .set_show_preview(config.show_preview); - self.notification_manager.set_timeout(config.timeout_ms); - self.notification_manager - .set_urgency(config.urgency.clone()); + pub fn enqueue_incoming_message_event( + &mut self, + chat: ChatInfo, + message: MessageInfo, + sender_name: String, + ) { + self.incoming_message_events + .push_back(IncomingMessageEvent { chat, message, sender_name }); } - /// Synchronizes muted chats from Telegram to notification manager. - /// - /// Should be called after chats are loaded to ensure muted chats don't trigger notifications. - pub fn sync_notification_muted_chats(&mut self) { - self.notification_manager - .sync_muted_chats(&self.chat_manager.chats); + pub fn drain_incoming_message_events(&mut self) -> Vec { + self.incoming_message_events.drain(..).collect() } // Делегирование к auth @@ -791,7 +794,13 @@ impl TdClient { let _ = functions::close(self.client_id).await; // 2. Create new client - let new_client = TdClient::new(db_path); + let new_client = TdClient::new(TdClientConfig { + credentials: TdCredentials { + api_id: self.api_id, + api_hash: self.api_hash.clone(), + }, + db_path, + }); // 3. Spawn set_tdlib_parameters for new client let new_client_id = new_client.client_id; diff --git a/src/tdlib/client_impl.rs b/crates/tele-core/src/tdlib/client_impl.rs similarity index 95% rename from src/tdlib/client_impl.rs rename to crates/tele-core/src/tdlib/client_impl.rs index 5a70043..c919fa3 100644 --- a/src/tdlib/client_impl.rs +++ b/crates/tele-core/src/tdlib/client_impl.rs @@ -5,7 +5,7 @@ use super::client::TdClient; use super::r#trait::{ AccountClient, AuthClient, ChatActionClient, ChatClient, ClientState, FileClient, - MessageClient, NotificationClient, ReactionClient, UpdateClient, UserClient, + MessageClient, ReactionClient, UpdateClient, UserClient, }; use super::{ AuthState, ChatInfo, FolderInfo, MessageInfo, ProfileInfo, ReplyInfo, UserCache, @@ -313,17 +313,6 @@ impl ClientState for TdClient { } } -impl NotificationClient for TdClient { - fn configure_notifications(&mut self, config: &crate::config::NotificationsConfig) { - self.configure_notifications(config); - } - - fn sync_notification_muted_chats(&mut self) { - self.notification_manager - .sync_muted_chats(&self.chat_manager.chats); - } -} - #[async_trait] impl AccountClient for TdClient { async fn recreate_client(&mut self, db_path: PathBuf) -> Result<(), String> { @@ -336,4 +325,8 @@ impl UpdateClient for TdClient { // Delegate to the real implementation TdClient::handle_update(self, update) } + + fn drain_incoming_message_events(&mut self) -> Vec { + TdClient::drain_incoming_message_events(self) + } } diff --git a/src/tdlib/message_conversion.rs b/crates/tele-core/src/tdlib/message_conversion.rs similarity index 100% rename from src/tdlib/message_conversion.rs rename to crates/tele-core/src/tdlib/message_conversion.rs diff --git a/src/tdlib/message_converter.rs b/crates/tele-core/src/tdlib/message_converter.rs similarity index 100% rename from src/tdlib/message_converter.rs rename to crates/tele-core/src/tdlib/message_converter.rs diff --git a/src/tdlib/messages/convert.rs b/crates/tele-core/src/tdlib/messages/convert.rs similarity index 100% rename from src/tdlib/messages/convert.rs rename to crates/tele-core/src/tdlib/messages/convert.rs diff --git a/src/tdlib/messages/mod.rs b/crates/tele-core/src/tdlib/messages/mod.rs similarity index 100% rename from src/tdlib/messages/mod.rs rename to crates/tele-core/src/tdlib/messages/mod.rs diff --git a/src/tdlib/messages/operations.rs b/crates/tele-core/src/tdlib/messages/operations.rs similarity index 100% rename from src/tdlib/messages/operations.rs rename to crates/tele-core/src/tdlib/messages/operations.rs diff --git a/src/tdlib/mod.rs b/crates/tele-core/src/tdlib/mod.rs similarity index 82% rename from src/tdlib/mod.rs rename to crates/tele-core/src/tdlib/mod.rs index 3bfe8b1..b297b59 100644 --- a/src/tdlib/mod.rs +++ b/crates/tele-core/src/tdlib/mod.rs @@ -4,7 +4,7 @@ mod chat_helpers; // Chat management helpers pub mod chats; pub mod client; mod client_impl; // Private module for trait implementation -pub(crate) mod message_conversion; // Message conversion utilities (for messages.rs) +pub mod message_conversion; // Message conversion utilities (for messages.rs) mod message_converter; // Message conversion utilities (for client.rs) pub mod messages; pub mod reactions; @@ -19,7 +19,7 @@ pub use client::TdClient; #[allow(unused_imports)] pub use r#trait::{ AccountClient, AuthClient, ChatActionClient, ChatClient, ClientState, FileClient, - MessageClient, NotificationClient, ReactionClient, TdClientTrait, UpdateClient, UserClient, + MessageClient, ReactionClient, TdClientTrait, UpdateClient, UserClient, }; #[allow(unused_imports)] pub use types::{ @@ -28,6 +28,7 @@ pub use types::{ VoiceDownloadState, VoiceInfo, }; +pub use client::{IncomingMessageEvent, TdClientConfig, TdCredentials}; #[cfg(feature = "images")] pub use types::ImageModalState; pub use users::UserCache; diff --git a/src/tdlib/reactions.rs b/crates/tele-core/src/tdlib/reactions.rs similarity index 100% rename from src/tdlib/reactions.rs rename to crates/tele-core/src/tdlib/reactions.rs diff --git a/src/tdlib/trait.rs b/crates/tele-core/src/tdlib/trait.rs similarity index 94% rename from src/tdlib/trait.rs rename to crates/tele-core/src/tdlib/trait.rs index deb3e58..5b06980 100644 --- a/src/tdlib/trait.rs +++ b/crates/tele-core/src/tdlib/trait.rs @@ -3,7 +3,10 @@ //! This trait allows tests to use FakeTdClient instead of real TDLib client. #![allow(dead_code)] -use crate::tdlib::{AuthState, FolderInfo, MessageInfo, ProfileInfo, UserCache, UserOnlineStatus}; +use crate::tdlib::{ + AuthState, FolderInfo, IncomingMessageEvent, MessageInfo, ProfileInfo, UserCache, + UserOnlineStatus, +}; use crate::types::{ChatId, MessageId, UserId}; use async_trait::async_trait; use std::borrow::Cow; @@ -163,12 +166,6 @@ pub trait ClientState: Send { fn network_state(&self) -> super::types::NetworkState; } -/// Notification configuration operations. -pub trait NotificationClient: Send { - fn configure_notifications(&mut self, config: &crate::config::NotificationsConfig); - fn sync_notification_muted_chats(&mut self); -} - /// Account switching operations. #[async_trait] pub trait AccountClient: Send { @@ -182,6 +179,7 @@ pub trait AccountClient: Send { /// TDLib update routing. pub trait UpdateClient: Send { fn handle_update(&mut self, update: Update); + fn drain_incoming_message_events(&mut self) -> Vec; } /// Facade trait for TDLib client operations @@ -198,7 +196,6 @@ pub trait TdClientTrait: + ReactionClient + FileClient + ClientState - + NotificationClient + AccountClient + UpdateClient + Send @@ -214,7 +211,6 @@ impl TdClientTrait for T where + ReactionClient + FileClient + ClientState - + NotificationClient + AccountClient + UpdateClient + Send diff --git a/src/tdlib/types.rs b/crates/tele-core/src/tdlib/types.rs similarity index 99% rename from src/tdlib/types.rs rename to crates/tele-core/src/tdlib/types.rs index d1237b3..34ac7c6 100644 --- a/src/tdlib/types.rs +++ b/crates/tele-core/src/tdlib/types.rs @@ -312,8 +312,8 @@ impl MessageInfo { /// # Примеры /// /// ``` -/// use tele_tui::tdlib::MessageBuilder; -/// use tele_tui::types::MessageId; +/// use tele_core::tdlib::MessageBuilder; +/// use tele_core::types::MessageId; /// /// let message = MessageBuilder::new(MessageId::new(123)) /// .sender_name("Alice") diff --git a/src/tdlib/update_handlers.rs b/crates/tele-core/src/tdlib/update_handlers.rs similarity index 98% rename from src/tdlib/update_handlers.rs rename to crates/tele-core/src/tdlib/update_handlers.rs index 5b6ec3c..2b3a6bf 100644 --- a/src/tdlib/update_handlers.rs +++ b/crates/tele-core/src/tdlib/update_handlers.rs @@ -27,12 +27,9 @@ pub fn handle_new_message_update(client: &mut TdClient, new_msg: UpdateNewMessag crate::tdlib::message_converter::convert_message(client, &new_msg.message, chat_id); // Get sender name (from message or user cache) - let sender_name = msg_info.sender_name(); + let sender_name = msg_info.sender_name().to_string(); - // Send notification - let _ = client - .notification_manager - .notify_new_message(&chat, &msg_info, sender_name); + client.enqueue_incoming_message_event(chat, msg_info, sender_name); } return; } diff --git a/src/tdlib/users.rs b/crates/tele-core/src/tdlib/users.rs similarity index 100% rename from src/tdlib/users.rs rename to crates/tele-core/src/tdlib/users.rs diff --git a/src/test_support/fake_tdclient.rs b/crates/tele-core/src/test_support/fake_tdclient.rs similarity index 100% rename from src/test_support/fake_tdclient.rs rename to crates/tele-core/src/test_support/fake_tdclient.rs diff --git a/src/test_support/fake_tdclient/builders.rs b/crates/tele-core/src/test_support/fake_tdclient/builders.rs similarity index 100% rename from src/test_support/fake_tdclient/builders.rs rename to crates/tele-core/src/test_support/fake_tdclient/builders.rs diff --git a/src/test_support/fake_tdclient/inspect.rs b/crates/tele-core/src/test_support/fake_tdclient/inspect.rs similarity index 100% rename from src/test_support/fake_tdclient/inspect.rs rename to crates/tele-core/src/test_support/fake_tdclient/inspect.rs diff --git a/src/test_support/fake_tdclient/operations.rs b/crates/tele-core/src/test_support/fake_tdclient/operations.rs similarity index 100% rename from src/test_support/fake_tdclient/operations.rs rename to crates/tele-core/src/test_support/fake_tdclient/operations.rs diff --git a/src/test_support/fake_tdclient/state.rs b/crates/tele-core/src/test_support/fake_tdclient/state.rs similarity index 100% rename from src/test_support/fake_tdclient/state.rs rename to crates/tele-core/src/test_support/fake_tdclient/state.rs diff --git a/src/test_support/fake_tdclient_impl.rs b/crates/tele-core/src/test_support/fake_tdclient_impl.rs similarity index 97% rename from src/test_support/fake_tdclient_impl.rs rename to crates/tele-core/src/test_support/fake_tdclient_impl.rs index d03e22d..665ab9f 100644 --- a/src/test_support/fake_tdclient_impl.rs +++ b/crates/tele-core/src/test_support/fake_tdclient_impl.rs @@ -3,7 +3,7 @@ use super::fake_tdclient::FakeTdClient; use crate::tdlib::{ AccountClient, AuthClient, ChatActionClient, ChatClient, ClientState, FileClient, - MessageClient, NotificationClient, ReactionClient, UpdateClient, UserClient, + MessageClient, ReactionClient, UpdateClient, UserClient, }; use crate::tdlib::{ AuthState, ChatInfo, FolderInfo, MessageInfo, ProfileInfo, ReplyInfo, UserCache, @@ -342,12 +342,6 @@ impl ClientState for FakeTdClient { } } -impl NotificationClient for FakeTdClient { - fn configure_notifications(&mut self, _config: &crate::config::NotificationsConfig) {} - - fn sync_notification_muted_chats(&mut self) {} -} - #[async_trait] impl AccountClient for FakeTdClient { async fn recreate_client(&mut self, _db_path: PathBuf) -> Result<(), String> { @@ -357,4 +351,8 @@ impl AccountClient for FakeTdClient { impl UpdateClient for FakeTdClient { fn handle_update(&mut self, _update: Update) {} + + fn drain_incoming_message_events(&mut self) -> Vec { + Vec::new() + } } diff --git a/crates/tele-core/src/test_support/mod.rs b/crates/tele-core/src/test_support/mod.rs new file mode 100644 index 0000000..fce76d3 --- /dev/null +++ b/crates/tele-core/src/test_support/mod.rs @@ -0,0 +1,7 @@ +//! Core test support for deterministic TDLib fixtures. + +pub mod fake_tdclient; +mod fake_tdclient_impl; +pub mod test_data; + +pub use fake_tdclient::FakeTdClient; diff --git a/src/test_support/test_data.rs b/crates/tele-core/src/test_support/test_data.rs similarity index 100% rename from src/test_support/test_data.rs rename to crates/tele-core/src/test_support/test_data.rs diff --git a/src/types.rs b/crates/tele-core/src/types.rs similarity index 100% rename from src/types.rs rename to crates/tele-core/src/types.rs diff --git a/crates/tele-core/src/utils.rs b/crates/tele-core/src/utils.rs new file mode 100644 index 0000000..67430cf --- /dev/null +++ b/crates/tele-core/src/utils.rs @@ -0,0 +1,9 @@ +use chrono::{DateTime, Local, NaiveDate, Utc}; + +pub fn get_day(timestamp: i32) -> i64 { + let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).expect("valid epoch date"); + let msg_day = DateTime::::from_timestamp(timestamp as i64, 0) + .map(|dt| dt.with_timezone(&Local).date_naive()) + .unwrap_or(epoch); + msg_day.signed_duration_since(epoch).num_days() +} diff --git a/crates/tele-tui/Cargo.toml b/crates/tele-tui/Cargo.toml new file mode 100644 index 0000000..bade336 --- /dev/null +++ b/crates/tele-tui/Cargo.toml @@ -0,0 +1,66 @@ +[package] +name = "tele-tui" +version = "0.1.0" +edition = "2021" +authors = ["Your Name "] +description = "Terminal UI for Telegram with Vim-style navigation" +license = "MIT" +repository = "https://github.com/your-username/tele-tui" +keywords = ["telegram", "tui", "terminal", "cli"] +categories = ["command-line-utilities"] +default-run = "tele-tui" + +[features] +default = ["clipboard", "url-open", "notifications", "images"] +clipboard = ["dep:arboard"] +url-open = ["dep:open"] +notifications = ["dep:notify-rust"] +images = ["dep:ratatui-image", "dep:image", "tele-core/images"] +test-support = ["tele-core/test-support"] + +[dependencies] +tele-core = { path = "../tele-core" } +ratatui = "0.29" +crossterm = "0.28" +tdlib-rs = { version = "1.2.0", features = ["download-tdlib"] } +tokio = { version = "1", features = ["full"] } +async-trait = "0.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +dotenvy = "0.15" +chrono = "0.4" +open = { version = "5.0", optional = true } +arboard = { version = "3.4", optional = true } +notify-rust = { version = "4.11", optional = true } +ratatui-image = { version = "8.1", optional = true, features = ["image-defaults"] } +image = { version = "0.25", optional = true } +toml = "0.8" +dirs = "5.0" +thiserror = "1.0" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +base64 = "0.22.1" +fs2 = "0.4" + +[dev-dependencies] +insta = "1.34" +tokio-test = "0.4" +criterion = "0.5" +termwright = "0.2" + +[[bin]] +name = "tele-tui-test-fixture" +path = "src/bin/tele-tui-test-fixture.rs" +required-features = ["test-support"] + +[[bench]] +name = "group_messages" +harness = false + +[[bench]] +name = "formatting" +harness = false + +[[bench]] +name = "format_markdown" +harness = false diff --git a/benches/format_markdown.rs b/crates/tele-tui/benches/format_markdown.rs similarity index 100% rename from benches/format_markdown.rs rename to crates/tele-tui/benches/format_markdown.rs diff --git a/benches/formatting.rs b/crates/tele-tui/benches/formatting.rs similarity index 100% rename from benches/formatting.rs rename to crates/tele-tui/benches/formatting.rs diff --git a/benches/group_messages.rs b/crates/tele-tui/benches/group_messages.rs similarity index 100% rename from benches/group_messages.rs rename to crates/tele-tui/benches/group_messages.rs diff --git a/build.rs b/crates/tele-tui/build.rs similarity index 79% rename from build.rs rename to crates/tele-tui/build.rs index fa0c8d4..9884f8c 100644 --- a/build.rs +++ b/crates/tele-tui/build.rs @@ -13,7 +13,12 @@ fn main() { fn tdlib_lib_dirs() -> Vec { let manifest_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string()); - let build_dir = manifest_dir.join("target").join(profile).join("build"); + let workspace_dir = manifest_dir + .parent() + .and_then(Path::parent) + .map(Path::to_path_buf) + .unwrap_or(manifest_dir); + let build_dir = workspace_dir.join("target").join(profile).join("build"); let Ok(entries) = fs::read_dir(build_dir) else { return Vec::new(); diff --git a/src/accounts/lock.rs b/crates/tele-tui/src/accounts/lock.rs similarity index 100% rename from src/accounts/lock.rs rename to crates/tele-tui/src/accounts/lock.rs diff --git a/src/accounts/manager.rs b/crates/tele-tui/src/accounts/manager.rs similarity index 100% rename from src/accounts/manager.rs rename to crates/tele-tui/src/accounts/manager.rs diff --git a/src/accounts/mod.rs b/crates/tele-tui/src/accounts/mod.rs similarity index 100% rename from src/accounts/mod.rs rename to crates/tele-tui/src/accounts/mod.rs diff --git a/src/accounts/profile.rs b/crates/tele-tui/src/accounts/profile.rs similarity index 100% rename from src/accounts/profile.rs rename to crates/tele-tui/src/accounts/profile.rs diff --git a/src/app/auth_state.rs b/crates/tele-tui/src/app/auth_state.rs similarity index 100% rename from src/app/auth_state.rs rename to crates/tele-tui/src/app/auth_state.rs diff --git a/src/app/chat_filter.rs b/crates/tele-tui/src/app/chat_filter.rs similarity index 100% rename from src/app/chat_filter.rs rename to crates/tele-tui/src/app/chat_filter.rs diff --git a/src/app/chat_list_state.rs b/crates/tele-tui/src/app/chat_list_state.rs similarity index 100% rename from src/app/chat_list_state.rs rename to crates/tele-tui/src/app/chat_list_state.rs diff --git a/src/app/chat_state.rs b/crates/tele-tui/src/app/chat_state.rs similarity index 100% rename from src/app/chat_state.rs rename to crates/tele-tui/src/app/chat_state.rs diff --git a/src/app/compose_state.rs b/crates/tele-tui/src/app/compose_state.rs similarity index 100% rename from src/app/compose_state.rs rename to crates/tele-tui/src/app/compose_state.rs diff --git a/src/app/message_service.rs b/crates/tele-tui/src/app/message_service.rs similarity index 100% rename from src/app/message_service.rs rename to crates/tele-tui/src/app/message_service.rs diff --git a/src/app/message_view_state.rs b/crates/tele-tui/src/app/message_view_state.rs similarity index 100% rename from src/app/message_view_state.rs rename to crates/tele-tui/src/app/message_view_state.rs diff --git a/src/app/methods/compose.rs b/crates/tele-tui/src/app/methods/compose.rs similarity index 100% rename from src/app/methods/compose.rs rename to crates/tele-tui/src/app/methods/compose.rs diff --git a/src/app/methods/messages.rs b/crates/tele-tui/src/app/methods/messages.rs similarity index 100% rename from src/app/methods/messages.rs rename to crates/tele-tui/src/app/methods/messages.rs diff --git a/src/app/methods/mod.rs b/crates/tele-tui/src/app/methods/mod.rs similarity index 100% rename from src/app/methods/mod.rs rename to crates/tele-tui/src/app/methods/mod.rs diff --git a/src/app/methods/modal.rs b/crates/tele-tui/src/app/methods/modal.rs similarity index 100% rename from src/app/methods/modal.rs rename to crates/tele-tui/src/app/methods/modal.rs diff --git a/src/app/methods/navigation.rs b/crates/tele-tui/src/app/methods/navigation.rs similarity index 100% rename from src/app/methods/navigation.rs rename to crates/tele-tui/src/app/methods/navigation.rs diff --git a/src/app/methods/search.rs b/crates/tele-tui/src/app/methods/search.rs similarity index 100% rename from src/app/methods/search.rs rename to crates/tele-tui/src/app/methods/search.rs diff --git a/src/app/mod.rs b/crates/tele-tui/src/app/mod.rs similarity index 96% rename from src/app/mod.rs rename to crates/tele-tui/src/app/mod.rs index 817d68a..3eff9c7 100644 --- a/src/app/mod.rs +++ b/crates/tele-tui/src/app/mod.rs @@ -15,7 +15,9 @@ pub use methods::*; pub use state::AppScreen; use crate::accounts::AccountProfile; +use crate::notifications::NotificationManager; use crate::tdlib::{ChatInfo, TdClient, TdClientTrait}; +use crate::tdlib::{TdClientConfig, TdCredentials}; use crate::types::{ChatId, MessageId}; use ratatui::widgets::ListState; use std::path::PathBuf; @@ -102,6 +104,7 @@ pub struct App { config: crate::config::Config, pub screen: AppScreen, pub td_client: T, + pub notification_manager: NotificationManager, /// Состояние чата - type-safe state machine (новое!) pub chat_state: ChatState, /// Vim-like input mode: Normal (navigation) / Insert (text input) @@ -205,11 +208,13 @@ impl App { let inline_image_renderer = crate::media::image_renderer::ImageRenderer::new_fast(); #[cfg(feature = "images")] let modal_image_renderer = crate::media::image_renderer::ImageRenderer::new(); + let notification_manager = NotificationManager::from_config(&config.notifications); App { config, screen: AppScreen::Loading, td_client, + notification_manager, chat_state: ChatState::Normal, input_mode: InputMode::Normal, phone_input: String::new(), @@ -613,8 +618,18 @@ impl App { /// /// A new `App` instance ready to start authentication. pub fn new(config: crate::config::Config, db_path: std::path::PathBuf) -> App { - let mut td_client = TdClient::new(db_path); - td_client.configure_notifications(&config.notifications); + let (api_id, api_hash) = crate::config::Config::load_credentials().unwrap_or_else(|_| { + let api_id = std::env::var("API_ID") + .unwrap_or_else(|_| "0".to_string()) + .parse() + .unwrap_or(0); + let api_hash = std::env::var("API_HASH").unwrap_or_default(); + (api_id, api_hash) + }); + let td_client = TdClient::new(TdClientConfig { + credentials: TdCredentials { api_id, api_hash }, + db_path, + }); App::with_client(config, td_client) } } diff --git a/src/app/state.rs b/crates/tele-tui/src/app/state.rs similarity index 100% rename from src/app/state.rs rename to crates/tele-tui/src/app/state.rs diff --git a/src/app/ui_state.rs b/crates/tele-tui/src/app/ui_state.rs similarity index 100% rename from src/app/ui_state.rs rename to crates/tele-tui/src/app/ui_state.rs diff --git a/src/audio/cache.rs b/crates/tele-tui/src/audio/cache.rs similarity index 100% rename from src/audio/cache.rs rename to crates/tele-tui/src/audio/cache.rs diff --git a/src/audio/mod.rs b/crates/tele-tui/src/audio/mod.rs similarity index 100% rename from src/audio/mod.rs rename to crates/tele-tui/src/audio/mod.rs diff --git a/src/audio/player.rs b/crates/tele-tui/src/audio/player.rs similarity index 100% rename from src/audio/player.rs rename to crates/tele-tui/src/audio/player.rs diff --git a/src/bin/tele-tui-test-fixture.rs b/crates/tele-tui/src/bin/tele-tui-test-fixture.rs similarity index 100% rename from src/bin/tele-tui-test-fixture.rs rename to crates/tele-tui/src/bin/tele-tui-test-fixture.rs diff --git a/src/config/keybindings.rs b/crates/tele-tui/src/config/keybindings.rs similarity index 100% rename from src/config/keybindings.rs rename to crates/tele-tui/src/config/keybindings.rs diff --git a/src/config/loader.rs b/crates/tele-tui/src/config/loader.rs similarity index 100% rename from src/config/loader.rs rename to crates/tele-tui/src/config/loader.rs diff --git a/src/config/mod.rs b/crates/tele-tui/src/config/mod.rs similarity index 100% rename from src/config/mod.rs rename to crates/tele-tui/src/config/mod.rs diff --git a/src/config/validation.rs b/crates/tele-tui/src/config/validation.rs similarity index 100% rename from src/config/validation.rs rename to crates/tele-tui/src/config/validation.rs diff --git a/src/constants.rs b/crates/tele-tui/src/constants.rs similarity index 96% rename from src/constants.rs rename to crates/tele-tui/src/constants.rs index b8c8559..fd5e56b 100644 --- a/src/constants.rs +++ b/crates/tele-tui/src/constants.rs @@ -5,15 +5,19 @@ // ============================================================================ /// Максимальное количество сообщений в одном чате (для оптимизации памяти) +#[allow(dead_code)] pub const MAX_MESSAGES_IN_CHAT: usize = 500; /// Максимальный размер кэша пользователей (LRU) +#[allow(dead_code)] pub const MAX_USER_CACHE_SIZE: usize = 500; /// Максимальное количество чатов для загрузки +#[allow(dead_code)] pub const MAX_CHATS: usize = 200; /// Максимальное количество user_ids для хранения в чате +#[allow(dead_code)] pub const MAX_CHAT_USER_IDS: usize = 500; // ============================================================================ @@ -27,6 +31,7 @@ pub const POLL_TIMEOUT_MS: u64 = 16; pub const SHUTDOWN_TIMEOUT_SECS: u64 = 2; /// Количество пользователей для ленивой загрузки за один тик +#[allow(dead_code)] pub const LAZY_LOAD_USERS_PER_TICK: usize = 5; // ============================================================================ @@ -34,6 +39,7 @@ pub const LAZY_LOAD_USERS_PER_TICK: usize = 5; // ============================================================================ /// Лимит количества сообщений для загрузки через TDLib за раз +#[allow(dead_code)] pub const TDLIB_MESSAGE_LIMIT: i32 = 50; // ============================================================================ diff --git a/src/formatting.rs b/crates/tele-tui/src/formatting.rs similarity index 100% rename from src/formatting.rs rename to crates/tele-tui/src/formatting.rs diff --git a/src/input/auth.rs b/crates/tele-tui/src/input/auth.rs similarity index 100% rename from src/input/auth.rs rename to crates/tele-tui/src/input/auth.rs diff --git a/src/input/handlers/chat.rs b/crates/tele-tui/src/input/handlers/chat.rs similarity index 100% rename from src/input/handlers/chat.rs rename to crates/tele-tui/src/input/handlers/chat.rs diff --git a/src/input/handlers/chat/media.rs b/crates/tele-tui/src/input/handlers/chat/media.rs similarity index 100% rename from src/input/handlers/chat/media.rs rename to crates/tele-tui/src/input/handlers/chat/media.rs diff --git a/src/input/handlers/chat_list.rs b/crates/tele-tui/src/input/handlers/chat_list.rs similarity index 100% rename from src/input/handlers/chat_list.rs rename to crates/tele-tui/src/input/handlers/chat_list.rs diff --git a/src/input/handlers/chat_loader.rs b/crates/tele-tui/src/input/handlers/chat_loader.rs similarity index 100% rename from src/input/handlers/chat_loader.rs rename to crates/tele-tui/src/input/handlers/chat_loader.rs diff --git a/src/input/handlers/clipboard.rs b/crates/tele-tui/src/input/handlers/clipboard.rs similarity index 100% rename from src/input/handlers/clipboard.rs rename to crates/tele-tui/src/input/handlers/clipboard.rs diff --git a/src/input/handlers/compose.rs b/crates/tele-tui/src/input/handlers/compose.rs similarity index 100% rename from src/input/handlers/compose.rs rename to crates/tele-tui/src/input/handlers/compose.rs diff --git a/src/input/handlers/global.rs b/crates/tele-tui/src/input/handlers/global.rs similarity index 97% rename from src/input/handlers/global.rs rename to crates/tele-tui/src/input/handlers/global.rs index 23d935d..3eed6ce 100644 --- a/src/input/handlers/global.rs +++ b/crates/tele-tui/src/input/handlers/global.rs @@ -50,7 +50,8 @@ pub async fn handle_global_commands(app: &mut App, key: Key let _ = with_timeout(Duration::from_secs(5), app.td_client.load_chats(50)).await; // Синхронизируем muted чаты после обновления - app.td_client.sync_notification_muted_chats(); + app.notification_manager + .sync_muted_chats(app.td_client.chats()); app.status_message = None; true } diff --git a/src/input/handlers/mod.rs b/crates/tele-tui/src/input/handlers/mod.rs similarity index 100% rename from src/input/handlers/mod.rs rename to crates/tele-tui/src/input/handlers/mod.rs diff --git a/src/input/handlers/modal.rs b/crates/tele-tui/src/input/handlers/modal.rs similarity index 100% rename from src/input/handlers/modal.rs rename to crates/tele-tui/src/input/handlers/modal.rs diff --git a/src/input/handlers/modal/account.rs b/crates/tele-tui/src/input/handlers/modal/account.rs similarity index 100% rename from src/input/handlers/modal/account.rs rename to crates/tele-tui/src/input/handlers/modal/account.rs diff --git a/src/input/handlers/modal/delete.rs b/crates/tele-tui/src/input/handlers/modal/delete.rs similarity index 100% rename from src/input/handlers/modal/delete.rs rename to crates/tele-tui/src/input/handlers/modal/delete.rs diff --git a/src/input/handlers/modal/pinned.rs b/crates/tele-tui/src/input/handlers/modal/pinned.rs similarity index 100% rename from src/input/handlers/modal/pinned.rs rename to crates/tele-tui/src/input/handlers/modal/pinned.rs diff --git a/src/input/handlers/modal/profile.rs b/crates/tele-tui/src/input/handlers/modal/profile.rs similarity index 100% rename from src/input/handlers/modal/profile.rs rename to crates/tele-tui/src/input/handlers/modal/profile.rs diff --git a/src/input/handlers/modal/reactions.rs b/crates/tele-tui/src/input/handlers/modal/reactions.rs similarity index 100% rename from src/input/handlers/modal/reactions.rs rename to crates/tele-tui/src/input/handlers/modal/reactions.rs diff --git a/src/input/handlers/profile.rs b/crates/tele-tui/src/input/handlers/profile.rs similarity index 100% rename from src/input/handlers/profile.rs rename to crates/tele-tui/src/input/handlers/profile.rs diff --git a/src/input/handlers/search.rs b/crates/tele-tui/src/input/handlers/search.rs similarity index 100% rename from src/input/handlers/search.rs rename to crates/tele-tui/src/input/handlers/search.rs diff --git a/src/input/main_input.rs b/crates/tele-tui/src/input/main_input.rs similarity index 100% rename from src/input/main_input.rs rename to crates/tele-tui/src/input/main_input.rs diff --git a/src/input/mod.rs b/crates/tele-tui/src/input/mod.rs similarity index 100% rename from src/input/mod.rs rename to crates/tele-tui/src/input/mod.rs diff --git a/src/lib.rs b/crates/tele-tui/src/lib.rs similarity index 87% rename from src/lib.rs rename to crates/tele-tui/src/lib.rs index 976aaa1..3028777 100644 --- a/src/lib.rs +++ b/crates/tele-tui/src/lib.rs @@ -11,11 +11,10 @@ pub mod formatting; pub mod input; #[cfg(feature = "images")] pub mod media; -pub mod message_grouping; pub mod notifications; -pub mod tdlib; #[cfg(any(test, feature = "test-support"))] pub mod test_support; -pub mod types; pub mod ui; pub mod utils; + +pub use tele_core::{message_grouping, tdlib, types}; diff --git a/src/main.rs b/crates/tele-tui/src/main.rs similarity index 97% rename from src/main.rs rename to crates/tele-tui/src/main.rs index 36f917c..18065f2 100644 --- a/src/main.rs +++ b/crates/tele-tui/src/main.rs @@ -7,13 +7,12 @@ mod formatting; mod input; #[cfg(feature = "images")] mod media; -mod message_grouping; mod notifications; -mod tdlib; -mod types; mod ui; mod utils; +pub use tele_core::{message_grouping, tdlib, types}; + use crossterm::{ event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyModifiers}, execute, @@ -202,6 +201,13 @@ async fn run_app( ); } } + for event in app.td_client.drain_incoming_message_events() { + let _ = app.notification_manager.notify_new_message( + &event.chat, + &event.message, + &event.sender_name, + ); + } // Помечаем UI как требующий перерисовки если были обновления if had_updates { @@ -437,7 +443,7 @@ async fn run_app( continue; } let notifications_cfg = app.config().notifications.clone(); - app.td_client.configure_notifications(¬ifications_cfg); + app.notification_manager.configure(¬ifications_cfg); // 4. Reset app state app.current_account_name = account_name.clone(); @@ -509,7 +515,8 @@ async fn update_screen_state(app: &mut App) -> bool app.chat_list_state.select(Some(0)); } // Синхронизируем muted чаты для notifications - app.td_client.sync_notification_muted_chats(); + app.notification_manager + .sync_muted_chats(app.td_client.chats()); // Убираем статус загрузки когда чаты появились if app.is_loading { app.is_loading = false; diff --git a/src/media/cache.rs b/crates/tele-tui/src/media/cache.rs similarity index 100% rename from src/media/cache.rs rename to crates/tele-tui/src/media/cache.rs diff --git a/src/media/image_renderer.rs b/crates/tele-tui/src/media/image_renderer.rs similarity index 100% rename from src/media/image_renderer.rs rename to crates/tele-tui/src/media/image_renderer.rs diff --git a/src/media/mod.rs b/crates/tele-tui/src/media/mod.rs similarity index 100% rename from src/media/mod.rs rename to crates/tele-tui/src/media/mod.rs diff --git a/src/notifications.rs b/crates/tele-tui/src/notifications.rs similarity index 94% rename from src/notifications.rs rename to crates/tele-tui/src/notifications.rs index 125f722..a67bcbb 100644 --- a/src/notifications.rs +++ b/crates/tele-tui/src/notifications.rs @@ -52,6 +52,22 @@ impl NotificationManager { } } + /// Creates a notification manager from application config. + pub fn from_config(config: &crate::config::NotificationsConfig) -> Self { + let mut manager = Self::new(); + manager.configure(config); + manager + } + + /// Applies notification settings from application config. + pub fn configure(&mut self, config: &crate::config::NotificationsConfig) { + self.set_enabled(config.enabled); + self.set_only_mentions(config.only_mentions); + self.set_show_preview(config.show_preview); + self.set_timeout(config.timeout_ms); + self.set_urgency(config.urgency.clone()); + } + /// Sets whether notifications are enabled pub fn set_enabled(&mut self, enabled: bool) { self.enabled = enabled; diff --git a/src/test_support/app_builder.rs b/crates/tele-tui/src/test_support/app_builder.rs similarity index 100% rename from src/test_support/app_builder.rs rename to crates/tele-tui/src/test_support/app_builder.rs diff --git a/src/test_support/mod.rs b/crates/tele-tui/src/test_support/mod.rs similarity index 54% rename from src/test_support/mod.rs rename to crates/tele-tui/src/test_support/mod.rs index 6ce3c4e..f06c78a 100644 --- a/src/test_support/mod.rs +++ b/crates/tele-tui/src/test_support/mod.rs @@ -1,9 +1,6 @@ //! Test-only support for deterministic UI fixtures and integration tests. pub mod app_builder; -pub mod fake_tdclient; -mod fake_tdclient_impl; pub mod snapshot_utils; -pub mod test_data; -pub use fake_tdclient::FakeTdClient; +pub use tele_core::test_support::{fake_tdclient, test_data, FakeTdClient}; diff --git a/src/test_support/snapshot_utils.rs b/crates/tele-tui/src/test_support/snapshot_utils.rs similarity index 100% rename from src/test_support/snapshot_utils.rs rename to crates/tele-tui/src/test_support/snapshot_utils.rs diff --git a/src/ui/auth.rs b/crates/tele-tui/src/ui/auth.rs similarity index 100% rename from src/ui/auth.rs rename to crates/tele-tui/src/ui/auth.rs diff --git a/src/ui/chat_list.rs b/crates/tele-tui/src/ui/chat_list.rs similarity index 100% rename from src/ui/chat_list.rs rename to crates/tele-tui/src/ui/chat_list.rs diff --git a/src/ui/components/chat_list_item.rs b/crates/tele-tui/src/ui/components/chat_list_item.rs similarity index 100% rename from src/ui/components/chat_list_item.rs rename to crates/tele-tui/src/ui/components/chat_list_item.rs diff --git a/src/ui/components/emoji_picker.rs b/crates/tele-tui/src/ui/components/emoji_picker.rs similarity index 100% rename from src/ui/components/emoji_picker.rs rename to crates/tele-tui/src/ui/components/emoji_picker.rs diff --git a/src/ui/components/input_field.rs b/crates/tele-tui/src/ui/components/input_field.rs similarity index 100% rename from src/ui/components/input_field.rs rename to crates/tele-tui/src/ui/components/input_field.rs diff --git a/src/ui/components/message_bubble.rs b/crates/tele-tui/src/ui/components/message_bubble.rs similarity index 100% rename from src/ui/components/message_bubble.rs rename to crates/tele-tui/src/ui/components/message_bubble.rs diff --git a/src/ui/components/message_list.rs b/crates/tele-tui/src/ui/components/message_list.rs similarity index 100% rename from src/ui/components/message_list.rs rename to crates/tele-tui/src/ui/components/message_list.rs diff --git a/src/ui/components/mod.rs b/crates/tele-tui/src/ui/components/mod.rs similarity index 100% rename from src/ui/components/mod.rs rename to crates/tele-tui/src/ui/components/mod.rs diff --git a/src/ui/components/modal.rs b/crates/tele-tui/src/ui/components/modal.rs similarity index 100% rename from src/ui/components/modal.rs rename to crates/tele-tui/src/ui/components/modal.rs diff --git a/src/ui/compose_bar.rs b/crates/tele-tui/src/ui/compose_bar.rs similarity index 100% rename from src/ui/compose_bar.rs rename to crates/tele-tui/src/ui/compose_bar.rs diff --git a/src/ui/footer.rs b/crates/tele-tui/src/ui/footer.rs similarity index 100% rename from src/ui/footer.rs rename to crates/tele-tui/src/ui/footer.rs diff --git a/src/ui/loading.rs b/crates/tele-tui/src/ui/loading.rs similarity index 100% rename from src/ui/loading.rs rename to crates/tele-tui/src/ui/loading.rs diff --git a/src/ui/main_screen.rs b/crates/tele-tui/src/ui/main_screen.rs similarity index 100% rename from src/ui/main_screen.rs rename to crates/tele-tui/src/ui/main_screen.rs diff --git a/src/ui/messages.rs b/crates/tele-tui/src/ui/messages.rs similarity index 100% rename from src/ui/messages.rs rename to crates/tele-tui/src/ui/messages.rs diff --git a/src/ui/messages/header.rs b/crates/tele-tui/src/ui/messages/header.rs similarity index 100% rename from src/ui/messages/header.rs rename to crates/tele-tui/src/ui/messages/header.rs diff --git a/src/ui/messages/list.rs b/crates/tele-tui/src/ui/messages/list.rs similarity index 100% rename from src/ui/messages/list.rs rename to crates/tele-tui/src/ui/messages/list.rs diff --git a/src/ui/messages/pinned.rs b/crates/tele-tui/src/ui/messages/pinned.rs similarity index 100% rename from src/ui/messages/pinned.rs rename to crates/tele-tui/src/ui/messages/pinned.rs diff --git a/src/ui/mod.rs b/crates/tele-tui/src/ui/mod.rs similarity index 100% rename from src/ui/mod.rs rename to crates/tele-tui/src/ui/mod.rs diff --git a/src/ui/modals/account_switcher.rs b/crates/tele-tui/src/ui/modals/account_switcher.rs similarity index 100% rename from src/ui/modals/account_switcher.rs rename to crates/tele-tui/src/ui/modals/account_switcher.rs diff --git a/src/ui/modals/delete_confirm.rs b/crates/tele-tui/src/ui/modals/delete_confirm.rs similarity index 100% rename from src/ui/modals/delete_confirm.rs rename to crates/tele-tui/src/ui/modals/delete_confirm.rs diff --git a/src/ui/modals/image_viewer.rs b/crates/tele-tui/src/ui/modals/image_viewer.rs similarity index 100% rename from src/ui/modals/image_viewer.rs rename to crates/tele-tui/src/ui/modals/image_viewer.rs diff --git a/src/ui/modals/mod.rs b/crates/tele-tui/src/ui/modals/mod.rs similarity index 100% rename from src/ui/modals/mod.rs rename to crates/tele-tui/src/ui/modals/mod.rs diff --git a/src/ui/modals/pinned.rs b/crates/tele-tui/src/ui/modals/pinned.rs similarity index 100% rename from src/ui/modals/pinned.rs rename to crates/tele-tui/src/ui/modals/pinned.rs diff --git a/src/ui/modals/reaction_picker.rs b/crates/tele-tui/src/ui/modals/reaction_picker.rs similarity index 100% rename from src/ui/modals/reaction_picker.rs rename to crates/tele-tui/src/ui/modals/reaction_picker.rs diff --git a/src/ui/modals/search.rs b/crates/tele-tui/src/ui/modals/search.rs similarity index 100% rename from src/ui/modals/search.rs rename to crates/tele-tui/src/ui/modals/search.rs diff --git a/src/ui/profile.rs b/crates/tele-tui/src/ui/profile.rs similarity index 100% rename from src/ui/profile.rs rename to crates/tele-tui/src/ui/profile.rs diff --git a/src/utils/formatting.rs b/crates/tele-tui/src/utils/formatting.rs similarity index 99% rename from src/utils/formatting.rs rename to crates/tele-tui/src/utils/formatting.rs index 1cb5088..1ed6709 100644 --- a/src/utils/formatting.rs +++ b/crates/tele-tui/src/utils/formatting.rs @@ -111,10 +111,12 @@ pub fn format_date_with(timestamp: i32, time: &impl LocalTimeSource) -> String { /// Получить день из timestamp для группировки. /// Возвращает число дней с 1970-01-01 в системной таймзоне. +#[allow(dead_code)] pub fn get_day(timestamp: i32) -> i64 { get_day_with(timestamp, &system_time()) } +#[allow(dead_code)] pub fn get_day_with(timestamp: i32, time: &impl LocalTimeSource) -> i64 { let epoch = NaiveDate::from_ymd_opt(1970, 1, 1).expect("valid epoch date"); diff --git a/src/utils/mod.rs b/crates/tele-tui/src/utils/mod.rs similarity index 100% rename from src/utils/mod.rs rename to crates/tele-tui/src/utils/mod.rs diff --git a/src/utils/modal_handler.rs b/crates/tele-tui/src/utils/modal_handler.rs similarity index 100% rename from src/utils/modal_handler.rs rename to crates/tele-tui/src/utils/modal_handler.rs diff --git a/src/utils/retry.rs b/crates/tele-tui/src/utils/retry.rs similarity index 100% rename from src/utils/retry.rs rename to crates/tele-tui/src/utils/retry.rs diff --git a/src/utils/tdlib.rs b/crates/tele-tui/src/utils/tdlib.rs similarity index 100% rename from src/utils/tdlib.rs rename to crates/tele-tui/src/utils/tdlib.rs diff --git a/src/utils/validation.rs b/crates/tele-tui/src/utils/validation.rs similarity index 100% rename from src/utils/validation.rs rename to crates/tele-tui/src/utils/validation.rs diff --git a/tests/account_switcher.rs b/crates/tele-tui/tests/account_switcher.rs similarity index 100% rename from tests/account_switcher.rs rename to crates/tele-tui/tests/account_switcher.rs diff --git a/tests/accounts.rs b/crates/tele-tui/tests/accounts.rs similarity index 100% rename from tests/accounts.rs rename to crates/tele-tui/tests/accounts.rs diff --git a/tests/chat_list.rs b/crates/tele-tui/tests/chat_list.rs similarity index 100% rename from tests/chat_list.rs rename to crates/tele-tui/tests/chat_list.rs diff --git a/tests/config.rs b/crates/tele-tui/tests/config.rs similarity index 100% rename from tests/config.rs rename to crates/tele-tui/tests/config.rs diff --git a/tests/copy.rs b/crates/tele-tui/tests/copy.rs similarity index 100% rename from tests/copy.rs rename to crates/tele-tui/tests/copy.rs diff --git a/tests/delete_message.rs b/crates/tele-tui/tests/delete_message.rs similarity index 100% rename from tests/delete_message.rs rename to crates/tele-tui/tests/delete_message.rs diff --git a/tests/drafts.rs b/crates/tele-tui/tests/drafts.rs similarity index 100% rename from tests/drafts.rs rename to crates/tele-tui/tests/drafts.rs diff --git a/tests/e2e_smoke.rs b/crates/tele-tui/tests/e2e_smoke.rs similarity index 100% rename from tests/e2e_smoke.rs rename to crates/tele-tui/tests/e2e_smoke.rs diff --git a/tests/e2e_termwright.rs b/crates/tele-tui/tests/e2e_termwright.rs similarity index 100% rename from tests/e2e_termwright.rs rename to crates/tele-tui/tests/e2e_termwright.rs diff --git a/tests/e2e_user_journey.rs b/crates/tele-tui/tests/e2e_user_journey.rs similarity index 100% rename from tests/e2e_user_journey.rs rename to crates/tele-tui/tests/e2e_user_journey.rs diff --git a/tests/edit_message.rs b/crates/tele-tui/tests/edit_message.rs similarity index 100% rename from tests/edit_message.rs rename to crates/tele-tui/tests/edit_message.rs diff --git a/tests/footer.rs b/crates/tele-tui/tests/footer.rs similarity index 100% rename from tests/footer.rs rename to crates/tele-tui/tests/footer.rs diff --git a/tests/helpers/app_builder.rs b/crates/tele-tui/tests/helpers/app_builder.rs similarity index 100% rename from tests/helpers/app_builder.rs rename to crates/tele-tui/tests/helpers/app_builder.rs diff --git a/tests/helpers/fake_tdclient.rs b/crates/tele-tui/tests/helpers/fake_tdclient.rs similarity index 100% rename from tests/helpers/fake_tdclient.rs rename to crates/tele-tui/tests/helpers/fake_tdclient.rs diff --git a/tests/helpers/fake_tdclient/builders.rs b/crates/tele-tui/tests/helpers/fake_tdclient/builders.rs similarity index 100% rename from tests/helpers/fake_tdclient/builders.rs rename to crates/tele-tui/tests/helpers/fake_tdclient/builders.rs diff --git a/tests/helpers/fake_tdclient/inspect.rs b/crates/tele-tui/tests/helpers/fake_tdclient/inspect.rs similarity index 100% rename from tests/helpers/fake_tdclient/inspect.rs rename to crates/tele-tui/tests/helpers/fake_tdclient/inspect.rs diff --git a/tests/helpers/fake_tdclient/operations.rs b/crates/tele-tui/tests/helpers/fake_tdclient/operations.rs similarity index 100% rename from tests/helpers/fake_tdclient/operations.rs rename to crates/tele-tui/tests/helpers/fake_tdclient/operations.rs diff --git a/tests/helpers/fake_tdclient/state.rs b/crates/tele-tui/tests/helpers/fake_tdclient/state.rs similarity index 100% rename from tests/helpers/fake_tdclient/state.rs rename to crates/tele-tui/tests/helpers/fake_tdclient/state.rs diff --git a/tests/helpers/fake_tdclient_impl.rs b/crates/tele-tui/tests/helpers/fake_tdclient_impl.rs similarity index 97% rename from tests/helpers/fake_tdclient_impl.rs rename to crates/tele-tui/tests/helpers/fake_tdclient_impl.rs index cf5e2fc..8412ece 100644 --- a/tests/helpers/fake_tdclient_impl.rs +++ b/crates/tele-tui/tests/helpers/fake_tdclient_impl.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; use tdlib_rs::enums::{ChatAction, Update}; use tele_tui::tdlib::{ AccountClient, AuthClient, ChatActionClient, ChatClient, ClientState, FileClient, - MessageClient, NotificationClient, ReactionClient, UpdateClient, UserClient, + MessageClient, ReactionClient, UpdateClient, UserClient, }; use tele_tui::tdlib::{ AuthState, ChatInfo, FolderInfo, MessageInfo, ProfileInfo, ReplyInfo, UserCache, @@ -342,12 +342,6 @@ impl ClientState for FakeTdClient { } } -impl NotificationClient for FakeTdClient { - fn configure_notifications(&mut self, _config: &tele_tui::config::NotificationsConfig) {} - - fn sync_notification_muted_chats(&mut self) {} -} - #[async_trait] impl AccountClient for FakeTdClient { async fn recreate_client(&mut self, _db_path: PathBuf) -> Result<(), String> { @@ -357,4 +351,8 @@ impl AccountClient for FakeTdClient { impl UpdateClient for FakeTdClient { fn handle_update(&mut self, _update: Update) {} + + fn drain_incoming_message_events(&mut self) -> Vec { + Vec::new() + } } diff --git a/tests/helpers/mod.rs b/crates/tele-tui/tests/helpers/mod.rs similarity index 100% rename from tests/helpers/mod.rs rename to crates/tele-tui/tests/helpers/mod.rs diff --git a/tests/helpers/snapshot_utils.rs b/crates/tele-tui/tests/helpers/snapshot_utils.rs similarity index 100% rename from tests/helpers/snapshot_utils.rs rename to crates/tele-tui/tests/helpers/snapshot_utils.rs diff --git a/tests/helpers/test_data.rs b/crates/tele-tui/tests/helpers/test_data.rs similarity index 100% rename from tests/helpers/test_data.rs rename to crates/tele-tui/tests/helpers/test_data.rs diff --git a/tests/input_field.rs b/crates/tele-tui/tests/input_field.rs similarity index 100% rename from tests/input_field.rs rename to crates/tele-tui/tests/input_field.rs diff --git a/tests/input_navigation.rs b/crates/tele-tui/tests/input_navigation.rs similarity index 100% rename from tests/input_navigation.rs rename to crates/tele-tui/tests/input_navigation.rs diff --git a/tests/messages.rs b/crates/tele-tui/tests/messages.rs similarity index 100% rename from tests/messages.rs rename to crates/tele-tui/tests/messages.rs diff --git a/tests/modals.rs b/crates/tele-tui/tests/modals.rs similarity index 100% rename from tests/modals.rs rename to crates/tele-tui/tests/modals.rs diff --git a/tests/navigation.rs b/crates/tele-tui/tests/navigation.rs similarity index 100% rename from tests/navigation.rs rename to crates/tele-tui/tests/navigation.rs diff --git a/tests/network_typing.rs b/crates/tele-tui/tests/network_typing.rs similarity index 100% rename from tests/network_typing.rs rename to crates/tele-tui/tests/network_typing.rs diff --git a/tests/profile.rs b/crates/tele-tui/tests/profile.rs similarity index 100% rename from tests/profile.rs rename to crates/tele-tui/tests/profile.rs diff --git a/tests/reactions.rs b/crates/tele-tui/tests/reactions.rs similarity index 100% rename from tests/reactions.rs rename to crates/tele-tui/tests/reactions.rs diff --git a/tests/reply_forward.rs b/crates/tele-tui/tests/reply_forward.rs similarity index 100% rename from tests/reply_forward.rs rename to crates/tele-tui/tests/reply_forward.rs diff --git a/tests/screens.rs b/crates/tele-tui/tests/screens.rs similarity index 100% rename from tests/screens.rs rename to crates/tele-tui/tests/screens.rs diff --git a/tests/search.rs b/crates/tele-tui/tests/search.rs similarity index 100% rename from tests/search.rs rename to crates/tele-tui/tests/search.rs diff --git a/tests/send_message.rs b/crates/tele-tui/tests/send_message.rs similarity index 100% rename from tests/send_message.rs rename to crates/tele-tui/tests/send_message.rs diff --git a/tests/snapshots/chat_list__chat_list_search_mode.snap b/crates/tele-tui/tests/snapshots/chat_list__chat_list_search_mode.snap similarity index 100% rename from tests/snapshots/chat_list__chat_list_search_mode.snap rename to crates/tele-tui/tests/snapshots/chat_list__chat_list_search_mode.snap diff --git a/tests/snapshots/chat_list__chat_list_three_chats.snap b/crates/tele-tui/tests/snapshots/chat_list__chat_list_three_chats.snap similarity index 100% rename from tests/snapshots/chat_list__chat_list_three_chats.snap rename to crates/tele-tui/tests/snapshots/chat_list__chat_list_three_chats.snap diff --git a/tests/snapshots/chat_list__chat_long_title.snap b/crates/tele-tui/tests/snapshots/chat_list__chat_long_title.snap similarity index 100% rename from tests/snapshots/chat_list__chat_long_title.snap rename to crates/tele-tui/tests/snapshots/chat_list__chat_long_title.snap diff --git a/tests/snapshots/chat_list__chat_muted.snap b/crates/tele-tui/tests/snapshots/chat_list__chat_muted.snap similarity index 100% rename from tests/snapshots/chat_list__chat_muted.snap rename to crates/tele-tui/tests/snapshots/chat_list__chat_muted.snap diff --git a/tests/snapshots/chat_list__chat_pinned.snap b/crates/tele-tui/tests/snapshots/chat_list__chat_pinned.snap similarity index 100% rename from tests/snapshots/chat_list__chat_pinned.snap rename to crates/tele-tui/tests/snapshots/chat_list__chat_pinned.snap diff --git a/tests/snapshots/chat_list__chat_selected.snap b/crates/tele-tui/tests/snapshots/chat_list__chat_selected.snap similarity index 100% rename from tests/snapshots/chat_list__chat_selected.snap rename to crates/tele-tui/tests/snapshots/chat_list__chat_selected.snap diff --git a/tests/snapshots/chat_list__chat_with_mentions.snap b/crates/tele-tui/tests/snapshots/chat_list__chat_with_mentions.snap similarity index 100% rename from tests/snapshots/chat_list__chat_with_mentions.snap rename to crates/tele-tui/tests/snapshots/chat_list__chat_with_mentions.snap diff --git a/tests/snapshots/chat_list__chat_with_online_status.snap b/crates/tele-tui/tests/snapshots/chat_list__chat_with_online_status.snap similarity index 100% rename from tests/snapshots/chat_list__chat_with_online_status.snap rename to crates/tele-tui/tests/snapshots/chat_list__chat_with_online_status.snap diff --git a/tests/snapshots/chat_list__chat_with_unread.snap b/crates/tele-tui/tests/snapshots/chat_list__chat_with_unread.snap similarity index 100% rename from tests/snapshots/chat_list__chat_with_unread.snap rename to crates/tele-tui/tests/snapshots/chat_list__chat_with_unread.snap diff --git a/tests/snapshots/chat_list__empty_chat_list.snap b/crates/tele-tui/tests/snapshots/chat_list__empty_chat_list.snap similarity index 100% rename from tests/snapshots/chat_list__empty_chat_list.snap rename to crates/tele-tui/tests/snapshots/chat_list__empty_chat_list.snap diff --git a/tests/snapshots/footer__footer_chat_list.snap b/crates/tele-tui/tests/snapshots/footer__footer_chat_list.snap similarity index 100% rename from tests/snapshots/footer__footer_chat_list.snap rename to crates/tele-tui/tests/snapshots/footer__footer_chat_list.snap diff --git a/tests/snapshots/footer__footer_network_connecting.snap b/crates/tele-tui/tests/snapshots/footer__footer_network_connecting.snap similarity index 100% rename from tests/snapshots/footer__footer_network_connecting.snap rename to crates/tele-tui/tests/snapshots/footer__footer_network_connecting.snap diff --git a/tests/snapshots/footer__footer_network_connecting_proxy.snap b/crates/tele-tui/tests/snapshots/footer__footer_network_connecting_proxy.snap similarity index 100% rename from tests/snapshots/footer__footer_network_connecting_proxy.snap rename to crates/tele-tui/tests/snapshots/footer__footer_network_connecting_proxy.snap diff --git a/tests/snapshots/footer__footer_network_waiting.snap b/crates/tele-tui/tests/snapshots/footer__footer_network_waiting.snap similarity index 100% rename from tests/snapshots/footer__footer_network_waiting.snap rename to crates/tele-tui/tests/snapshots/footer__footer_network_waiting.snap diff --git a/tests/snapshots/footer__footer_open_chat.snap b/crates/tele-tui/tests/snapshots/footer__footer_open_chat.snap similarity index 100% rename from tests/snapshots/footer__footer_open_chat.snap rename to crates/tele-tui/tests/snapshots/footer__footer_open_chat.snap diff --git a/tests/snapshots/footer__footer_search_mode.snap b/crates/tele-tui/tests/snapshots/footer__footer_search_mode.snap similarity index 100% rename from tests/snapshots/footer__footer_search_mode.snap rename to crates/tele-tui/tests/snapshots/footer__footer_search_mode.snap diff --git a/tests/snapshots/input_field__empty_input.snap b/crates/tele-tui/tests/snapshots/input_field__empty_input.snap similarity index 100% rename from tests/snapshots/input_field__empty_input.snap rename to crates/tele-tui/tests/snapshots/input_field__empty_input.snap diff --git a/tests/snapshots/input_field__input_editing_mode.snap b/crates/tele-tui/tests/snapshots/input_field__input_editing_mode.snap similarity index 100% rename from tests/snapshots/input_field__input_editing_mode.snap rename to crates/tele-tui/tests/snapshots/input_field__input_editing_mode.snap diff --git a/tests/snapshots/input_field__input_long_text_2_lines.snap b/crates/tele-tui/tests/snapshots/input_field__input_long_text_2_lines.snap similarity index 100% rename from tests/snapshots/input_field__input_long_text_2_lines.snap rename to crates/tele-tui/tests/snapshots/input_field__input_long_text_2_lines.snap diff --git a/tests/snapshots/input_field__input_long_text_max_lines.snap b/crates/tele-tui/tests/snapshots/input_field__input_long_text_max_lines.snap similarity index 100% rename from tests/snapshots/input_field__input_long_text_max_lines.snap rename to crates/tele-tui/tests/snapshots/input_field__input_long_text_max_lines.snap diff --git a/tests/snapshots/input_field__input_reply_mode.snap b/crates/tele-tui/tests/snapshots/input_field__input_reply_mode.snap similarity index 100% rename from tests/snapshots/input_field__input_reply_mode.snap rename to crates/tele-tui/tests/snapshots/input_field__input_reply_mode.snap diff --git a/tests/snapshots/input_field__input_search_mode.snap b/crates/tele-tui/tests/snapshots/input_field__input_search_mode.snap similarity index 100% rename from tests/snapshots/input_field__input_search_mode.snap rename to crates/tele-tui/tests/snapshots/input_field__input_search_mode.snap diff --git a/tests/snapshots/input_field__input_with_text.snap b/crates/tele-tui/tests/snapshots/input_field__input_with_text.snap similarity index 100% rename from tests/snapshots/input_field__input_with_text.snap rename to crates/tele-tui/tests/snapshots/input_field__input_with_text.snap diff --git a/tests/snapshots/messages__album_incoming.snap b/crates/tele-tui/tests/snapshots/messages__album_incoming.snap similarity index 100% rename from tests/snapshots/messages__album_incoming.snap rename to crates/tele-tui/tests/snapshots/messages__album_incoming.snap diff --git a/tests/snapshots/messages__album_outgoing.snap b/crates/tele-tui/tests/snapshots/messages__album_outgoing.snap similarity index 100% rename from tests/snapshots/messages__album_outgoing.snap rename to crates/tele-tui/tests/snapshots/messages__album_outgoing.snap diff --git a/tests/snapshots/messages__album_selected.snap b/crates/tele-tui/tests/snapshots/messages__album_selected.snap similarity index 100% rename from tests/snapshots/messages__album_selected.snap rename to crates/tele-tui/tests/snapshots/messages__album_selected.snap diff --git a/tests/snapshots/messages__album_with_regular_messages.snap b/crates/tele-tui/tests/snapshots/messages__album_with_regular_messages.snap similarity index 100% rename from tests/snapshots/messages__album_with_regular_messages.snap rename to crates/tele-tui/tests/snapshots/messages__album_with_regular_messages.snap diff --git a/tests/snapshots/messages__date_separator_old_date.snap b/crates/tele-tui/tests/snapshots/messages__date_separator_old_date.snap similarity index 100% rename from tests/snapshots/messages__date_separator_old_date.snap rename to crates/tele-tui/tests/snapshots/messages__date_separator_old_date.snap diff --git a/tests/snapshots/messages__edited_message.snap b/crates/tele-tui/tests/snapshots/messages__edited_message.snap similarity index 100% rename from tests/snapshots/messages__edited_message.snap rename to crates/tele-tui/tests/snapshots/messages__edited_message.snap diff --git a/tests/snapshots/messages__empty_chat.snap b/crates/tele-tui/tests/snapshots/messages__empty_chat.snap similarity index 100% rename from tests/snapshots/messages__empty_chat.snap rename to crates/tele-tui/tests/snapshots/messages__empty_chat.snap diff --git a/tests/snapshots/messages__forwarded_message.snap b/crates/tele-tui/tests/snapshots/messages__forwarded_message.snap similarity index 100% rename from tests/snapshots/messages__forwarded_message.snap rename to crates/tele-tui/tests/snapshots/messages__forwarded_message.snap diff --git a/tests/snapshots/messages__long_message_wrap.snap b/crates/tele-tui/tests/snapshots/messages__long_message_wrap.snap similarity index 100% rename from tests/snapshots/messages__long_message_wrap.snap rename to crates/tele-tui/tests/snapshots/messages__long_message_wrap.snap diff --git a/tests/snapshots/messages__markdown_bold_italic_code.snap b/crates/tele-tui/tests/snapshots/messages__markdown_bold_italic_code.snap similarity index 100% rename from tests/snapshots/messages__markdown_bold_italic_code.snap rename to crates/tele-tui/tests/snapshots/messages__markdown_bold_italic_code.snap diff --git a/tests/snapshots/messages__markdown_link_mention.snap b/crates/tele-tui/tests/snapshots/messages__markdown_link_mention.snap similarity index 100% rename from tests/snapshots/messages__markdown_link_mention.snap rename to crates/tele-tui/tests/snapshots/messages__markdown_link_mention.snap diff --git a/tests/snapshots/messages__markdown_spoiler.snap b/crates/tele-tui/tests/snapshots/messages__markdown_spoiler.snap similarity index 100% rename from tests/snapshots/messages__markdown_spoiler.snap rename to crates/tele-tui/tests/snapshots/messages__markdown_spoiler.snap diff --git a/tests/snapshots/messages__media_placeholder.snap b/crates/tele-tui/tests/snapshots/messages__media_placeholder.snap similarity index 100% rename from tests/snapshots/messages__media_placeholder.snap rename to crates/tele-tui/tests/snapshots/messages__media_placeholder.snap diff --git a/tests/snapshots/messages__multiple_reactions.snap b/crates/tele-tui/tests/snapshots/messages__multiple_reactions.snap similarity index 100% rename from tests/snapshots/messages__multiple_reactions.snap rename to crates/tele-tui/tests/snapshots/messages__multiple_reactions.snap diff --git a/tests/snapshots/messages__outgoing_read.snap b/crates/tele-tui/tests/snapshots/messages__outgoing_read.snap similarity index 100% rename from tests/snapshots/messages__outgoing_read.snap rename to crates/tele-tui/tests/snapshots/messages__outgoing_read.snap diff --git a/tests/snapshots/messages__outgoing_sent.snap b/crates/tele-tui/tests/snapshots/messages__outgoing_sent.snap similarity index 100% rename from tests/snapshots/messages__outgoing_sent.snap rename to crates/tele-tui/tests/snapshots/messages__outgoing_sent.snap diff --git a/tests/snapshots/messages__reply_message.snap b/crates/tele-tui/tests/snapshots/messages__reply_message.snap similarity index 100% rename from tests/snapshots/messages__reply_message.snap rename to crates/tele-tui/tests/snapshots/messages__reply_message.snap diff --git a/tests/snapshots/messages__selected_message.snap b/crates/tele-tui/tests/snapshots/messages__selected_message.snap similarity index 100% rename from tests/snapshots/messages__selected_message.snap rename to crates/tele-tui/tests/snapshots/messages__selected_message.snap diff --git a/tests/snapshots/messages__sender_grouping.snap b/crates/tele-tui/tests/snapshots/messages__sender_grouping.snap similarity index 100% rename from tests/snapshots/messages__sender_grouping.snap rename to crates/tele-tui/tests/snapshots/messages__sender_grouping.snap diff --git a/tests/snapshots/messages__single_incoming_message.snap b/crates/tele-tui/tests/snapshots/messages__single_incoming_message.snap similarity index 100% rename from tests/snapshots/messages__single_incoming_message.snap rename to crates/tele-tui/tests/snapshots/messages__single_incoming_message.snap diff --git a/tests/snapshots/messages__single_outgoing_message.snap b/crates/tele-tui/tests/snapshots/messages__single_outgoing_message.snap similarity index 100% rename from tests/snapshots/messages__single_outgoing_message.snap rename to crates/tele-tui/tests/snapshots/messages__single_outgoing_message.snap diff --git a/tests/snapshots/messages__single_reaction.snap b/crates/tele-tui/tests/snapshots/messages__single_reaction.snap similarity index 100% rename from tests/snapshots/messages__single_reaction.snap rename to crates/tele-tui/tests/snapshots/messages__single_reaction.snap diff --git a/tests/snapshots/modals__delete_confirmation_modal.snap b/crates/tele-tui/tests/snapshots/modals__delete_confirmation_modal.snap similarity index 100% rename from tests/snapshots/modals__delete_confirmation_modal.snap rename to crates/tele-tui/tests/snapshots/modals__delete_confirmation_modal.snap diff --git a/tests/snapshots/modals__emoji_picker_default.snap b/crates/tele-tui/tests/snapshots/modals__emoji_picker_default.snap similarity index 100% rename from tests/snapshots/modals__emoji_picker_default.snap rename to crates/tele-tui/tests/snapshots/modals__emoji_picker_default.snap diff --git a/tests/snapshots/modals__emoji_picker_with_selection.snap b/crates/tele-tui/tests/snapshots/modals__emoji_picker_with_selection.snap similarity index 100% rename from tests/snapshots/modals__emoji_picker_with_selection.snap rename to crates/tele-tui/tests/snapshots/modals__emoji_picker_with_selection.snap diff --git a/tests/snapshots/modals__forward_mode.snap b/crates/tele-tui/tests/snapshots/modals__forward_mode.snap similarity index 100% rename from tests/snapshots/modals__forward_mode.snap rename to crates/tele-tui/tests/snapshots/modals__forward_mode.snap diff --git a/tests/snapshots/modals__pinned_message.snap b/crates/tele-tui/tests/snapshots/modals__pinned_message.snap similarity index 100% rename from tests/snapshots/modals__pinned_message.snap rename to crates/tele-tui/tests/snapshots/modals__pinned_message.snap diff --git a/tests/snapshots/modals__profile_group_chat.snap b/crates/tele-tui/tests/snapshots/modals__profile_group_chat.snap similarity index 100% rename from tests/snapshots/modals__profile_group_chat.snap rename to crates/tele-tui/tests/snapshots/modals__profile_group_chat.snap diff --git a/tests/snapshots/modals__profile_personal_chat.snap b/crates/tele-tui/tests/snapshots/modals__profile_personal_chat.snap similarity index 100% rename from tests/snapshots/modals__profile_personal_chat.snap rename to crates/tele-tui/tests/snapshots/modals__profile_personal_chat.snap diff --git a/tests/snapshots/modals__search_in_chat.snap b/crates/tele-tui/tests/snapshots/modals__search_in_chat.snap similarity index 100% rename from tests/snapshots/modals__search_in_chat.snap rename to crates/tele-tui/tests/snapshots/modals__search_in_chat.snap diff --git a/tests/snapshots/screens__auth_screen_code.snap b/crates/tele-tui/tests/snapshots/screens__auth_screen_code.snap similarity index 100% rename from tests/snapshots/screens__auth_screen_code.snap rename to crates/tele-tui/tests/snapshots/screens__auth_screen_code.snap diff --git a/tests/snapshots/screens__auth_screen_password.snap b/crates/tele-tui/tests/snapshots/screens__auth_screen_password.snap similarity index 100% rename from tests/snapshots/screens__auth_screen_password.snap rename to crates/tele-tui/tests/snapshots/screens__auth_screen_password.snap diff --git a/tests/snapshots/screens__auth_screen_phone.snap b/crates/tele-tui/tests/snapshots/screens__auth_screen_phone.snap similarity index 100% rename from tests/snapshots/screens__auth_screen_phone.snap rename to crates/tele-tui/tests/snapshots/screens__auth_screen_phone.snap diff --git a/tests/snapshots/screens__loading_screen_default.snap b/crates/tele-tui/tests/snapshots/screens__loading_screen_default.snap similarity index 100% rename from tests/snapshots/screens__loading_screen_default.snap rename to crates/tele-tui/tests/snapshots/screens__loading_screen_default.snap diff --git a/tests/snapshots/screens__loading_screen_with_status.snap b/crates/tele-tui/tests/snapshots/screens__loading_screen_with_status.snap similarity index 100% rename from tests/snapshots/screens__loading_screen_with_status.snap rename to crates/tele-tui/tests/snapshots/screens__loading_screen_with_status.snap diff --git a/tests/snapshots/screens__main_screen_account_switcher_overlay.snap b/crates/tele-tui/tests/snapshots/screens__main_screen_account_switcher_overlay.snap similarity index 100% rename from tests/snapshots/screens__main_screen_account_switcher_overlay.snap rename to crates/tele-tui/tests/snapshots/screens__main_screen_account_switcher_overlay.snap diff --git a/tests/snapshots/screens__main_screen_chat_list_loaded.snap b/crates/tele-tui/tests/snapshots/screens__main_screen_chat_list_loaded.snap similarity index 100% rename from tests/snapshots/screens__main_screen_chat_list_loaded.snap rename to crates/tele-tui/tests/snapshots/screens__main_screen_chat_list_loaded.snap diff --git a/tests/snapshots/screens__main_screen_chat_open_narrow_valid.snap b/crates/tele-tui/tests/snapshots/screens__main_screen_chat_open_narrow_valid.snap similarity index 100% rename from tests/snapshots/screens__main_screen_chat_open_narrow_valid.snap rename to crates/tele-tui/tests/snapshots/screens__main_screen_chat_open_narrow_valid.snap diff --git a/tests/snapshots/screens__main_screen_chat_open_with_messages.snap b/crates/tele-tui/tests/snapshots/screens__main_screen_chat_open_with_messages.snap similarity index 100% rename from tests/snapshots/screens__main_screen_chat_open_with_messages.snap rename to crates/tele-tui/tests/snapshots/screens__main_screen_chat_open_with_messages.snap diff --git a/tests/snapshots/screens__main_screen_empty.snap b/crates/tele-tui/tests/snapshots/screens__main_screen_empty.snap similarity index 100% rename from tests/snapshots/screens__main_screen_empty.snap rename to crates/tele-tui/tests/snapshots/screens__main_screen_empty.snap diff --git a/tests/snapshots/screens__main_screen_terminal_too_small.snap b/crates/tele-tui/tests/snapshots/screens__main_screen_terminal_too_small.snap similarity index 100% rename from tests/snapshots/screens__main_screen_terminal_too_small.snap rename to crates/tele-tui/tests/snapshots/screens__main_screen_terminal_too_small.snap diff --git a/tests/snapshots/style_snapshots__style_reaction_picker_selection.snap b/crates/tele-tui/tests/snapshots/style_snapshots__style_reaction_picker_selection.snap similarity index 100% rename from tests/snapshots/style_snapshots__style_reaction_picker_selection.snap rename to crates/tele-tui/tests/snapshots/style_snapshots__style_reaction_picker_selection.snap diff --git a/tests/snapshots/style_snapshots__style_selected_chat.snap b/crates/tele-tui/tests/snapshots/style_snapshots__style_selected_chat.snap similarity index 100% rename from tests/snapshots/style_snapshots__style_selected_chat.snap rename to crates/tele-tui/tests/snapshots/style_snapshots__style_selected_chat.snap diff --git a/tests/snapshots/style_snapshots__style_selected_message.snap b/crates/tele-tui/tests/snapshots/style_snapshots__style_selected_message.snap similarity index 100% rename from tests/snapshots/style_snapshots__style_selected_message.snap rename to crates/tele-tui/tests/snapshots/style_snapshots__style_selected_message.snap diff --git a/tests/style_snapshots.rs b/crates/tele-tui/tests/style_snapshots.rs similarity index 100% rename from tests/style_snapshots.rs rename to crates/tele-tui/tests/style_snapshots.rs diff --git a/tests/vim_mode.rs b/crates/tele-tui/tests/vim_mode.rs similarity index 100% rename from tests/vim_mode.rs rename to crates/tele-tui/tests/vim_mode.rs diff --git a/docs/IOS_CORE_REUSE.md b/docs/IOS_CORE_REUSE.md new file mode 100644 index 0000000..685e5f9 --- /dev/null +++ b/docs/IOS_CORE_REUSE.md @@ -0,0 +1,28 @@ +# iOS core reuse + +Первый workspace split готовит код к будущему iOS-клиенту, но не добавляет +Swift, SwiftUI, UniFFI, C ABI или XCFramework. + +## Уже в `tele-core` + +- Typed IDs и shared domain-типы: `types`. +- TDLib client wrapper, auth/chats/messages/reactions/users/update handling. +- `TdClientConfig` и `TdCredentials`: credentials передаются явно из клиента. +- Core-neutral `IncomingMessageEvent` вместо прямой зависимости от desktop notifications. +- Pure message grouping. +- Pure account profile structs and validation. +- Reusable `FakeTdClient` and TDLib test data. + +## Остаётся TUI-only + +- `ratatui`, `crossterm`, UI state, input handling and snapshots. +- Runtime config loading, `.env`, `accounts.toml`, XDG/macOS paths and lock files. +- Desktop notifications, clipboard, URL opening, terminal images and `ffplay`. +- PTY fixture and `termwright` E2E tests. + +## Следующий этап + +1. Decide the iOS-facing API shape on top of `tele-core`. +2. Add UniFFI or a C ABI only after the Rust boundary is stable. +3. Validate TDLib linking and database paths for `aarch64-apple-ios`. +4. Keep platform delivery concerns outside `tele-core`. diff --git a/docs/PROJECT_STRUCTURE.md b/docs/PROJECT_STRUCTURE.md index be5376e..2829413 100644 --- a/docs/PROJECT_STRUCTURE.md +++ b/docs/PROJECT_STRUCTURE.md @@ -9,22 +9,28 @@ TDLib updates -> mpsc channel -> App state -> UI render User input -> input handlers -> App methods -> TdClientTrait -> TDLib API ``` -`main.rs` держит event loop: клавиатура, TDLib updates, фоновые задачи и отрисовка по `needs_redraw`. +`crates/tele-tui/src/main.rs` держит event loop: клавиатура, TDLib updates, +фоновые задачи и отрисовка по `needs_redraw`. ## Подсистемы | Путь | Назначение | |------|------------| -| `src/app/` | Центральное состояние `App`, экраны, режимы и modal state | -| `src/app/methods/` | Trait-based методы navigation/messages/compose/search/modal | -| `src/input/` | Роутинг клавиатуры и обработчики global/chat/compose/modal/search | -| `src/tdlib/` | TDLib wrapper: auth, chats, users, reactions, updates, conversion, operations | -| `src/ui/` | Отрисовка экранов, списка чатов, сообщений, footer, compose bar и модалок | -| `src/config/` | TOML config, credentials, keybindings, validation | -| `src/accounts/` | Профили, `accounts.toml`, migration, per-account lock files | -| `src/audio/` | Голосовые сообщения через `ffplay` и `VoiceCache` | -| `src/media/` | Inline images и modal viewer под feature `images` | -| `src/utils/` | Форматирование, validation, retry, TDLib log helpers | +| `crates/tele-core/src/tdlib/` | TDLib wrapper: auth, chats, users, reactions, updates, conversion, operations | +| `crates/tele-core/src/types.rs` | Shared typed IDs | +| `crates/tele-core/src/message_grouping.rs` | Pure message grouping | +| `crates/tele-core/src/accounts/` | Pure account profile types and validation | +| `crates/tele-core/src/test_support/` | Reusable `FakeTdClient` and TDLib test data | +| `crates/tele-tui/src/app/` | Центральное состояние `App`, экраны, режимы и modal state | +| `crates/tele-tui/src/app/methods/` | Trait-based методы navigation/messages/compose/search/modal | +| `crates/tele-tui/src/input/` | Роутинг клавиатуры и обработчики global/chat/compose/modal/search | +| `crates/tele-tui/src/ui/` | Отрисовка экранов, списка чатов, сообщений, footer, compose bar и модалок | +| `crates/tele-tui/src/config/` | TOML config, credentials, keybindings, validation | +| `crates/tele-tui/src/accounts/` | `accounts.toml`, migration, account data paths, per-account lock files | +| `crates/tele-tui/src/audio/` | Голосовые сообщения через `ffplay` и `VoiceCache` | +| `crates/tele-tui/src/media/` | Inline images и modal viewer под feature `images` | +| `crates/tele-tui/src/notifications.rs` | Desktop notification delivery and muted-chat syncing | +| `crates/tele-tui/src/utils/` | Форматирование, validation, retry, TDLib log helpers | ## State @@ -37,16 +43,20 @@ User input -> input handlers -> App methods -> TdClientTrait -> TDLib API - `TdClientTrait` задаёт API для приложения и тестов. - Реальный клиент живёт в `TdClient`, тесты используют `FakeTdClient`. - Updates должны фильтроваться по активному `client_id`, особенно для мультиаккаунта. +- `TdClient` не зависит от desktop notifications. Он отдаёт входящие сообщения + через `drain_incoming_message_events()`, а `tele-tui` решает, показывать ли + desktop notification. ## Тесты | Область | Где искать | |---------|------------| -| Test builders и fake TDLib | `tests/helpers/` | -| Snapshot UI | `tests/*` + `tests/snapshots/` | -| Навигация и ввод | `tests/input_navigation.rs`, `tests/vim_mode.rs`, `tests/navigation.rs` | -| Аккаунты | `tests/accounts.rs`, `tests/account_switcher.rs` | -| User journeys | `tests/e2e_smoke.rs`, `tests/e2e_user_journey.rs` | +| Core unit tests | `crates/tele-core/src/**` | +| Test builders и fake TDLib | `crates/tele-core/src/test_support/`, `crates/tele-tui/src/test_support/`, `crates/tele-tui/tests/helpers/` | +| Snapshot UI | `crates/tele-tui/tests/*` + `crates/tele-tui/tests/snapshots/` | +| Навигация и ввод | `crates/tele-tui/tests/input_navigation.rs`, `crates/tele-tui/tests/vim_mode.rs`, `crates/tele-tui/tests/navigation.rs` | +| Аккаунты | `crates/tele-tui/tests/accounts.rs`, `crates/tele-tui/tests/account_switcher.rs` | +| User journeys | `crates/tele-tui/tests/e2e_smoke.rs`, `crates/tele-tui/tests/e2e_user_journey.rs` | ## Runtime-файлы diff --git a/docs/TDLIB_INTEGRATION.md b/docs/TDLIB_INTEGRATION.md index 7d0e395..f45e004 100644 --- a/docs/TDLIB_INTEGRATION.md +++ b/docs/TDLIB_INTEGRATION.md @@ -1,6 +1,6 @@ # TDLib integration notes -Проект использует `tdlib-rs` с feature `download-tdlib`. Актуальные версии смотри в `Cargo.toml`. +Проект использует `tdlib-rs` с feature `download-tdlib`. Актуальные версии смотри в `crates/tele-core/Cargo.toml` и `crates/tele-tui/Cargo.toml`. ## Runtime @@ -23,6 +23,9 @@ UI должен показывать понятное состояние и не - Receive loop передаёт в UI пару `(client_id, Update)`. - UI применяет update только если `client_id == active_client_id`. - При переключении аккаунта pending updates старого клиента должны игнорироваться. +- `tele-core` не вызывает desktop notifications напрямую. Входящие сообщения + складываются в очередь `IncomingMessageEvent`, которую `tele-tui` drain-ит в + main loop и передаёт в `NotificationManager`. Это критично для multi-account: без фильтрации старый клиент может испортить state нового аккаунта. diff --git a/docs/superpowers/plans/2026-05-20-ios-app-roadmap.md b/docs/superpowers/plans/2026-05-20-ios-app-roadmap.md new file mode 100644 index 0000000..fd44030 --- /dev/null +++ b/docs/superpowers/plans/2026-05-20-ios-app-roadmap.md @@ -0,0 +1,142 @@ +# iOS Telegram Client Roadmap + +## Summary + +Build a full native iOS app on top of the new `tele-core` crate, keeping Telegram/TDLib behavior shared in Rust and implementing UI/platform concerns in SwiftUI. Target feature parity with the current TUI client: auth, chat list, folders, messages, send/edit/delete/reply/forward/copy, reactions, search, pinned/profile flows, photos/albums, voice playback, notifications, multi-account support, unread/muted/mentions, drafts, network/typing state. + +Architecture default: Rust `tele-core` remains the source of Telegram state and operations; add a UniFFI-based bridge crate plus a SwiftUI app. Do not port `ratatui`, terminal image rendering, `ffplay`, desktop notifications, or TUI keybindings to iOS. + +## Phases + +### Phase 0: Stabilize Current Workspace + +- Finish and commit the current split: `tele-core` + `tele-tui`. +- Confirm `tele-core` has no TUI/desktop deps: no `ratatui`, `crossterm`, `ratatui-image`, `notify-rust`, `arboard`, `open`, `ffplay`. +- Save this roadmap at `docs/superpowers/plans/2026-05-20-ios-app-roadmap.md`. +- Acceptance: + - `cargo fmt -- --check` + - `cargo check -p tele-core` + - `cargo test -p tele-core` + - `cargo check -p tele-tui --all-targets --all-features` + - `cargo test --workspace --all-features` + +### Phase 1: iOS-Facing Core API + +- Add a platform-neutral session layer in `tele-core` above `TdClientTrait`. +- Expose stable models for iOS: account, auth state, chat summary, folder, message, media, reactions, profile, draft, network state, typing state. +- Add event stream types for Swift: auth changed, chat list changed, message added/updated/deleted, reaction changed, media download progress, incoming notification candidate, network changed. +- Keep filesystem, notifications, clipboard, URL open, and audio playback out of `tele-core`. +- Acceptance: + - Core unit tests cover auth transitions, chat/message mapping, incoming event queue, folders, reactions, drafts, search results, pinned/profile data. + - Existing `tele-tui` behavior remains unchanged. + +### Phase 2: UniFFI Bridge + +- Add `crates/tele-ios-ffi` using UniFFI. +- Export a small async-safe facade: + - `create_session(config) -> SessionHandle` + - `poll_events() -> Vec` + - auth methods: phone/code/password + - chat methods: load chats/folders/history/search/open profile + - message methods: send/edit/delete/reply/forward/react/copy payload + - media methods: download photo/download voice +- Generate Swift bindings and wire Rust build outputs into an iOS-consumable XCFramework. +- Acceptance: + - Swift sample test can create a fake session, receive events, load chats, open a chat, send a message, react, and search. + - Real TDLib linking is validated for iOS simulator and device or documented as blocked with exact linker error. + +### Phase 3: iOS App Shell + +- Add native app under `apps/ios/TeleTuiIOS`. +- Use SwiftUI + MVVM: + - `SessionStore` + - `AuthViewModel` + - `ChatListViewModel` + - `ChatViewModel` + - `ProfileViewModel` + - `MediaViewModel` +- Implement auth screens, loading/error state, tab-free chat list, folder selector, chat screen, compose bar, profile sheet, settings/account switcher shell. +- Store credentials and account metadata with Keychain + Application Support paths, not TUI config files. +- Acceptance: + - App boots on simulator using fake bridge. + - Auth flow screens match all `AuthState` variants. + - Chat list and chat detail render deterministic fake data. + +### Phase 4: Messaging Feature Parity + +- Implement chat list features: folders, search, unread count, mentions, muted state, pinned indicator, drafts, network footer/status equivalent. +- Implement message features: markdown rendering, incoming/outgoing styling, date separators, sender grouping, albums, reply/forward context, edited/read state. +- Implement actions: send, edit, delete confirmation, reply, forward, reactions picker, pinned messages, profile open/leave flow, copy message text via `UIPasteboard`. +- Acceptance: + - XCTest/UI tests cover the same user journeys as TUI: launch, open chat, send, receive incoming, switch chats, edit, reply, search, reactions, delete confirmation. + - Snapshot tests cover chat list, message list, modals/sheets, auth screens, profile, and media placeholders. + +### Phase 5: iOS Media, Notifications, and Accounts + +- Replace desktop-only behavior with iOS-native services: + - notifications: `UNUserNotificationCenter` + - URL open: `UIApplication.open` + - clipboard: `UIPasteboard` + - voice playback: `AVAudioPlayer` or `AVPlayer` + - photo viewing: SwiftUI image viewer with zoom/pan +- Implement photo download/cache, albums, fullscreen viewer, voice download/cache/play/seek. +- Implement multi-account switcher with per-account TDLib db paths and app-level account lock policy suitable for iOS. +- Acceptance: + - Local notifications respect muted chats and mention-only settings. + - Voice messages play, pause, seek, and cache. + - Photos/albums open fullscreen and reuse cache. + - Account switching does not mix old TDLib events into the active account. + +### Phase 6: Real Device Hardening + +- Run against real Telegram credentials on simulator and device. +- Add background/foreground lifecycle handling: reconnect, suspend polling, resume events, close sessions safely. +- Add privacy and permission flows: notifications, local network/file storage if needed. +- Add crash logging and structured Rust/Swift logs. +- Optimize large chats: pagination, image memory pressure, voice cache limits, event batching. +- Acceptance: + - 30-minute manual smoke on real device: auth, load chats, open multiple chats, send/edit/delete/reply/forward/react, receive notifications, view photos, play voice, switch accounts. + - No mixed-account updates after rapid account switch. + - No UI freeze during chat history loads or media downloads. + +### Phase 7: Release Readiness + +- Add CI jobs for Rust core, FFI generation, Swift build, simulator tests, and packaging. +- Add TestFlight configuration, app icons, launch screen, entitlements, privacy manifest, notification capability, and TDLib packaging docs. +- Document support matrix: minimum iOS version, device architectures, TDLib version, known limitations. +- Acceptance: + - Clean CI from empty checkout. + - TestFlight build installs and launches. + - Release checklist in docs includes credentials setup, TDLib build, signing, and rollback steps. + +## Key Interface Decisions + +- iOS UI is native SwiftUI, not a terminal/TUI port. +- Rust/Swift boundary is UniFFI unless TDLib iOS linking forces a lower-level C ABI. +- `tele-core` owns Telegram semantics and emits events; Swift owns presentation, storage permissions, notifications, clipboard, URL opening, and media playback. +- `tele-tui` remains a first-class crate and must keep passing its existing tests after every core change. + +## Test Plan + +- Rust: + - `cargo fmt -- --check` + - `cargo clippy --workspace --all-targets --all-features -- -D warnings` + - `cargo test --workspace --all-features` + - `cargo tree -p tele-core | rg "ratatui|crossterm|ratatui-image|notify-rust|arboard|open|ffplay"` must return no matches. +- FFI: + - Generated Swift bindings compile. + - Fake-session Swift tests cover all exported methods and event variants. +- iOS: + - XCTest unit tests for view models. + - SwiftUI snapshot tests for auth, chat list, chat, message actions, profile, media. + - UI tests for auth mock flow, open chat, send, edit, reply, forward, react, search, account switch. +- Manual: + - Simulator fake-data smoke each phase. + - Real-device TDLib smoke before Phase 6 completion. + +## Assumptions + +- "Полноценное iOS-приложение" means practical feature parity with current `tele-tui`, not a minimal chat reader. +- iOS implementation should prioritize native UX over preserving Vim/TUI keybindings. +- iOS credentials/account storage should use iOS-native secure storage and app sandbox paths. +- The first saved plan file should be `docs/superpowers/plans/2026-05-20-ios-app-roadmap.md`.