1 # This file is part of NIT ( http://www.nitlanguage.org ).
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 # Window to list beers and other beer-related views
20 # View about a beer, with its name, description and rating
25 autoinit beer_info
, parent
28 var beer_info
: BeerAndRatings
30 # Buttons to realize the rating buttons
31 var star_buttons
= new Array[StarButton]
33 # Layout of the first line with the name and `star_buttons`
34 var top_line_layout
= new HorizontalLayout(parent
=self)
38 var lbl_name
= new Label(parent
=top_line_layout
, text
=beer_info
.beer
.name
)
41 var desc
= beer_info
.beer
.desc
42 if beer_info
.is_new
then desc
+= " (New)".t
43 var lbl_desc
= new Label(parent
=self, text
=desc
)
45 var lbl_stats
= new Label(parent
=self, text
=beer_info
.rating_text
)
48 var badges
= beer_info
.badges
49 if badges
!= null then
50 var lbl_comment
= new Label(parent
=self, text
=badges
.join
(" "))
51 lbl_comment
.size
= 0.5
54 var rating
= beer_info
.user_rating
or else 0
58 # Prepare and display the rating controls
59 fun setup_stars
(rating
: Int)
61 var l_stars
= new HorizontalLayout(parent
=top_line_layout
)
64 var but
= new StarButton(beer_info
.beer
, i
, i
<= rating
, parent
=l_stars
)
70 redef fun on_event
(event
)
72 assert event
isa ButtonPressEvent
74 var sender
= event
.sender
75 if sender
isa StarButton then
76 on_review sender
.rating
81 fun on_review
(rating
: Int)
83 var beer_id
= beer_info
.beer
.id
84 (new ReviewAction(app
.window
, "rest/review?token={app.token}&beer={beer_id}&rating={rating}")).start
88 for but
in star_buttons
do
95 # Beers pane listing the available beers
99 private var layout
= new VerticalLayout(parent
=self)
100 private var list_beers
= new ListLayout(parent
=layout
)
104 if debug
then print
"BenitluxWindow::init"
109 # Send HTTP request to list beers
110 fun action_list_beers
111 do (new ListBeersAction(self, "rest/list?token={app.token}")).start
117 # View to describe and rate a eer
121 autoinit beer
, init_rating
, parent
, enabled
126 # Previous rating, 0 for none
129 redef fun parent
=(layout
) do end
131 redef fun enabled
=(value
) do end
134 # Button with a star, filled or not, for rating beers
138 autoinit beer
, rating
, on
, parent
, enabled
140 # Info on the beer to rate
146 # Set if the star is filled
147 fun on
=(on
: Bool) is autoinit
do text
= if on
then "★" else "☆"
150 redef class BeerAndRatings
151 # Text version of the ratings
152 fun rating_text
: String
154 var txt
= new Array[String]
157 if global
!= null and global
.count
> 0 then
158 txt
.add
"%0★ %1 reviews".t
.format
(global
.average
.to_precision
(1), global
.count
)
159 else txt
.add
"No reviews yet".t
162 if local
!= null and local
.count
> 0 then
163 txt
.add
", friends: %0☆ %1 reviews".t
.format
(local
.average
.to_precision
(1), local
.count
)
171 # Capitalize first letter for a prettier display
175 if desc
.length
== 0 then return desc
177 var first_letter
= desc
.first
.to_upper
178 return first_letter
.to_s
+ desc
.substring_from
(1)
182 # Comparator of beers
186 redef type COMPARED: BeerAndRatings
188 redef fun compare
(a
, b
) do return value_of
(a
) <=> value_of
(b
)
190 private fun value_of
(beer
: COMPARED): Float
195 var rating
= beer
.user_rating
196 if rating
!= null then
198 value
+= rating
.to_f
* 4.0
201 var followed
= beer
.followed
202 if followed
!= null then
204 value
+= followed
.average
* 2.0
207 var global
= beer
.global
208 if global
!= null then
210 value
+= global
.average
213 return (max
- value
)/max
217 # Async request to submit a review
219 super WindowHttpRequest
221 redef fun on_load
(res
, status
)
223 if intercept_error
(res
) then return
227 # Async request to update the beer list
228 class ListBeersAction
229 super WindowHttpRequest
231 redef type W
: BeersWindow
233 redef fun on_load
(beers
, status
)
235 window
.layout
.remove window
.list_beers
236 window
.list_beers
= new ListLayout(parent
=window
.layout
)
238 if intercept_error
(beers
) then return
240 if not beers
isa Array[BeerAndRatings] then
241 app
.feedback
"Communication Error".t
245 # Sort beers per preference
246 var comparator
= new BeerComparator
247 comparator
.sort beers
250 for beer_and_rating
in beers
do
251 var view
= new BeerView(beer_and_rating
, parent
=window
.list_beers
)
256 redef class BestBeerBadge
257 redef fun to_s
do return "Favorite beer on the menu.".t
260 redef class FavoriteBeerBadge
261 redef fun to_s
do return "Favorite of %0.".t
.format
(users
.join
(", ", " & "))
264 redef class SimilarBeerBadge
265 redef fun to_s
do return "Similar to %0.".t
.format
(beers
.join
(", ", " & "))
269 # Pretty compressed list of this list of beer as a pseudo diff
271 # Require: `self isa Array[BeerAndRatings]`
272 fun beers_to_notification
: String
274 assert self isa Array[BeerAndRatings]
276 # Sort beers per preference
277 var comparator
= new BeerComparator
280 # Organize the notification line per line
281 # First the new beers, then the fixed one.
282 var lines
= new Array[String]
283 var fix_beers
= new Array[String]
287 lines
.add
"+ {beer.name}: {beer.desc}"
288 else fix_beers
.add beer
.name
291 # Show a few fixed beers per line
292 if fix_beers
.not_empty
then
293 var line
= new FlatBuffer
295 for i
in fix_beers
.length
.times
, beer
in fix_beers
do
297 if i
> 0 then line
.append
", "
299 var l
= line
.length
+ beer
.length
300 if l
< 42 then # Very approximate width of a notification on Android
307 line
= new FlatBuffer
315 return lines
.join
("\n")
318 # Does `self` has a new beer?
320 # Require: `self isa Array[BeerAndRatings]`
321 fun has_new_beers
: Bool
323 assert self isa Array[BeerAndRatings]
325 for beer
in self do if beer
.is_new
then return true