Add create season function.

This commit is contained in:
luxick
2018-03-09 20:45:12 +01:00
parent ce7bb3a244
commit 7034321889
10 changed files with 473 additions and 78 deletions

View File

@@ -1,7 +1,9 @@
"""
This module contains UI functions for displaying different dialogs
"""
import datetime
from gi.repository import Gtk
from common import models
def enter_string_dialog(builder: Gtk.Builder, title: str, value=None) -> str:
@@ -28,6 +30,32 @@ def enter_string_dialog(builder: Gtk.Builder, title: str, value=None) -> str:
return value
def edit_season(builder: 'Gtk.Builder', season: 'models.Season'=None):
if not season:
season = models.Season()
builder.get_object('season_number_spin').set_value(season.number or 1)
builder.get_object('season_game_entry').set_text(season.game_name or '')
builder.get_object('season_start_entry').set_text(season.start_date or '')
builder.get_object('season_end_entry').set_text(season.end_date or '')
dialog = builder.get_object('edit_season_dialog')
result = dialog.run()
dialog.hide()
if result != Gtk.ResponseType.OK:
return None
season.number = builder.get_object('season_number_spin').get_value()
season.game_name = builder.get_object('season_game_entry').get_text()
start_string = builder.get_object('season_start_entry').get_text()
if start_string:
season.start_date = datetime.datetime.strptime(start_string, '%Y-%m-%d')
end_string = builder.get_object('season_end_entry').get_text()
if end_string:
season.end_date = datetime.datetime.strptime(end_string, '%Y-%m-%d')
return season
def show_episode_dialog(builder: Gtk.Builder, title: str, season_id: int, episode):
""" Shows a dialog to edit an episode
:param builder: GtkBuilder with loaded 'dialogs.glade'

View File

@@ -1,10 +1,10 @@
import os
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf
from gi.repository import Gtk
from dsst_gtk3.handlers import handlers
from dsst_gtk3 import util, reload, client
from common import models
class GtkUi:
""" The main UI class """
@@ -29,34 +29,51 @@ class GtkUi:
# Connect to data server
config = config['servers'][0]
self.data_client = client.Access(config)
self.data = {}
# Create local data caches
self.players = util.Cache()
self.drinks = util.Cache()
self.seasons = util.Cache()
self.episodes = util.Cache()
self.enemies = util.Cache()
self.season_stats = util.Cache()
# Create meta data cache
self.meta = {'connection': '{}:{}'.format(config.get('host'), config.get('port'))}
self.season_changed = True
self.ep_changed = False
# Load base data and seasons
self.initial_load()
self.load_server_meta()
self.reload()
self.update_status_bar_meta()
def initial_load(self):
with util.network_operation(self):
self.data['players'] = self.data_client.send_request('load_players')
self.data['drinks'] = self.data_client.send_request('load_drinks')
self.data['seasons'] = self.data_client.send_request('load_seasons')
def load_server_meta(self):
self.meta['database'] = self.data_client.send_request('load_db_meta')
reload.reload_base_data(self.ui, self)
def reload(self):
if self.season_changed:
with util.network_operation(self):
refresh_base = False
if not self.players.valid:
self.players.data = self.data_client.send_request('load_players')
refresh_base = True
if not self.drinks.valid:
self.drinks.data = self.data_client.send_request('load_drinks')
refresh_base= True
if not self.seasons.valid:
self.seasons.data = self.data_client.send_request('load_seasons')
refresh_base = True
if refresh_base:
reload.reload_base_data(self.ui, self)
if not self.episodes.valid:
with util.network_operation(self):
season_id = self.get_selected_season_id()
self.data['episodes'] = self.data_client.send_request('load_episodes', season_id)
self.data['season_stats'] = self.data_client.send_request('load_season_stats', season_id)
if season_id:
self.episodes.data = self.data_client.send_request('load_episodes', season_id)
self.season_stats.data = self.data_client.send_request('load_season_stats', season_id)
reload.reload_episodes(self.ui, self)
reload.reload_season_stats(self)
self.season_changed = False
if self.ep_changed:
reload.reload_episode_stats(self)
def update_season(self, season: 'models.Season'):
with util.network_operation(self):
self.data_client.send_request('update_season', season)
self.seasons.valid = False
def update_status_bar_meta(self):
self.ui.get_object('connection_label').set_text(self.meta.get('connection'))

View File

@@ -1,4 +1,7 @@
from dsst_gtk3 import dialogs, util
import datetime
from dsst_gtk3 import dialogs, util, gtk_ui
from gi.repository import Gtk
class DialogHandlers:
@@ -27,3 +30,20 @@ class DialogHandlers:
def do_manage_drinks(self, *_):
result = dialogs.show_manage_drinks_dialog(self.app.ui)
def do_show_date_picker(self, entry: 'Gtk.Entry', *_):
dialog = self.app.ui.get_object('date_picker_dialog')
result = dialog.run()
dialog.hide()
if result == Gtk.ResponseType.OK:
date = self.app.ui.get_object('date_picker_calendar').get_date()
date_string = '{}-{:02d}-{:02d}'.format(date.year, date.month +1, date.day)
entry.set_text(date_string)
@staticmethod
def do_set_today(cal: 'Gtk.Calendar'):
"""Set date of a Gtk Calendar to today
:param cal: Gtk.Calendar
"""
cal.select_month = datetime.date.today().month
cal.select_day = datetime.date.today().day

View File

@@ -1,4 +1,4 @@
from dsst_gtk3 import dialogs, gtk_ui
from dsst_gtk3 import dialogs, gtk_ui, reload
class SeasonHandlers:
@@ -7,12 +7,14 @@ class SeasonHandlers:
self.app = app
def do_add_season(self, *_):
name = dialogs.enter_string_dialog(self.app.ui, 'Name for the new Season')
if name:
season = dialogs.edit_season(self.app.ui)
if season:
self.app.update_season(season)
self.app.reload()
def do_season_selected(self, *_):
self.app.season_changed = True
self.app.episodes.valid = False
self.app.season_stats.valid = False
self.app.reload()
def do_add_episode(self, *_):
@@ -23,8 +25,7 @@ class SeasonHandlers:
self.app.reload()
def on_selected_episode_changed(self, *_):
self.app.ep_changed = True
self.app.reload()
reload.reload_episode_stats(self.app)
def on_episode_double_click(self, *_):
self.app.ui.get_object('stats_notebook').set_current_page(1)

View File

@@ -10,11 +10,11 @@ def reload_base_data(builder: Gtk.Builder, app: 'gtk_ui.GtkUi',):
"""
# Rebuild all players store
builder.get_object('all_players_store').clear()
for player in app.data['players']:
for player in app.players.data:
builder.get_object('all_players_store').append([player.id, player.name, player.hex_id])
# Rebuild drink store
builder.get_object('drink_store').clear()
for drink in app.data['drinks']:
for drink in app.drinks.data:
builder.get_object('drink_store').append([drink.id, drink.name, '{:.2f}%'.format(drink.vol)])
# Rebuild seasons store
combo = builder.get_object('season_combo_box') # type: Gtk.ComboBox
@@ -22,7 +22,7 @@ def reload_base_data(builder: Gtk.Builder, app: 'gtk_ui.GtkUi',):
with util.block_handler(combo, app.handlers.do_season_selected):
store = builder.get_object('seasons_store')
store.clear()
for season in app.data['seasons']:
for season in app.seasons.data:
store.append([season.id, season.game_name])
combo.set_active(active)
@@ -37,7 +37,7 @@ def reload_episodes(builder: Gtk.Builder, app: 'gtk_ui.GtkUi'):
with util.block_handler(selection, app.handlers.on_selected_episode_changed):
model, selected_paths = selection.get_selected_rows()
model.clear()
for episode in app.data['episodes']:
for episode in app.episodes.data:
model.append([episode.id, episode.name, str(episode.date), episode.number])
if selected_paths:
selection.select_path(selected_paths[0])
@@ -47,7 +47,7 @@ def reload_season_stats(app: 'gtk_ui.GtkUi'):
"""Load statistic data for selected season
:param app: GtkUi instance
"""
season_stats = app.data.get('season_stats')
season_stats = app.season_stats.data
# Load player kill/death data
store = app.ui.get_object('player_season_store')
store.clear()
@@ -65,7 +65,7 @@ def reload_episode_stats(app: 'gtk_ui.GtkUi'):
"""Reload all data that is dependant on a selected episode
:param app: app: GtkUi instance
"""
episode = [ep for ep in app.data['episodes'] if ep.id == app.get_selected_episode_id()][0]
episode = [ep for ep in app.episodes.data if ep.id == app.get_selected_episode_id()][0]
store = app.ui.get_object('episode_players_store')
store.clear()
for player in episode.players:
@@ -75,7 +75,7 @@ def reload_episode_stats(app: 'gtk_ui.GtkUi'):
store.clear()
for death in episode.deaths:
penalties = [x.drink.name for x in death.penalties]
penalties = [f'{number}x {drink}' for drink, number in Counter(penalties).items()]
penalties = ['{}x {}'.format(number, drink) for drink, number in Counter(penalties).items()]
penalty_string = ', '.join(penalties)
store.append([death.id, death.player.name, death.enemy.name, penalty_string])
# Reload victory store for notebook view
@@ -100,7 +100,7 @@ def reload_episode_stats(app: 'gtk_ui.GtkUi'):
sorted_list = Counter(enemy_list).most_common(1)
if sorted_list:
enemy_name, deaths = sorted_list[0]
app.ui.get_object('ep_enemy_name_label').set_text(f'{enemy_name} ({deaths} Deaths)')
app.ui.get_object('ep_enemy_name_label').set_text('{} ({} Deaths)'.format(enemy_name, deaths))
def fill_list_store(store: Gtk.ListStore, models: list):

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.3 -->
<!-- Generated with glade 3.20.4 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<requires lib="gtk+" version="3.16"/>
<object class="GtkDialog" id="nameEnterDialog">
<property name="can_focus">False</property>
<property name="resizable">False</property>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.4 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<requires lib="gtk+" version="3.16"/>
<object class="GtkListStore" id="all_players_store">
<columns>
<!-- column-name id -->
@@ -1591,23 +1591,7 @@
</packing>
</child>
<child>
<object class="GtkButton" id="add_season_button">
<property name="label" translatable="yes">New</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<signal name="clicked" handler="do_add_season" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
<placeholder/>
</child>
</object>
<packing>
@@ -1665,23 +1649,7 @@
</packing>
</child>
<child>
<object class="GtkButton" id="add_episode_button">
<property name="label" translatable="yes">New</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<signal name="clicked" handler="do_add_episode" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
<placeholder/>
</child>
</object>
<packing>
@@ -2573,4 +2541,339 @@
<placeholder/>
</child>
</object>
<object class="GtkDialog" id="date_picker_dialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Pick Date</property>
<property name="resizable">False</property>
<property name="default_width">300</property>
<property name="type_hint">dialog</property>
<property name="deletable">False</property>
<property name="transient_for">main_window</property>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button3">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button6">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Pick Date</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="date_today_buton">
<property name="label" translatable="yes">Today</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="do_set_today" object="date_picker_calendar" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCalendar" id="date_picker_calendar">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="year">2018</property>
<property name="month">2</property>
<property name="day">9</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-5">button3</action-widget>
<action-widget response="-6">button6</action-widget>
</action-widgets>
<child>
<placeholder/>
</child>
</object>
<object class="GtkDialog" id="edit_season_dialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Edit Season</property>
<property name="resizable">False</property>
<property name="type_hint">dialog</property>
<property name="deletable">False</property>
<property name="transient_for">main_window</property>
<property name="attached_to">main_window</property>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button4">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button5">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Season Number:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="season_number_spin">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="input_purpose">digits</property>
<property name="adjustment">ep_number_ajustment</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Game Name:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="season_game_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Start Date:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="season_start_entry">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="secondary_icon_stock">gtk-edit</property>
<signal name="icon-press" handler="do_show_date_picker" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">End Date:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="season_end_entry">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="secondary_icon_stock">gtk-edit</property>
<signal name="icon-press" handler="do_show_date_picker" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-5">button4</action-widget>
<action-widget response="-6">button5</action-widget>
</action-widgets>
<child>
<placeholder/>
</child>
</object>
</interface>

View File

@@ -16,11 +16,26 @@ DEFAULT_CONFIG = {
'host': 'localhost',
'port': 12345,
'buffer_size': 1024,
'auth_token': 'a'}
'auth_token': ''}
]
}
class Cache:
def __init__(self, data={}, valid=False):
self._data = data
self.valid = valid
@property
def data(self):
return self._data
@data.setter
def data(self, value):
self._data = value
self.valid = True
@contextmanager
def block_handler(widget: 'Gtk.Widget', handler_func: Callable):
"""Run an operation while a signal handler for a widget is blocked
@@ -35,7 +50,7 @@ def block_handler(widget: 'Gtk.Widget', handler_func: Callable):
@contextmanager
def network_operation(app: 'gtk_ui.GtkUi'):
"""Run operation in try/except block and display exception in a dialog
:param exception:
:param app: Reference to main Gtk Application
"""
app.ui.get_object('status_bar').push(0, 'Connecting to server')
try:
@@ -47,7 +62,6 @@ def network_operation(app: 'gtk_ui.GtkUi'):
app.ui.get_object('status_bar').push(0, '')
def get_combo_value(combo, index: int):
""" Retrieve the selected value of a combo box at the selected index in the model
:param combo: Any Gtk Widget that supports 'get_active_iter()'

View File

@@ -1,8 +1,20 @@
from common import models
from dsst_server.data_access import sql
class WriteFunctions:
@staticmethod
def create_season(season: 'models.Season'):
return 'Season created.'
@staticmethod
def update_season(season: 'models.Season', *_):
(sql.Season
.insert(id=season.id, number=season.number, game_name=season.game_name, start_date=season.start_date,
end_date=season.end_date)
.on_conflict(
update={sql.Season.number: season.number,
sql.Season.game_name: season.game_name,
sql.Season.start_date: season.start_date,
sql.Season.end_date: season.end_date})
.execute())

View File

@@ -62,7 +62,7 @@ class DsstServer:
if action_name in self.tokens[token]:
action = getattr(FunctionProxy, action_name)
try:
value = action(request.get('args'))
value = action(*request.get('args'))
except Exception as e:
response = {'success': False, 'message': 'Exception was thrown on server.\n{}'.format(e)}
util.send_msg(client, pickle.dumps(response))