1 module mvvm.model;
2 
3 import rx;
4 
5 class AppViewModel
6 {
7     private BehaviorSubject!string _name;
8     private BehaviorSubject!int _age;
9     private Observable!bool _canDecrementAge;
10     private Observable!bool _canClear;
11     private Observable!string _profile;
12 
13     this()
14     {
15         _name = new BehaviorSubject!string("");
16         _age = new BehaviorSubject!int(0);
17 
18         _canDecrementAge = _age.map!(age => age > 0).distinctUntilChanged()
19             .observableObject!bool();
20 
21         _canClear = combineLatest(_name, _age).map!(t => t[0] != "" || t[1] != 0)
22             .distinctUntilChanged().observableObject!bool();
23 
24         _profile = combineLatest!((a, b) => formatProfile(a, b))(_name, _age).distinctUntilChanged()
25             .observableObject!string();
26     }
27 
28     Subject!string name()
29     {
30         return _name;
31     }
32 
33     Subject!int age()
34     {
35         return _age;
36     }
37 
38     Observable!bool canDecrementAge()
39     {
40         return _canDecrementAge;
41     }
42 
43     unittest
44     {
45         auto model = new AppViewModel;
46         bool lastValue = true;
47         model.canDecrementAge.doSubscribe((bool canDecrement) {
48             lastValue = canDecrement;
49         });
50         assert(!lastValue);
51 
52         model.incrementAge();
53         assert(lastValue);
54         model.decrementAge();
55         assert(!lastValue);
56     }
57 
58     Observable!bool canClear()
59     {
60         return _canClear;
61     }
62 
63     unittest
64     {
65         auto model = new AppViewModel;
66         bool lastValue = true;
67         model.canClear.doSubscribe((bool canClear) {
68             lastValue = canClear;
69         });
70         assert(!lastValue);
71 
72         model.name.put("TEST");
73         assert(lastValue);
74         model.name.put("");
75         assert(!lastValue);
76         model.incrementAge();
77         assert(lastValue);
78         model.decrementAge();
79         assert(!lastValue);
80     }
81 
82     Observable!string profile()
83     {
84         return _profile;
85     }
86 
87     void clear()
88     {
89         _name.value = "";
90         _age.value = 0;
91     }
92 
93     void incrementAge()
94     {
95         _age.value = _age.value + 1;
96     }
97 
98     void decrementAge()
99     {
100         _age.value = _age.value - 1;
101     }
102 
103     private string formatProfile(string name, int age)
104     {
105         if (name.length == 0)
106             return "";
107 
108         import std.format;
109 
110         return format!"%s (%d)"(name, age);
111     }
112 
113     unittest
114     {
115         auto model = new AppViewModel;
116         assert(model.formatProfile("", 0) == "");
117         assert(model.formatProfile("", 10) == "");
118         assert(model.formatProfile("TEST", 0) == "TEST (0)");
119         assert(model.formatProfile("TEST", 10) == "TEST (10)");
120     }
121 }