Browse Source

Strategická: Upgrade game UI

master
Jiří Kalvoda 2 years ago
parent
commit
e46d612718
  1. 197
      server/hra/web/game.py
  2. 50
      server/hra/web/pages.py
  3. 4
      server/static/occupy.css

197
server/hra/web/game.py

@ -1,5 +1,5 @@
from flask import Flask, redirect, flash, session, g, request, get_flashed_messages, Markup from flask import Flask, redirect, flash, session, g, request, get_flashed_messages, Markup
from wtforms import Form, BooleanField, StringField, PasswordField, validators, SubmitField, IntegerField, DateTimeField, RadioField from wtforms import Form, BooleanField, StringField, PasswordField, validators, SubmitField, IntegerField, DateTimeField, RadioField, FloatField
from wtforms.validators import ValidationError from wtforms.validators import ValidationError
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_bootstrap import Bootstrap from flask_bootstrap import Bootstrap
@ -45,12 +45,22 @@ class OccupyViewConfig(FlaskForm):
refresh_meta = "Aktualizace pomocí HTML META" refresh_meta = "Aktualizace pomocí HTML META"
refresh_js = "Aktualizace pomocí java scriptu" refresh_js = "Aktualizace pomocí java scriptu"
font_size = IntegerField("Velikost fontu", default=8) clickable_down = "Podrobnosti na kliknutí pod mapou"
clickable_right = "Podrobnosti na kliknutí vpravo vedle mapy"
clickable_not = "Vypnout podrobnosti kliknutím (zmenší nároky na sít a procesor)"
status_minimalistic = "Minimalistické metadata"
status_up = "Matadata nahoře"
status_left = "Metadata vlevo od mapy"
font_size = FloatField("Velikost fontu", default=8.0)
refresh = RadioField("Aktualizace", choices=(refresh_none, refresh_meta), default=refresh_none) refresh = RadioField("Aktualizace", choices=(refresh_none, refresh_meta), default=refresh_none)
not_clickable = BooleanField("Vypnout podrobnosti kliknutím (zmenší nároky na sít a procesor)") clickable = RadioField("", choices=(clickable_not, clickable_down, clickable_right), default=clickable_down)
status = RadioField("", choices=(status_minimalistic, status_left, status_up), default=status_minimalistic)
big_fields = BooleanField("Široká políčka (trojciferné počty)") big_fields = BooleanField("Široká políčka (trojciferné počty)")
submit = SubmitField("Refresh/Potvrdit") submit = SubmitField("Refresh/Potvrdit")
show_data_only = SubmitField("Zobrazit stránku pouze s daty")
@add_wlogic @add_wlogic
class Occupy(WLogic): class Occupy(WLogic):
@ -58,59 +68,94 @@ class Occupy(WLogic):
meta_refresh_without_reaming = 15 meta_refresh_without_reaming = 15
game = state.game game = state.game
team_id = team.team_id if team else None
if game.step_mode == db.StepMode.automatic: if game.step_mode == db.StepMode.automatic:
time_reaming = (state.create_time - datetime.now()).total_seconds() + game.step_every_s time_reaming = (state.create_time - datetime.now()).total_seconds() + game.step_every_s
else: else:
time_reaming = None time_reaming = None
s = state.get_state() s = state.get_state()
if team is not None:
s = self.logic.personalize_state(s, team.team_id, state.round)
conff = OccupyViewConfig(formdata=request.args, csrf_enabled=False) conff = OccupyViewConfig(formdata=request.args, csrf_enabled=False)
q = db.get_session().query(db.Log).order_by(db.Log.log_id.desc()) q = db.get_session().query(db.Log).order_by(db.Log.log_id.desc())
conff.validate() conff.validate()
max_num = 999 if conff.big_fields.data else 99 max_num = 999 if conff.big_fields.data else 99
b = BasePage() def reaming_time(id="time"):
b.h2(f"Hra {self.game.print()} kolo {state.round}") if time_reaming is not None:
if not conff.not_clickable.data: b.b("Čas do konce kola: ", b._span(id=id)(int(time_reaming)), " sekund")
b.p("Po kliknutí na buňku se zobrazí další informace.") b.script(Markup(f"""
if conff.refresh.data == conff.refresh_meta and time_reaming is None: var intervalID = window.setInterval(update_time, 100);
b.p(f"Není známo, kdy nastane další kolo, proto může být aktualizace až o {meta_refresh_without_reaming} sekund opožděna.") var t = { time_reaming*1000 };
with b.p(): function update_time() {{
b.line().b(_class=f"game_team_{team.team_id}")(f"Pohled týmu {team.print()}") document.getElementById("{id}").innerHTML = Math.floor(t/1000);;
with b.line().b(_class="pull-right"): t -= 100;
if time_reaming is not None: }}
b("Čas do konce kola: ", b._span(id="time")(int(time_reaming)), " sekund") """))
else: else:
b("Konec kola není stanoven") b("Konec kola není stanoven")
with b.p(style="text-align:center;").table(_class="game_table"):
for i, row in enumerate(s["world"]): def status():
with b.tr(): members_counts = [0 for _ in teams]
for j, x in enumerate(row): occupied_counts = [0 for _ in teams]
occupied_by_team = x["occupied_by_team"]
home_for_team = x["home_for_team"] for x in s["world"]:
members = x["members"] for y in x:
with b.td(): occupied_by_team = y["occupied_by_team"]
classes = [] members = y["members"]
with b.a(href=f"#cell_{i}_{j}") if not conff.not_clickable.data else b.bucket(): if occupied_by_team is not None:
if x["protected_for_team"] is not None: occupied_counts[occupied_by_team] += 1
classes.append("game_protected") members_counts[occupied_by_team] += len(members)
if x["hill"]:
classes.append("game_hill")
b(Markup(" ")) with b.div(_class="game_left_status button form-frame"):
else: b.b("Kolo ", state.round)
if home_for_team is not None: with b.p():
classes.append(f'game_home') reaming_time(id="time_left")
if occupied_by_team is not None: with b.p():
classes.append(f'game_occupied') for t, occupied_count, members_count in zip(teams, occupied_counts, members_counts):
classes.append(f'game_occupied_by_{occupied_by_team}') with b.line().span(_class=f"game_team_{t.team_id}"):
num = len(members) b.b("Tým ", t.print())
if num: b.br()
b(num if num <= max_num else ("+++" if conff.big_fields.data else "++")) b("Bodů: ", t.get_move(state.round).points)
else: b.br()
b("Políček: ", occupied_count)
b.br()
b("Vojáků: ", members_count)
b.br()
def table():
with b.table(_class="game_table"):
for i, row in enumerate(s["world"]):
with b.tr():
for j, x in enumerate(row):
occupied_by_team = x["occupied_by_team"]
home_for_team = x["home_for_team"]
members = x["members"]
with b.td():
classes = []
with b.a(href=f"#cell_{i}_{j}") if conff.clickable.data != conff.clickable_not else b.bucket():
if x["protected_for_team"] is not None:
classes.append("game_protected")
if x["hill"]:
classes.append("game_hill")
b(Markup("&nbsp;")) b(Markup("&nbsp;"))
b(_class=" ".join(classes)) else:
if home_for_team is not None:
classes.append(f'game_home')
if occupied_by_team is not None:
classes.append(f'game_occupied')
classes.append(f'game_occupied_by_{occupied_by_team}')
num = len(members)
if num:
b(num if num <= max_num else ("+++" if conff.big_fields.data else "++"))
else:
b(Markup("&nbsp;"))
b(_class=" ".join(classes))
if not conff.not_clickable.data: def clickable():
for i, row in enumerate(s["world"]): for i, row in enumerate(s["world"]):
for j, x in enumerate(row): for j, x in enumerate(row):
occupied_by_team = x["occupied_by_team"] occupied_by_team = x["occupied_by_team"]
@ -131,34 +176,60 @@ class Occupy(WLogic):
b.p().b(f"Počet osob: {len(members)}") b.p().b(f"Počet osob: {len(members)}")
with b.ul(): with b.ul():
for m in members: for m in members:
b.li(_class=f"game_team_{home_for_team}")(f"Voják {m['id']} týmu {teams[m['team']].print()}") b.li(_class=f"game_team_{m['team']}")(f"Voják {m['id']} týmu {teams[m['team']].print()}")
b = BasePage()
if not conff.show_data_only.data:
b.h2(f"Hra {self.game.print()} kolo {state.round}")
if conff.clickable.data != conff.clickable_not:
b.p("Po kliknutí na buňku se zobrazí další informace.")
if conff.refresh.data == conff.refresh_meta and time_reaming is None:
b.p(f"Není známo, kdy nastane další kolo, proto může být aktualizace až o {meta_refresh_without_reaming} sekund opožděna.")
with b.p():
if team is not None:
b.line().b(_class=f"game_team_{team.team_id}")(f"Pohled týmu {team.print()}")
with b.line().b(_class="pull-right"):
reaming_time()
b.div(style="clear: both; margin-bottom: 1ex")("")
with b.div().div(style="text-align:center;", id="game_main"):
if conff.status.data == conff.status_left:
status()
table()
if conff.clickable.data == conff.clickable_right:
clickable()
b.div(style="clear: both; margin-bottom: 1ex")("")
if conff.clickable.data == conff.clickable_down:
clickable()
del conff.csrf_token del conff.csrf_token
b.p() b.p()
b.div(_class="form-frame")(jinja_mac.quick_form(conff, form_type="horizontal", method="GET")) if not conff.show_data_only.data:
b.div(_class="form-frame")(jinja_mac.quick_form(conff, form_type="horizontal", method="GET"))
b.script(Markup(f"""
var intervalID = window.setInterval(update_time, 100);
var t = { time_reaming*1000 };
function update_time() {{
document.getElementById("time").innerHTML = Math.floor(t/1000);;
t -= 100;
}}
"""))
def head(x): def head(x):
style = ""
page_w = float("inf") if conff.show_data_only.data else 1000
refresh_time = time_reaming + 1 if time_reaming is not None else 15 refresh_time = time_reaming + 1 if time_reaming is not None else 15
font_size = int(conff.font_size.data) font_size = float(conff.font_size.data or 8.0)
box_size = int(font_size * 1.3 + 1) box_size = int(font_size * 1.5 + 1)
left_w = 0
if conff.status.data == conff.status_left:
left_w = 150
box_w = box_size box_w = box_size
if conff.big_fields.data: if conff.big_fields.data:
box_w *= 1.5 box_w *= 1.5
table_w = len(s["world"][0]) * box_w table_w = len(s["world"][0]) * box_w
margin_cmd = "" margin_cmd = ""
if table_w > 1000: main_w = table_w + left_w
margin_cmd = f"margin-left: {(1000-table_w) / 2}px;" if conff.clickable.data == conff.clickable_right:
right_w = 400
main_w += right_w
style += f".game_tab {{\n width: {right_w}px\n}}\n"
if main_w > page_w:
margin_cmd = f"margin-left: {(page_w-main_w) / 2}px;"
if conff.refresh.data == conff.refresh_meta: if conff.refresh.data == conff.refresh_meta:
b.meta(**{"HTTP-EQUIV": "refresh", "CONTENT": f"{refresh_time};{app.url_for(web_game_view.__name__, game_id=game.game_id, team_id=team.team_id, **request.args)}"}) b.meta(**{"HTTP-EQUIV": "refresh", "CONTENT": f"{refresh_time};{app.url_for(web_game_view.__name__, game_id=game.game_id, team_id=team_id, **request.args)}"})
b.link(rel="stylesheet", href=app.url_for('static', filename='occupy.css'), type='text/css', media="all") b.link(rel="stylesheet", href=app.url_for('static', filename='occupy.css'), type='text/css', media="all")
b.style(Markup(f""" b.style(Markup(f"""
table.game_table tr td {{ table.game_table tr td {{
@ -169,8 +240,15 @@ class Occupy(WLogic):
}} }}
table.game_table {{ table.game_table {{
width: {table_w}px; width: {table_w}px;
}}
#game_main {{
{margin_cmd} {margin_cmd}
width: {main_w}px;
}}
.game_left_status {{
width: {left_w-20}px;
}} }}
{style}
""")) """))
@ -178,5 +256,6 @@ class Occupy(WLogic):
limited_size=False, limited_size=False,
sticky_head=False, sticky_head=False,
head=head, head=head,
empty=conff.show_data_only.data
) )
return b.print_file() return b.print_file()

50
server/hra/web/pages.py

@ -22,7 +22,7 @@ import hra.lib as lib
@html.WrapAfterBuilder_decorator @html.WrapAfterBuilder_decorator
def BasePage(b, content, head=lambda x:None, limited_size=True, sticky_head=True): def BasePage(b, content, head=lambda x:None, limited_size=True, sticky_head=True, empty=False):
b.current_tag = html.Tag(b, "html", []) b.current_tag = html.Tag(b, "html", [])
b.root_tag = b.current_tag b.root_tag = b.current_tag
with b.head(): with b.head():
@ -34,29 +34,32 @@ def BasePage(b, content, head=lambda x:None, limited_size=True, sticky_head=True
b.link(rel="shortcut icon", href=app.url_for('static', filename='img/favicon.ico')) b.link(rel="shortcut icon", href=app.url_for('static', filename='img/favicon.ico'))
b(head) b(head)
with b.body() as body: with b.body() as body:
with b.header(_class=f"flavor-{config.WEB_FLAVOR}"): if empty:
with b.div(_class="content content_limited" if limited_size else "content"):
with b.a(href="/", title="Na hlavní stránku"):
b.img(src=app.url_for('static', filename='hippo.png'), style="width: 60px;height: auto;", alt="KSP")
b.h1()("Hra na soustředění KSP")
with b.div(id="nav-wrapper", _class="nav-wrapper-sticky" if sticky_head else ""):
with b.nav(id="main-menu", _class="content"):
for item in g.menu:
b.a(href=item.url)(item.name)
if g.user:
b.a(_class="right", href="/")(f"Přihlášen: {g.user.username}")
b.a(_class="right", href="/logout")(f"Odhlásit")
else:
b.a(_class="right", href="/login")(f"Přihlásit")
b.a(_class="right", href="/registration")(f"Registrovat")
with b.main():
messages = get_flashed_messages(with_categories=True)
if messages:
for category, message in messages:
if category == "message":
category = "warning"
b.div(_class=f"alert alert-{category}", role="alert")(message)
b(*content) b(*content)
else:
with b.header(_class=f"flavor-{config.WEB_FLAVOR}"):
with b.div(_class="content content_limited" if limited_size else "content"):
with b.a(href="/", title="Na hlavní stránku"):
b.img(src=app.url_for('static', filename='hippo.png'), style="width: 60px;height: auto;", alt="KSP")
b.h1()("Hra na soustředění KSP")
with b.div(id="nav-wrapper", _class="nav-wrapper-sticky" if sticky_head else ""):
with b.nav(id="main-menu", _class="content"):
for item in g.menu:
b.a(href=item.url)(item.name)
if g.user:
b.a(_class="right", href="/")(f"Přihlášen: {g.user.username}")
b.a(_class="right", href="/logout")(f"Odhlásit")
else:
b.a(_class="right", href="/login")(f"Přihlásit")
b.a(_class="right", href="/registration")(f"Registrovat")
with b.main():
messages = get_flashed_messages(with_categories=True)
if messages:
for category, message in messages:
if category == "message":
category = "warning"
b.div(_class=f"alert alert-{category}", role="alert")(message)
b(*content)
class OptionalIntField(wtforms.IntegerField): class OptionalIntField(wtforms.IntegerField):
@ -310,6 +313,7 @@ def web_game_step(game_id):
return redirect(app.url_for(web_game.__name__, game_id=game_id)) return redirect(app.url_for(web_game.__name__, game_id=game_id))
@app.route("/game/<int:game_id>/view", methods=['GET'])
@app.route("/game/<int:game_id>/view/<int:team_id>", methods=['GET']) @app.route("/game/<int:game_id>/view/<int:team_id>", methods=['GET'])
def web_game_view(game_id, team_id=None): def web_game_view(game_id, team_id=None):
ses = db.get_session() ses = db.get_session()

4
server/static/occupy.css

@ -136,3 +136,7 @@ table.game_table tr td a, table.game_table tr td a:hover, table.game_table tr td
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
} }
#game_main div, #game_main table {
float: left;
}

Loading…
Cancel
Save