nit: Added link to `CONTRIBUTING.md` from the README
[nit.git] / contrib / benitlux / src / client / base.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Common services for the Benitlux app
16 module base
17
18 import app::ui
19 import app::data_store
20 import app::http_request
21 import android::aware
22 import json::serialization
23
24 import benitlux_model
25 import translations
26
27 # Show debug output?
28 fun debug: Bool do return true
29
30 # Root URI of the remote RESTfule server
31 fun benitlux_rest_server_uri: String do return "http://localhost:8080/"
32
33 redef class App
34
35 # Current connection token, or "none"
36 var token: String is lazy, writable do
37 var token = app.data_store["token"]
38 if token isa String then return token
39 return "none"
40 end
41
42 # Name of the currently logged in user
43 var user: nullable String is lazy, writable do
44 var user = app.data_store["user"]
45 if user isa nullable String then return user
46 return null
47 end
48
49 # Event when user logs in or out
50 fun on_log_in do on_save_state
51
52 redef fun on_save_state
53 do
54 app.data_store["user"] = user
55 app.data_store["token"] = token
56 super
57 end
58
59 # Has this app state been restored yet?
60 var restored = false
61
62 redef fun on_restore_state
63 do
64 super
65
66 # TODO this may happen before the lazy loading above
67 restored = true
68
69 if token != "none" then on_log_in
70 end
71
72 # Show simple feedback to the user on important errors
73 fun feedback(text: Text) do print_error text
74 end
75
76 # Show a notification to the user
77 fun notify(title, content: Text, uniqueness_id: Int)
78 do print "Notification {uniqueness_id}: {title}; {content}"
79
80 # View for an item in a list, like a beer or a person
81 abstract class ItemView
82 super View
83 end
84
85 # Basic async HTTP request for this app
86 #
87 # Note that connection errors are passed to `on_fail`, and
88 # server errors or authentification errors are received by `on_load`
89 # and should be passed to `intercept_error`.
90 class BenitluxHttpRequest
91 super AsyncHttpRequest
92
93 redef fun rest_server_uri do return benitlux_rest_server_uri
94
95 redef var rest_action
96
97 redef fun on_fail(error)
98 do
99 if error isa IOError then
100 # This should be a normal network error like being offline.
101 # Print to log, but don't show to the user.
102 print_error error.class_name
103 else
104 # This could be a deserialization error,
105 # it may be related to an outdated client.
106 # Report to user.
107 print_error "Request Error: {rest_server_uri / rest_action} with {error}"
108 app.feedback "Request Error: {error}"
109 end
110 end
111
112 # Intercept known server side errors
113 fun intercept_error(res: nullable Object): Bool
114 do
115 if res isa BenitluxTokenError then
116 app.token = "none"
117 app.user = null
118 return true
119 else if res isa BenitluxError then
120 app.feedback((res.user_message or else res.message).t)
121 return true
122 else if res isa Error then
123 app.feedback res.message.t
124 return true
125 end
126 return false
127 end
128 end
129
130 # Async request with services to act on the windows of the app
131 class WindowHttpRequest
132 super BenitluxHttpRequest
133
134 autoinit window, rest_action
135
136 # Type of the related `window`
137 type W: Window
138
139 # `Window` on which to apply the results of this request
140 var window: W
141
142 # `Views` to disable while this request is in progress
143 var affected_views = new Array[View]
144
145 redef fun before do for view in affected_views do view.enabled = false
146
147 redef fun after do for view in affected_views do view.enabled = true
148 end
149
150 redef class Text
151 # Ellipsize `self` so it fits within `max_length` characters
152 #
153 # FIXME Remove this when labels are correctly ellipsized on iOS.
154 fun ellipsize: Text do return self
155 end