14#include "../core/callback_scope.hpp"
15#include "../core/completion.hpp"
51 std::function<
void(std::string
const&)> onError = {})
52 : _dispatcher{&dispatcher}, _application{std::move(application)}, _onError{std::move(onError)} {}
63 std::function<
void(std::expected<PreferencesLoaded, std::string>)> done = {}) {
64 Document const& doc = screen.document();
65 PrefLoad request{.app = _application, .scope = doc.
id, .points = {}};
66 for (
auto const& [name, point] : doc.
customize) {
67 static_cast<void>(point);
68 request.points.push_back(name);
70 _points.insert_or_assign(doc.
id,
request.points);
73 done(PreferencesLoaded{});
78 std::make_shared<std::function<void(std::expected<PreferencesLoaded, std::string>)>>(std::move(done));
80 ->execute(
"load", model::ActionTraits<PrefLoad>::toJson(request), CallOptions{})
82 [&screen, shared](std::string
const& reply) {
83 auto applied = apply(screen, reply);
85 (*shared)(std::move(applied));
88 .onError(scope, [shared](std::exception_ptr
const& error) {
90 (*shared)(std::unexpected(detail::failureText(error)));
99 void changed(std::string
const& screen, std::string
const& point,
Value const& value) {
100 PrefSet const request{.app = _application,
103 .value = glz::write_json(
valueToJson(value)).value_or(
"null")};
111 void reset(std::string
const& screen, std::string
const& point) {
112 std::vector<std::string> points;
113 if (point ==
"all") {
114 if (
auto const found = _points.find(screen); found != _points.end()) {
115 points = found->second;
118 points.push_back(point);
120 for (std::string& each : points) {
121 PrefRemove const request{.app = _application, .scope = screen, .point = std::move(each)};
129 [[nodiscard]] std::shared_ptr<ModelChannel>
const& channel() {
130 if (_channel ==
nullptr) {
138 void report(async::Completion<std::string> call)
const {
139 call.thenDetached([](std::string
const&) {})
140 .onErrorDetached([onError = _onError](std::exception_ptr
const& error) {
142 onError(detail::failureText(error));
151 [[nodiscard]]
static std::expected<PreferencesLoaded, std::string> apply(Screen& screen,
152 std::string
const& reply) {
155 values = model::ActionTraits<PrefLoad>::resultFromJson(reply);
156 }
catch (std::exception
const& error) {
157 return std::unexpected(std::string{
"not a preferences reply: "} + error.what());
159 PreferencesLoaded loaded;
160 auto const& points =
screen.document().customize;
161 for (
auto& [name, text] : values.values) {
162 auto const point = points.find(name);
163 if (point == points.end() || !take(screen, point->second, text)) {
177 [[nodiscard]]
static bool take(Screen& screen, CustomizePoint
const& point, std::string
const& text) {
178 auto const json = parseJson(text);
182 bool const typed = point.kind ==
"choice" || point.kind ==
"value";
184 return value &&
screen.setPreference(point.name, std::move(*value));
187 Dispatcher* _dispatcher;
188 std::string _application;
189 std::function<void(std::string
const&)> _onError;
190 std::shared_ptr<ModelChannel> _channel;
192 std::map<std::string, std::vector<std::string>, std::less<>> _points;
Screen screen(Screen::Builder builder)
A screen with its id as a template argument, as spec 5 §11 writes it.
Owned lifetime-and-stop gate for asynchronous callbacks — a data member, not a base class.
The interpreter's view of the bridge: binds a model by its type id, privately or to a shared instance...
virtual std::shared_ptr< ModelChannel > bind(std::string const &typeId, bridge::BindSharing sharing, std::string const &instanceKey)=0
Binds a model.
void load(Screen &screen, async::CallbackScope const &scope, std::function< void(std::expected< PreferencesLoaded, std::string >)> done={})
Loads screen's stored choices, in one call for all its points, and sets each that fits.
void reset(std::string const &screen, std::string const &point)
Forgets the stored choice at a point, or at every point of a screen this sync has loaded.
void changed(std::string const &screen, std::string const &point, Value const &value)
Stores the user's choice at a point.
PreferenceSync(Dispatcher &dispatcher, std::string application, std::function< void(std::string const &)> onError={})
A sync for application.
A mounted screen: its scopes, its view mounted through Mounted, and what its host asks of it.
The document's typed value (spec 5 §3): what every expression evaluates to.
The UI document (spec 5 §3): its model — declarations, commands, view nodes, components and customiza...
The UI document interpreter: Interpreter::mount turns a loaded Document into reactive state and a vie...
Per-person storage of customization choices (spec 5 §12b, spec 6 §8): the IPreferencesStore seam,...
constexpr std::string_view kPreferencesModel
The type id the preferences model is registered under.
void request(Store< ViewState, Msg > &store, bridge::BridgeHandler< Model, Sharing > &handler, async::CallbackScope const &scope, Action action, ToMsg toMsg, ToFailMsg toFailMsg)
Executes action and sends its result, or its failure, to store as one message.
Traits specialisation that maps an action type to its id, JSON codec, and result type.
How one model call is sent.
A loaded and validated UI document: a screen, or the app document (id app, spec 6 §5).
std::string id
The document id, such as lims.results.
std::map< std::string, CustomizePoint, std::less<> > customize
Customization points, by name.
load: the stored choices of a screen's points. A request carries no person.
remove: forgets one choice. A request carries no person.
set: stores one choice. A request carries no person.
What loading a screen's choices did.
std::size_t applied
Stored choices the screen took.
std::size_t ignored
Stored choices the screen ignored: text that is not a value of the point's type, or a value the point...
The UI document's typed values (ui::Value), its types (ui::Type), their JSON form,...
Json valueToJson(Value const &value)
Writes a value in its JSON form: the inverse of valueFromJson, with a timestamp as ISO-8601 text.
std::expected< Value, std::string > valueFromJson(Json const &json)
Reads a value from its JSON form, structurally.