Public Access
Enter on a picture shows it: shrunk to fit the screen, or at its own size with Enter again and the arrows to move. Dithered to the screen's 256 colours; a colour the screen has exactly is left alone, so screenshots are shown as they are. The picture is decoded once, straight into the screen's buffer, and kept there (App::retainsContent): no copy in memory. Decoding runs on the storage task, so the keys keep working and a 12 megapixel photograph appears as it comes instead of tripping the watchdog. PNG, BMP and GIF are read by decoders of our own, host-tested against files made by Pillow; the PNG one needs 32 KB where the display library's needed 44 KB in one block, which the device often doesn't have. JPEG uses the library's TJpgDec. Also corrects two sentences that still gave 16 KB as the editing limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
83 lines
2.8 KiB
C++
83 lines
2.8 KiB
C++
#pragma once
|
|
|
|
#include <FS.h>
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "apps/image_pane.h"
|
|
#include "dialog_model.h"
|
|
#include "key_help.h"
|
|
#include "key_event.h"
|
|
#include "list_model.h"
|
|
#include "services/storage_service.h"
|
|
#include "services/update_service.h"
|
|
#include "text_pager.h"
|
|
#include "ui/canvas.h"
|
|
#include "ui/theme.h"
|
|
|
|
namespace roro {
|
|
|
|
// Looks inside a file for the Storage App (F1, Q134), by type: text read as it's scrolled, a hex
|
|
// dump, a Capture's packets, a Track's summary, an Update File's version and whether it's
|
|
// genuine. Tab switches to the text or the hex of the same file. Nothing here changes a file.
|
|
class FileViewer {
|
|
public:
|
|
FileViewer(StorageService& storage, UpdateService& update) : storage_(storage), update_(update), image_(storage) {}
|
|
|
|
void open(const std::string& path, uint32_t size);
|
|
void close();
|
|
bool onKey(const KeyEvent& e); // false: leave the viewer
|
|
void help(std::vector<KeyHelp>& out) const;
|
|
bool update(uint32_t nowMs); // true: draw again
|
|
void draw(Canvas& c);
|
|
|
|
// For `e` in the Storage App: is this a text small enough to edit (Q146)? And a line to say why not.
|
|
bool showingText() const { return mode_ == Mode::Text; }
|
|
const std::string& path() const { return path_; }
|
|
uint32_t size() const { return size_; }
|
|
void say(const std::string& text);
|
|
// A picture is drawn once and kept on the screen (App::retainsContent).
|
|
bool retains() const { return mode_ == Mode::Image; }
|
|
void lost() { image_.lost(); }
|
|
|
|
private:
|
|
enum class Mode { Text, Hex, Gpx, Pcap, Packet, Ota, Image };
|
|
static constexpr int kRows = 8;
|
|
static constexpr int kCols = 38;
|
|
struct Scan; // what a storage job reads through a whole file for: shared with that job
|
|
|
|
size_t readAt(uint32_t offset, uint8_t* into, size_t len);
|
|
void show(Mode mode);
|
|
void startScan(Mode mode);
|
|
void refresh(); // reads what the screen shows, when it has moved
|
|
void openPacket(int index);
|
|
void scroll(int lines);
|
|
std::string title() const;
|
|
|
|
StorageService& storage_;
|
|
UpdateService& update_;
|
|
ImagePane image_;
|
|
std::string path_;
|
|
uint32_t size_ = 0;
|
|
Mode mode_ = Mode::Text, base_ = Mode::Text;
|
|
std::shared_ptr<fs::File> file_; // opened and read on the storage task only
|
|
std::unique_ptr<files::TextPager> pager_;
|
|
uint32_t hexTop_ = 0; // in rows of eight bytes
|
|
std::vector<std::string> shown_; // the rows on screen
|
|
bool stale_ = true;
|
|
std::shared_ptr<Scan> scan_;
|
|
bool scanShown_ = false;
|
|
int shownPercent_ = -1;
|
|
ListModel packets_{kRows};
|
|
int rowsFrom_ = -1;
|
|
std::vector<std::string> details_;
|
|
int detailsTop_ = 0;
|
|
std::unique_ptr<DialogModel> confirm_;
|
|
std::string message_;
|
|
uint32_t messageMs_ = 0;
|
|
};
|
|
|
|
} // namespace roro
|