diff --git a/sharing/linux/tui/BUILD b/sharing/linux/tui/BUILD index 0c6fb981..cda98e14 100644 --- a/sharing/linux/tui/BUILD +++ b/sharing/linux/tui/BUILD @@ -1,4 +1,5 @@ load("@rules_cc//cc:cc_binary.bzl", "cc_binary") +load("@rules_cc//cc:cc_library.bzl", "cc_library") load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands") @@ -22,6 +23,49 @@ cc_binary( srcs = [ "main.cc", ], + deps = [ + ":app", + ] +) + +cc_library( + name = "app", + srcs = [ + "app.cc", + ], + hdrs = [ + "app.h", + ], + deps = [ + ":file_picker", + ":page", + "//sharing/linux/tui/ui:home_screen", + "@ftxui//:ftxui", + ], +) + +cc_library( + name = "page", + hdrs = [ + "page.h", + ], +) + +cc_library( + name = "file_picker", + srcs = [ + "file_picker.cc", + ], + hdrs = [ + "file_picker.h", + ], +) + +cc_library( + name = "palette", + hdrs = [ + "palette.h", + ], deps = [ "@ftxui//:ftxui", ] diff --git a/sharing/linux/tui/app.cc b/sharing/linux/tui/app.cc new file mode 100644 index 00000000..8d25f399 --- /dev/null +++ b/sharing/linux/tui/app.cc @@ -0,0 +1,59 @@ +#include "sharing/linux/tui/app.h" + +#include + +#include "ftxui/component/component.hpp" +#include "sharing/linux/tui/ui/home_screen.h" + +namespace nearby::sharing::linux_tui { +namespace { + +std::string GetHostname() { + char hostname[256] = {}; + gethostname(hostname, sizeof(hostname)); + return hostname; +} + +} // namespace + +TuiApp::TuiApp() : screen_(ftxui::ScreenInteractive::Fullscreen()) { + hostname_ = GetHostname(); + screen_.TrackMouse(true); +} + +int TuiApp::Run() { + auto component = HomeScreen({ + .hostname = hostname_, + .current_page = ¤t_page_, + .selected_file = &selected_file_, + .file_picker = &file_picker_, + .on_file_selected = + [this](std::string path) { + selected_file_ = path; + current_page_ = Page::Sharing; + }, + }); + + auto app = ftxui::CatchEvent( + component, [this](ftxui::Event event) { return HandleEvent(event); }); + + screen_.Loop(app); + return 0; +} + +bool TuiApp::HandleEvent(ftxui::Event event) { + if (event == ftxui::Event::Character('q') || event == ftxui::Event::Escape) { + screen_.ExitLoopClosure()(); + return true; + } + + if (event == ftxui::Event::Backspace && current_page_ == Page::Sharing) { + current_page_ = Page::FilePicker; + selected_file_.clear(); + return true; + } + + return false; +} + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/app.h b/sharing/linux/tui/app.h new file mode 100644 index 00000000..202b61e2 --- /dev/null +++ b/sharing/linux/tui/app.h @@ -0,0 +1,27 @@ +#pragma once + +#include "ftxui/component/screen_interactive.hpp" +#include "sharing/linux/tui/file_picker.h" +#include "sharing/linux/tui/page.h" + +#include + +namespace nearby::sharing::linux_tui { + +class TuiApp { + public: + TuiApp(); + + int Run(); + + private: + bool HandleEvent(ftxui::Event event); + + ftxui::ScreenInteractive screen_; + ZenityFilePicker file_picker_; + Page current_page_ = Page::FilePicker; + std::string hostname_; + std::string selected_file_; +}; + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/components/BUILD b/sharing/linux/tui/components/BUILD new file mode 100644 index 00000000..0e6570fd --- /dev/null +++ b/sharing/linux/tui/components/BUILD @@ -0,0 +1,30 @@ +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +cc_library( + name = "file_icon", + srcs = [ + "file_icon.cc", + ], + hdrs = [ + "file_icon.h", + ], + deps = [ + "@ftxui//:ftxui", + ], +) + +cc_library( + name = "file_picker_card", + srcs = [ + "file_picker_card.cc", + ], + hdrs = [ + "file_picker_card.h", + ], + deps = [ + ":file_icon", + "//sharing/linux/tui:file_picker", + "//sharing/linux/tui:palette", + "@ftxui//:ftxui", + ], +) diff --git a/sharing/linux/tui/components/brand.cc b/sharing/linux/tui/components/brand.cc new file mode 100644 index 00000000..40a66c93 --- /dev/null +++ b/sharing/linux/tui/components/brand.cc @@ -0,0 +1,15 @@ +#include "sharing/linux/tui/components/brand.h" + +namespace nearby::sharing::linux_tui { +using namespace ftxui; + +Element Brand() { + return vbox({ + text(" ___ _ _ ___ _ "), + text(" / _ \\ _ _(_)__| |__ / __| |_ __ _ _ _ ___ "), + text(" | (_) | || | / _| / / \\__ \\ ' \\/ _` | '_/ -_)"), + text(" \\__\\_\\\\_,_|_\\__|_\\_\\ |___/_||_\\__,_|_| \\___|"), + text(" "), + }); +} +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/components/brand.h b/sharing/linux/tui/components/brand.h new file mode 100644 index 00000000..0536bc8e --- /dev/null +++ b/sharing/linux/tui/components/brand.h @@ -0,0 +1,9 @@ +#pragma once + +#include "ftxui/dom/elements.hpp" + +namespace nearby::sharing::linux_tui { + +ftxui::Element Brand(); + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/components/file_icon.cc b/sharing/linux/tui/components/file_icon.cc new file mode 100644 index 00000000..c301e1e6 --- /dev/null +++ b/sharing/linux/tui/components/file_icon.cc @@ -0,0 +1,29 @@ +#include "sharing/linux/tui/components/file_icon.h" + +namespace nearby::sharing::linux_tui { + +ftxui::Element FileIcon(FileIconSize size) { + if (size == FileIconSize::Small) { + return ftxui::vbox({ + ftxui::text(" ______ ") | ftxui::center, + ftxui::text(" / | | ") | ftxui::center, + ftxui::text(" /__| | ") | ftxui::center, + ftxui::text(" | ----- | ") | ftxui::center, + ftxui::text(" | ----- | ") | ftxui::center, + ftxui::text(" |_______| ") | ftxui::center, + }); + } + + return ftxui::vbox({ + ftxui::text(" __________ ") | ftxui::center, + ftxui::text(" / | | ") | ftxui::center, + ftxui::text(" /__| | ") | ftxui::center, + ftxui::text(" | --------- | ") | ftxui::center, + ftxui::text(" | --------- | ") | ftxui::center, + ftxui::text(" | --------- | ") | ftxui::center, + ftxui::text(" | --------- | ") | ftxui::center, + ftxui::text(" |___________| ") | ftxui::center, + }); +} + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/components/file_icon.h b/sharing/linux/tui/components/file_icon.h new file mode 100644 index 00000000..24d9a5fb --- /dev/null +++ b/sharing/linux/tui/components/file_icon.h @@ -0,0 +1,14 @@ +#pragma once + +#include "ftxui/dom/elements.hpp" + +namespace nearby::sharing::linux_tui { + +enum class FileIconSize { + Large, + Small, +}; + +ftxui::Element FileIcon(FileIconSize size); + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/components/file_picker_card.cc b/sharing/linux/tui/components/file_picker_card.cc new file mode 100644 index 00000000..cb9a93cd --- /dev/null +++ b/sharing/linux/tui/components/file_picker_card.cc @@ -0,0 +1,69 @@ +#include "sharing/linux/tui/components/file_picker_card.h" + +#include + +#include "ftxui/dom/elements.hpp" +#include "ftxui/component/event.hpp" +#include "ftxui/screen/box.hpp" +#include "sharing/linux/tui/components/file_icon.h" +#include "sharing/linux/tui/palette.h" + +namespace nearby::sharing::linux_tui { + +ftxui::Component FilePickerCard(FilePickerCardOptions options) { + auto picker_box = std::make_shared(); + auto hovered = std::make_shared(false); + + auto card = ftxui::Renderer([picker_box, hovered] { + auto picker_card = + ftxui::vbox({ + FileIcon(FileIconSize::Large) | ftxui::color(Palette::secondary), + ftxui::separatorEmpty(), + ftxui::text("Select file to share") | ftxui::bold | ftxui::center, + }) | + ftxui::borderStyled(*hovered ? Palette::primary : Palette::secondary) | + ftxui::size(ftxui::WIDTH, ftxui::GREATER_THAN, 33) | + ftxui::size(ftxui::HEIGHT, ftxui::EQUAL, 13) | + ftxui::reflect(*picker_box); + + return ftxui::vbox({ + ftxui::filler(), + ftxui::hbox({ + ftxui::filler(), + picker_card, + ftxui::filler(), + }), + ftxui::filler(), + }) | + ftxui::flex; + }); + + return ftxui::CatchEvent( + card, [picker_box, hovered, options](ftxui::Event event) { + if (!event.is_mouse()) { + return false; + } + + auto mouse = event.mouse(); + bool inside_picker = + mouse.x >= picker_box->x_min && mouse.x <= picker_box->x_max && + mouse.y >= picker_box->y_min && mouse.y <= picker_box->y_max; + + *hovered = inside_picker; + + if (!inside_picker || mouse.button != ftxui::Mouse::Left || + mouse.motion != ftxui::Mouse::Pressed || + options.file_picker == nullptr) { + return false; + } + + std::string path = options.file_picker->PickFile(); + if (!path.empty() && options.on_file_selected) { + options.on_file_selected(path); + } + + return true; + }); +} + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/components/file_picker_card.h b/sharing/linux/tui/components/file_picker_card.h new file mode 100644 index 00000000..e5be18aa --- /dev/null +++ b/sharing/linux/tui/components/file_picker_card.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +#include "ftxui/component/component.hpp" +#include "sharing/linux/tui/file_picker.h" + +namespace nearby::sharing::linux_tui { + +struct FilePickerCardOptions { + FilePicker* file_picker = nullptr; + std::function on_file_selected; +}; + +ftxui::Component FilePickerCard(FilePickerCardOptions options); + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/file_picker.cc b/sharing/linux/tui/file_picker.cc new file mode 100644 index 00000000..0bf60574 --- /dev/null +++ b/sharing/linux/tui/file_picker.cc @@ -0,0 +1,30 @@ +#include "sharing/linux/tui/file_picker.h" + +#include +#include + +namespace nearby::sharing::linux_tui { + +std::string ZenityFilePicker::PickFile() { + FILE* pipe = popen("zenity --file-selection 2>/dev/null", "r"); + if (pipe == nullptr) { + return {}; + } + + char buffer[4096]; + std::string result; + + if (fgets(buffer, sizeof(buffer), pipe) != nullptr) { + result = buffer; + } + + pclose(pipe); + + if (!result.empty() && result.back() == '\n') { + result.pop_back(); + } + + return result; +} + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/file_picker.h b/sharing/linux/tui/file_picker.h new file mode 100644 index 00000000..597f4577 --- /dev/null +++ b/sharing/linux/tui/file_picker.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace nearby::sharing::linux_tui { + +class FilePicker { + public: + virtual ~FilePicker() = default; + + virtual std::string PickFile() = 0; +}; + +class ZenityFilePicker final : public FilePicker { + public: + std::string PickFile() override; +}; + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/main.cc b/sharing/linux/tui/main.cc index 60aa0d93..788d8c11 100644 --- a/sharing/linux/tui/main.cc +++ b/sharing/linux/tui/main.cc @@ -1,185 +1,6 @@ -#include - -#include -#include -#include -#include - -#include - -using namespace ftxui; - -std::string OpenZenityFilePicker() { - FILE* pipe = popen("zenity --file-selection 2>/dev/null", "r"); - if (!pipe) { - return {}; - } - - char buffer[4096]; - std::string result; - - if (fgets(buffer, sizeof(buffer), pipe) != nullptr) { - result = buffer; - } - - pclose(pipe); - - // Remove trailing newline. - if (!result.empty() && result.back() == '\n') { - result.pop_back(); - } - - return result; -} - -enum class Page { - FilePicker, - FileSelected, -}; +#include "sharing/linux/tui/app.h" int main() { - auto screen = ScreenInteractive::Fullscreen(); - screen.TrackMouse(true); - - Page current_screen = Page::FilePicker; - auto title_color = Color::RGB(0xab, 0xda, 0xc4); - - // clang-format off - auto title = vbox({ - text("┏━┓╻ ╻╻┏━╸╻┏ ┏━┓╻ ╻┏━┓┏━┓┏━╸") | color(title_color), - text("┃┓┃┃ ┃┃┃ ┣┻┓ ┗━┓┣━┫┣━┫┣┳┛┣╸ ") | color(title_color), - text("┗┻┛┗━┛╹┗━╸╹ ╹ ┗━┛╹ ╹╹ ╹╹┗╸┗━╸") | color(title_color), - }); - - auto file_icon = vbox({ - text(" __________ ") | center | color(title_color), - text(" / | | ") | center | color(title_color), - text(" /__| | ") | center | color(title_color), - text(" | --------- | ") | center | color(title_color), - text(" | --------- | ") | center | color(title_color), - text(" | --------- | ") | center | color(title_color), - text(" | --------- | ") | center | color(title_color), - text(" |___________| ") | center | color(title_color), - }); - // clang-format on - - char hostname[256] = {}; - gethostname(hostname, sizeof(hostname)); - - bool picker_hovered = false; - std::string selected_file; - - Box picker_box; - auto RenderFilePickerScreen = [&] { - auto picker_card = - vbox({ - file_icon, - separatorEmpty(), - text("Click to open file picker") | bold | center, - separatorEmpty(), - text("No file selected") | dim | center, - }) | - borderStyled(picker_hovered ? Color::White : title_color) | - size(WIDTH, GREATER_THAN, 38) | size(HEIGHT, EQUAL, 15) | - reflect(picker_box); - - return vbox({ - filler(), - hbox({ - filler(), - picker_card, - filler(), - }), - filler(), - }) | - flex; - }; - - auto RenderFileSelectedScreen = [&] { - return vbox({ - text("File selected") | bold | center | color(title_color), - separator(), - paragraph(selected_file) | center, - separatorEmpty(), - text("Press Backspace to choose another file") | dim | center, - }) | - borderStyled(title_color) | flex; - }; - - auto component = Renderer([&] { - auto visible_as_box = - window(text(" Visible as "), - vbox({ - text(""), - text(std::string(hostname)) | bold | center, - text(""), - })) | - size(WIDTH, GREATER_THAN, 24) | size(HEIGHT, EQUAL, 5); - auto main_panel = current_screen == Page::FilePicker - ? RenderFilePickerScreen() - : RenderFileSelectedScreen(); - auto picker_card = - vbox({ - file_icon, - separatorEmpty(), - text("Click to open file picker") | bold | center, - separatorEmpty(), - paragraph(selected_file.empty() ? "No file selected" - : selected_file) | - dim | center, - }) | - borderStyled(picker_hovered ? Color::White : title_color) | - size(WIDTH, GREATER_THAN, 38) | size(HEIGHT, EQUAL, 15) | - reflect(picker_box); - - return vbox({ - title, - separator(), - hbox({ - vbox({ - visible_as_box, - }), - - main_panel | flex, - }) | flex, - }) | - size(WIDTH, GREATER_THAN, 80) | size(HEIGHT, GREATER_THAN, 24); - }); - - auto app = CatchEvent(component, [&](Event event) { - if (event == Event::Character('q') || event == Event::Escape) { - screen.ExitLoopClosure()(); - return true; - } - - if (!event.is_mouse()) { - return false; - } - - auto mouse = event.mouse(); - - bool inside_picker = - mouse.x >= picker_box.x_min && mouse.x <= picker_box.x_max && - mouse.y >= picker_box.y_min && mouse.y <= picker_box.y_max; - - picker_hovered = inside_picker; - - if (inside_picker && mouse.button == Mouse::Left && - mouse.motion == Mouse::Pressed) { - std::string path = OpenZenityFilePicker(); - - if (!path.empty()) { - selected_file = path; - current_screen = Page::FileSelected; - } - - return true; - } - - return false; - }); - - screen.Loop(app); - - return 0; + nearby::sharing::linux_tui::TuiApp app; + return app.Run(); } diff --git a/sharing/linux/tui/page.h b/sharing/linux/tui/page.h new file mode 100644 index 00000000..eeeb381e --- /dev/null +++ b/sharing/linux/tui/page.h @@ -0,0 +1,10 @@ +#pragma once + +namespace nearby::sharing::linux_tui { + +enum class Page { + FilePicker, + Sharing, +}; + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/palette.h b/sharing/linux/tui/palette.h new file mode 100644 index 00000000..2a6607c6 --- /dev/null +++ b/sharing/linux/tui/palette.h @@ -0,0 +1,24 @@ +#pragma once + +#include "ftxui/screen/color.hpp" + +namespace nearby::sharing::linux_tui { + +struct Palette { + inline static const ftxui::Color primary = + ftxui::Color::RGB(0xF1, 0xF9, 0xF6); // Off-white mint tint + + inline static const ftxui::Color secondary = + ftxui::Color::RGB(0x8A, 0xAF, 0xA4); // Muted sage gray + + inline static const ftxui::Color accent = + ftxui::Color::RGB(0xA3, 0xD9, 0xC9); // Original Mint Leaf + + inline static const ftxui::Color active = + ftxui::Color::RGB(0x23, 0x3D, 0x34); // Deep forest green tint + + inline static const ftxui::Color base = + ftxui::Color::RGB(0x12, 0x1D, 0x1A); // Near-black deep mint/charcoal +}; + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/ui/BUILD b/sharing/linux/tui/ui/BUILD new file mode 100644 index 00000000..ec539725 --- /dev/null +++ b/sharing/linux/tui/ui/BUILD @@ -0,0 +1,63 @@ +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +cc_library( + name = "home_header", + srcs = [ + "home_header.cc", + ], + hdrs = [ + "home_header.h", + ], + deps = [ + "@ftxui//:ftxui", + ], +) + +cc_library( + name = "sidebar", + srcs = [ + "sidebar.cc", + ], + hdrs = [ + "sidebar.h", + ], + deps = [ + "//sharing/linux/tui:palette", + "//sharing/linux/tui/components:file_icon", + "@ftxui//:ftxui", + ], +) + +cc_library( + name = "file_selected_screen", + srcs = [ + "file_selected_screen.cc", + ], + hdrs = [ + "file_selected_screen.h", + ], + deps = [ + "//sharing/linux/tui:palette", + "@ftxui//:ftxui", + ], +) + +cc_library( + name = "home_screen", + srcs = [ + "home_screen.cc", + ], + hdrs = [ + "home_screen.h", + ], + deps = [ + ":file_selected_screen", + ":home_header", + ":sidebar", + "//sharing/linux/tui:file_picker", + "//sharing/linux/tui:page", + "//sharing/linux/tui:palette", + "//sharing/linux/tui/components:file_picker_card", + "@ftxui//:ftxui", + ], +) diff --git a/sharing/linux/tui/ui/file_selected_screen.cc b/sharing/linux/tui/ui/file_selected_screen.cc new file mode 100644 index 00000000..9010109a --- /dev/null +++ b/sharing/linux/tui/ui/file_selected_screen.cc @@ -0,0 +1,20 @@ +#include "sharing/linux/tui/ui/file_selected_screen.h" + +#include "sharing/linux/tui/palette.h" + +namespace nearby::sharing::linux_tui { + +ftxui::Element FileSelectedScreen(const std::string& selected_file) { + return ftxui::vbox({ + ftxui::text("File selected") | ftxui::bold | ftxui::center | + ftxui::color(Palette::primary), + ftxui::separator(), + ftxui::paragraph(selected_file) | ftxui::center, + ftxui::separatorEmpty(), + ftxui::text("Press Backspace to choose another file") | + ftxui::dim | ftxui::center, + }) | + ftxui::borderStyled(Palette::primary) | ftxui::flex; +} + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/ui/file_selected_screen.h b/sharing/linux/tui/ui/file_selected_screen.h new file mode 100644 index 00000000..22f42113 --- /dev/null +++ b/sharing/linux/tui/ui/file_selected_screen.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include "ftxui/dom/elements.hpp" + +namespace nearby::sharing::linux_tui { + +ftxui::Element FileSelectedScreen(const std::string& selected_file); + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/ui/home_header.cc b/sharing/linux/tui/ui/home_header.cc new file mode 100644 index 00000000..5fef2503 --- /dev/null +++ b/sharing/linux/tui/ui/home_header.cc @@ -0,0 +1,11 @@ +#include "sharing/linux/tui/ui/home_header.h" +#include "sharing/linux/tui/components/brand.h" + +namespace nearby::sharing::linux_tui { +using namespace ftxui; + +Element HomeHeader() { + return Brand(); +} + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/ui/home_header.h b/sharing/linux/tui/ui/home_header.h new file mode 100644 index 00000000..81dbff75 --- /dev/null +++ b/sharing/linux/tui/ui/home_header.h @@ -0,0 +1,9 @@ +#pragma once + +#include "ftxui/dom/elements.hpp" + +namespace nearby::sharing::linux_tui { + +ftxui::Element HomeHeader(); + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/ui/home_screen.cc b/sharing/linux/tui/ui/home_screen.cc new file mode 100644 index 00000000..b59dc7b9 --- /dev/null +++ b/sharing/linux/tui/ui/home_screen.cc @@ -0,0 +1,43 @@ +#include "sharing/linux/tui/ui/home_screen.h" + +#include "ftxui/dom/elements.hpp" +#include "sharing/linux/tui/components/file_picker_card.h" +#include "sharing/linux/tui/palette.h" +#include "sharing/linux/tui/ui/file_selected_screen.h" +#include "sharing/linux/tui/ui/home_header.h" +#include "sharing/linux/tui/ui/sidebar.h" + +namespace nearby::sharing::linux_tui { + +ftxui::Component HomeScreen(HomeScreenOptions options) { + auto file_picker_card = + FilePickerCard({.file_picker = options.file_picker, + .on_file_selected = options.on_file_selected}); + + return ftxui::Renderer(file_picker_card, [file_picker_card, options] { + const std::string selected_file = + options.selected_file == nullptr ? "" : *options.selected_file; + const Page current_page = options.current_page == nullptr + ? Page::FilePicker + : *options.current_page; + + auto main_panel = current_page == Page::FilePicker + ? file_picker_card->Render() + : FileSelectedScreen(selected_file); + + return ftxui::vbox({ + HomeHeader() | ftxui::color(Palette::accent), + ftxui::separator(), + ftxui::hbox({ + Sidebar({.hostname = options.hostname, + .selected_file = selected_file}), + main_panel | ftxui::flex, + }) | ftxui::flex, + }) | + ftxui::bgcolor(Palette::base) | + ftxui::size(ftxui::WIDTH, ftxui::GREATER_THAN, 80) | + ftxui::size(ftxui::HEIGHT, ftxui::GREATER_THAN, 24); + }); +} + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/ui/home_screen.h b/sharing/linux/tui/ui/home_screen.h new file mode 100644 index 00000000..a0b243ef --- /dev/null +++ b/sharing/linux/tui/ui/home_screen.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#include "ftxui/component/component.hpp" +#include "sharing/linux/tui/file_picker.h" +#include "sharing/linux/tui/page.h" + +namespace nearby::sharing::linux_tui { + +struct HomeScreenOptions { + std::string hostname; + const Page* current_page = nullptr; + const std::string* selected_file = nullptr; + FilePicker* file_picker = nullptr; + std::function on_file_selected; +}; + +ftxui::Component HomeScreen(HomeScreenOptions options); + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/ui/sidebar.cc b/sharing/linux/tui/ui/sidebar.cc new file mode 100644 index 00000000..99ab7183 --- /dev/null +++ b/sharing/linux/tui/ui/sidebar.cc @@ -0,0 +1,42 @@ +#include "sharing/linux/tui/ui/sidebar.h" + +#include "sharing/linux/tui/components/file_icon.h" +#include "sharing/linux/tui/palette.h" + +namespace nearby::sharing::linux_tui { +using namespace ftxui; + +Element Sidebar(const SidebarState& state) { + auto visible_as_box = + window( + text(" Visible as "), + vbox({ + text(""), + text(state.hostname) | bold | center, + text(""), + })) | + size(WIDTH, GREATER_THAN, 24) | + size(HEIGHT, EQUAL, 5); + + if (state.selected_file.empty()) { + return vbox({ + visible_as_box, + filler(), + }); + } + + return vbox({ + visible_as_box, + filler(), + window( + text(" Selected to share ") | center, + vbox({ + FileIcon(FileIconSize::Small) | color(Palette::accent), + text(""), + paragraph(state.selected_file) | dim, + })) | + size(WIDTH, EQUAL, 24), + }); +} + +} // namespace nearby::sharing::linux_tui diff --git a/sharing/linux/tui/ui/sidebar.h b/sharing/linux/tui/ui/sidebar.h new file mode 100644 index 00000000..60a4b715 --- /dev/null +++ b/sharing/linux/tui/ui/sidebar.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "ftxui/dom/elements.hpp" + +namespace nearby::sharing::linux_tui { + +struct SidebarState { + std::string hostname; + std::string selected_file; +}; + +ftxui::Element Sidebar(const SidebarState& state); + +} // namespace nearby::sharing::linux_tui