Skip to content
This repository has been archived by the owner on Jul 11, 2023. It is now read-only.

New tab for counting gameplay statistics #514

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cddagl/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@
CONFIG_BRANCH_STABLE = 'stable'
CONFIG_BRANCH_EXPERIMENTAL = 'experimental'

DURATION_FORMAT = '{D:02}d {H:02}h {M:02}m {S:02}s'

### Path to Dirs and Files used in CDDAGL
### TODO: (kurzed) centralize here and then move to a better place?
Expand Down
52 changes: 51 additions & 1 deletion cddagl/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
from cddagl.i18n import proxy_gettext as _
from cddagl.sql.functions import get_config_value, config_true

from string import Formatter
from datetime import timedelta

version = cddagl.__version__
logger = logging.getLogger('cddagl')

Expand Down Expand Up @@ -150,4 +153,51 @@ def safe_humanize(arrow_date, other=None, locale='en_us', only_distance=False, g
except ValueError:
# On final fail, use en_us locale which should be translated
return arrow_date.humanize(other=other, locale='en_us', only_distance=only_distance,
granularity='auto')
granularity='auto')

def strfdelta(tdelta, fmt='{D:02}d {H:02}h {M:02}m {S:02}s', inputtype='timedelta'):
"""Convert a datetime.timedelta object or a regular number to a custom-
formatted string, just like the stftime() method does for datetime.datetime
objects.

The fmt argument allows custom formatting to be specified. Fields can
include seconds, minutes, hours, days, and weeks. Each field is optional.

Some examples:
'{D:02}d {H:02}h {M:02}m {S:02}s' --> '05d 08h 04m 02s' (default)
'{W}w {D}d {H}:{M:02}:{S:02}' --> '4w 5d 8:04:02'
'{D:2}d {H:2}:{M:02}:{S:02}' --> ' 5d 8:04:02'
'{H}h {S}s' --> '72h 800s'

The inputtype argument allows tdelta to be a regular number instead of the
default, which is a datetime.timedelta object. Valid inputtype strings:
's', 'seconds',
'm', 'minutes',
'h', 'hours',
'd', 'days',
'w', 'weeks'
"""

# Convert tdelta to integer seconds.
if inputtype == 'timedelta':
remainder = int(tdelta.total_seconds())
elif inputtype in ['s', 'seconds']:
remainder = int(tdelta)
elif inputtype in ['m', 'minutes']:
remainder = int(tdelta)*60
elif inputtype in ['h', 'hours']:
remainder = int(tdelta)*3600
elif inputtype in ['d', 'days']:
remainder = int(tdelta)*86400
elif inputtype in ['w', 'weeks']:
remainder = int(tdelta)*604800

f = Formatter()
desired_fields = [field_tuple[1] for field_tuple in f.parse(fmt)]
possible_fields = ('W', 'D', 'H', 'M', 'S')
constants = {'W': 604800, 'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
values = {}
for field in possible_fields:
if field in desired_fields and field in constants:
values[field], remainder = divmod(remainder, constants[field])
return f.format(fmt, **values)
13 changes: 13 additions & 0 deletions cddagl/ui/views/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ def __init__(self):
layout.addWidget(update_group_box)
self.setLayout(layout)

self.played = 0

def set_text(self):
self.game_dir_group_box.set_text()
self.update_group_box.set_text()
Expand All @@ -85,6 +87,9 @@ def get_mods_tab(self):
def get_backups_tab(self):
return self.parentWidget().parentWidget().backups_tab

def get_statistics_tab(self):
return self.parentWidget().parentWidget().statistics_tab

def disable_tab(self):
self.game_dir_group_box.disable_controls()
self.update_group_box.disable_controls(True)
Expand Down Expand Up @@ -452,6 +457,8 @@ def launch_game_process(self):
settings_tab.disable_tab()
backups_tab.disable_tab()

statistics_tab = main_tab.get_statistics_tab()

self.launch_game_button.setText(_('Show current game'))
self.launch_game_button.setEnabled(True)

Expand All @@ -477,6 +484,8 @@ def process_ended():
process_wait_thread.ended.connect(process_ended)
process_wait_thread.start()

statistics_tab.game_started()

self.process_wait_thread = process_wait_thread

def game_ended(self):
Expand All @@ -487,6 +496,10 @@ def game_ended(self):
self.game_process = None
self.game_started = False

main_tab = self.get_main_tab()
statistics_tab = main_tab.get_statistics_tab()
statistics_tab.game_ended()

main_window = self.get_main_window()
status_bar = main_window.statusBar()

Expand Down
151 changes: 151 additions & 0 deletions cddagl/ui/views/statistics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import logging
from datetime import datetime
from cddagl.functions import strfdelta
from cddagl.constants import DURATION_FORMAT

from PyQt5.QtCore import (
Qt, QTimer
)
from PyQt5.QtWidgets import (
QTabWidget, QGroupBox, QGridLayout, QLabel, QVBoxLayout, QPushButton
)
from cddagl.sql.functions import get_config_value, set_config_value

logger = logging.getLogger('cddagl')

class StatisticsTab(QTabWidget):
def __init__(self):
super(StatisticsTab, self).__init__()

self.game_start_time = None
self.last_game_duration = get_config_value('last_played', 0)

current_played_group_box = CurrentPlayedGroupBox()
self.current_played_group_box = current_played_group_box
self.reset_current_button = current_played_group_box.reset_current_button

total_game_duration_group_box = TotalPlayedGroupBox()
self.total_game_duration_group_box = total_game_duration_group_box
self.reset_total_button = total_game_duration_group_box.reset_total_button

layout = QVBoxLayout()
layout.addWidget(current_played_group_box)
layout.addWidget(total_game_duration_group_box)
self.setLayout(layout)

def set_text(self):
self.current_played_group_box.set_text()
self.current_played_group_box.set_label_text()
self.total_game_duration_group_box.set_text()

def get_main_window(self):
return self.parentWidget().parentWidget().parentWidget()

def get_main_tab(self):
return self.parentWidget().parentWidget().main_tab

def game_started(self):
self.game_start_time = datetime.now()
game_timer = QTimer()
game_timer.setInterval(1000)
game_timer.timeout.connect(self.game_tick)
self.game_timer = game_timer
game_timer.start()
self.reset_current_button.setEnabled(False)
self.reset_total_button.setEnabled(False)

def game_ended(self):
total_game_duration = int(get_config_value('total_played',0))
total_game_duration += self.last_game_duration
set_config_value('last_played', self.last_game_duration)
set_config_value('total_played', total_game_duration)
self.game_start_time = None
self.game_timer.stop()
self.reset_current_button.setEnabled(True)
self.reset_total_button.setEnabled(True)

def game_tick(self):
elapsed = int(datetime.now().timestamp() - self.game_start_time.timestamp())
self.last_game_duration = elapsed
self.current_played_group_box.set_label_text()
self.total_game_duration_group_box.set_label_text()

class CurrentPlayedGroupBox(QGroupBox):
def __init__(self):
super(CurrentPlayedGroupBox, self).__init__()

layout = QGridLayout()

current_played_label = QLabel()
current_played_label.setStyleSheet("font-size: 32px;")
layout.addWidget(current_played_label, 0, 0, Qt.AlignHCenter)
self.current_played_label = current_played_label

reset_current_button = QPushButton()
reset_current_button.setStyleSheet("font-size: 20px;")
reset_current_button.clicked.connect(self.reset_current)
layout.addWidget(reset_current_button, 1, 0, Qt.AlignHCenter)
self.reset_current_button = reset_current_button

self.setLayout(layout)
self.set_text()

def reset_current(self):
self.parentWidget().last_game_duration = 0
set_config_value('last_played', 0)
self.set_label_text()

def get_main_tab(self):
return self.parentWidget().get_main_tab()

def set_text(self):
self.reset_current_button.setText(_('RESET'))
last_game_duration = int(get_config_value('last_played', 0))
fmt_last_game_duration = strfdelta(last_game_duration, _(DURATION_FORMAT), inputtype='s')
self.current_played_label.setText(fmt_last_game_duration)
self.setTitle(_('Last game duration:'))

def set_label_text(self):
last_game_duration = self.parentWidget().last_game_duration
fmt_last_game_duration = strfdelta(last_game_duration, _(DURATION_FORMAT), inputtype='s')
self.current_played_label.setText(fmt_last_game_duration)


class TotalPlayedGroupBox(QGroupBox):
def __init__(self):
super(TotalPlayedGroupBox, self).__init__()

layout = QGridLayout()

total_game_duration_label = QLabel()
total_game_duration_label.setStyleSheet("font-size: 32px;")
layout.addWidget(total_game_duration_label, 0, 0, Qt.AlignHCenter)
self.total_game_duration_label = total_game_duration_label

reset_total_button = QPushButton()
reset_total_button.setStyleSheet("font-size: 20px;")
reset_total_button.clicked.connect(self.reset_total)
layout.addWidget(reset_total_button, 1, 0, Qt.AlignHCenter)
self.reset_total_button = reset_total_button

self.setLayout(layout)
self.set_text()

def reset_total(self):
set_config_value('total_played', 0)
self.set_label_text()

def get_main_tab(self):
return self.parentWidget().get_main_tab()

def set_text(self):
self.reset_total_button.setText(_('RESET'))
total_game_duration = int(get_config_value('total_played', 0))
fmt_total_game_duration = strfdelta(total_game_duration, _(DURATION_FORMAT), inputtype='s')
self.total_game_duration_label.setText(fmt_total_game_duration)
self.setTitle(_('Total time in game:'))

def set_label_text(self):
total_game_duration = int(get_config_value('total_played', 0)) + int(self.parentWidget().last_game_duration)
fmt_total_game_duration = strfdelta(total_game_duration, _(DURATION_FORMAT), inputtype='s')
self.total_game_duration_label.setText(fmt_total_game_duration)
9 changes: 9 additions & 0 deletions cddagl/ui/views/tabbed.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from cddagl.ui.views.settings import SettingsTab
from cddagl.ui.views.soundpacks import SoundpacksTab
from cddagl.ui.views.tilesets import TilesetsTab
from cddagl.ui.views.statistics import StatisticsTab
from cddagl.win32 import SimpleNamedPipe

logger = logging.getLogger('cddagl')
Expand Down Expand Up @@ -424,6 +425,7 @@ def __init__(self):
self.create_soundpacks_tab()
#self.create_fonts_tab()
self.create_settings_tab()
self.create_statistics_tab()

def set_text(self):
self.setTabText(self.indexOf(self.main_tab), _('Main'))
Expand All @@ -433,6 +435,7 @@ def set_text(self):
self.setTabText(self.indexOf(self.soundpacks_tab), _('Soundpacks'))
#self.setTabText(self.indexOf(self.fonts_tab), _('Fonts'))
self.setTabText(self.indexOf(self.settings_tab), _('Settings'))
self.setTabText(self.indexOf(self.statistics_tab), _('Statistics'))

self.main_tab.set_text()
self.backups_tab.set_text()
Expand All @@ -441,6 +444,7 @@ def set_text(self):
self.soundpacks_tab.set_text()
#self.fonts_tab.set_text()
self.settings_tab.set_text()
self.statistics_tab.set_text()

def create_main_tab(self):
main_tab = MainTab()
Expand Down Expand Up @@ -477,6 +481,11 @@ def create_settings_tab(self):
self.addTab(settings_tab, _('Settings'))
self.settings_tab = settings_tab

def create_statistics_tab(self):
statistics_tab = StatisticsTab()
self.addTab(statistics_tab, _('Statistics'))
self.statistics_tab = statistics_tab


class LauncherUpdateDialog(QDialog):
def __init__(self, url, version, parent=0, f=0):
Expand Down