max / goingson
1 file changed,
+45 insertions,
-39 deletions
| @@ -738,10 +738,17 @@ | |||
| 738 | 738 | ||
| 739 | 739 | /// The controls over the selection. | |
| 740 | 740 | /// | |
| 741 | - | /// The shipped bar's five, and its two halves are two kinds of control. | |
| 742 | - | /// Complete and Delete act on the set; snooze, project and priority apply a | |
| 743 | - | /// value to it, which is why [`Field::over`] had to exist — said as acts, the | |
| 744 | - | /// project picker alone is one button per project. | |
| 741 | + | /// The shipped bar's five, all of them acts. Complete and Delete act on the set | |
| 742 | + | /// and carry no value; priority, project and snooze apply a value, and reach it | |
| 743 | + | /// through [`Act::asks`] rather than by being pickers that write as they change. | |
| 744 | + | /// | |
| 745 | + | /// The picker was the reason [`Field::over`] was added: said as plain acts, a | |
| 746 | + | /// project picker is one button per project. `Act::asks` answers that without | |
| 747 | + | /// the write, because the value rides with the press instead of firing on its | |
| 748 | + | /// own, so a picker over forty projects is still one control. Under | |
| 749 | + | /// wiki `explicit-commit-affordance` the press is also the commit the reader | |
| 750 | + | /// needs, and a bar whose ticks stage while its pickers write was half staged | |
| 751 | + | /// and half live. | |
| 745 | 752 | /// | |
| 746 | 753 | /// # What is not here | |
| 747 | 754 | /// | |
| @@ -785,57 +792,56 @@ | |||
| 785 | 792 | )); | |
| 786 | 793 | } | |
| 787 | 794 | ||
| 788 | - | // A blank leading option on each picker, because a select opens on its | |
| 789 | - | // first option and one that opened on "High" would read as though the | |
| 790 | - | // selection already had a priority. Choosing the blank writes nothing: the | |
| 791 | - | // handlers answer an unparseable value with the list unchanged rather than | |
| 792 | - | // an error, which is the one place on this screen a bad value is not a 404 | |
| 793 | - | // — it is the control's resting state, not a wiring mistake. | |
| 794 | - | let mut priorities = vec![Choice::new("", "Set priority")]; | |
| 795 | - | priorities.extend( | |
| 796 | - | PRIORITIES | |
| 797 | - | .iter() | |
| 798 | - | .map(|priority| Choice::new(priority_word(priority), priority_word(priority))), | |
| 799 | - | ); | |
| 800 | - | out.push(Node::field( | |
| 801 | - | Field::select("priority", "Set priority", priorities) | |
| 802 | - | .writes(over(Action::post("/tasks/list/priority"))) | |
| 803 | - | .over(SELECTION), | |
| 795 | + | // The three value controls are acts that ask, not fields that write. A tick | |
| 796 | + | // stages and never writes (`5f2b8753`), so a bar whose ticks stage and whose | |
| 797 | + | // pickers write on change is half staged and half live. Pressing the verb is | |
| 798 | + | // the commit, and the picker it reveals is the value that commit carries. | |
| 799 | + | // | |
| 800 | + | // No blank leading option any more. It existed because a bare select opens | |
| 801 | + | // on its first option, and one opening on "High" read as though the | |
| 802 | + | // selection already had a priority. A picker that is not on screen until | |
| 803 | + | // the verb is pressed cannot say that, so the resting state has nowhere to | |
| 804 | + | // be and the option that stood for it is gone. The handlers still answer an | |
| 805 | + | // unparseable value with the list unchanged, which now covers nothing this | |
| 806 | + | // screen sends. | |
| 807 | + | let priorities: Vec<Choice> = PRIORITIES | |
| 808 | + | .iter() | |
| 809 | + | .map(|priority| Choice::new(priority_word(priority), priority_word(priority))) | |
| 810 | + | .collect(); | |
| 811 | + | out.push(Node::Act( | |
| 812 | + | Act::new("Set priority", over(Action::post("/tasks/list/priority"))) | |
| 813 | + | .over(SELECTION) | |
| 814 | + | .asking(Field::select("priority", "Priority", priorities)), | |
| 804 | 815 | )); | |
| 805 | 816 | ||
| 806 | 817 | let projects = state | |
| 807 | 818 | .projects | |
| 808 | 819 | .list_all(DESKTOP_USER_ID) | |
| 809 | 820 | .map_err(|error| RouteError::internal(error.to_string()))?; | |
| 810 | - | let mut options = vec![ | |
| 811 | - | Choice::new("", "Set project"), | |
| 812 | - | Choice::new(NONE, "No project"), | |
| 813 | - | ]; | |
| 821 | + | let mut options = vec![Choice::new(NONE, "No project")]; | |
| 814 | 822 | options.extend( | |
| 815 | 823 | projects | |
| 816 | 824 | .iter() | |
| 817 | 825 | .map(|project| Choice::new(project.id.to_string(), &project.name)), | |
| 818 | 826 | ); | |
| 819 | - | out.push(Node::field( | |
| 820 | - | Field::select("project", "Set project", options) | |
| 821 | - | .writes(over(Action::post("/tasks/list/project"))) | |
| 822 | - | .over(SELECTION), | |
| 827 | + | out.push(Node::Act( | |
| 828 | + | Act::new("Set project", over(Action::post("/tasks/list/project"))) | |
| 829 | + | .over(SELECTION) | |
| 830 | + | .asking(Field::select("project", "Project", options)), | |
| 823 | 831 | )); | |
| 824 | 832 | ||
| 825 | 833 | // The same precomputed times the shipped modal offers, from the same | |
| 826 | 834 | // function, so "Later Today" means one thing in the app. A described screen | |
| 827 | 835 | // has no modal to put them in and does not need one: they are options. | |
| 828 | - | let mut whens = vec![Choice::new("", "Snooze until")]; | |
| 829 | - | whens.extend( | |
| 830 | - | crate::commands::get_snooze_options() | |
| 831 | - | .options | |
| 832 | - | .into_iter() | |
| 833 | - | .map(|option| Choice::new(option.time.to_rfc3339(), option.label)), | |
| 834 | - | ); | |
| 835 | - | out.push(Node::field( | |
| 836 | - | Field::select("until", "Snooze until", whens) | |
| 837 | - | .writes(over(Action::post("/tasks/list/snooze"))) | |
| 838 | - | .over(SELECTION), | |
| 836 | + | let whens: Vec<Choice> = crate::commands::get_snooze_options() | |
| 837 | + | .options | |
| 838 | + | .into_iter() | |
| 839 | + | .map(|option| Choice::new(option.time.to_rfc3339(), option.label)) | |
| 840 | + | .collect(); | |
| 841 | + | out.push(Node::Act( | |
| 842 | + | Act::new("Snooze until", over(Action::post("/tasks/list/snooze"))) | |
| 843 | + | .over(SELECTION) | |
| 844 | + | .asking(Field::select("until", "Snooze until", whens)), | |
| 839 | 845 | )); | |
| 840 | 846 | ||
| 841 | 847 | Ok(out) |