from utils.utils import getchar, is_valid_date, siege_week from utils.hackatime import Client from rich.console import Console from rich.table import Table from datetime import date import sys, os, json class CLI(): def __init__(self): self.hackatime_client = Client() if os.path.exists("data.json"): with open("data.json", "r") as file: self.data = json.load(file) else: self.data = {"goals": {}, "coffers": 0, "bought_items": [], "projects": {}} def save_data(self): with open("data.json", "w") as file: file.write(json.dumps(self.data, indent=4)) def wait_for_input(self, text): print(text) return getchar() def wait_for_exit(self): print() self.wait_for_input("Press any key to exit ") os.system('cls' if os.name == 'nt' else 'clear') def command_wait(self, text, options: dict): selected_option = '' while selected_option not in options: print(text) selected_option = self.wait_for_input("Select an option: ") os.system('cls' if os.name == 'nt' else 'clear') options[selected_option]() def render_logo(self): from utils.constants import LOGO_ASCII_ART, PROJECT_INFO print(LOGO_ASCII_ART, 0.01) print(PROJECT_INFO) def home(self, start=False): os.system('cls' if os.name == 'nt' else 'clear') if start: self.render_logo() from utils.constants import HOME_SCREEN self.command_wait(HOME_SCREEN.format(siege_week=siege_week()), {"q": sys.exit, "t": lambda: self.stats_screen(True), "a": self.stats_screen, "p": self.projects, "g": self.goals, "h": self.shop, "s": self.statistics, "c": self.calendar}) def statistics(self): print("Comming Soon!") self.wait_for_exit() self.home() def calendar(self): print("Comming Soon!") self.wait_for_exit() self.home() def projects(self): print("Due to platform limitations, you have to add your projects from Hackatime manually. Sorry about this.") print("Loading Hackatime stats...") data = self.hackatime_client.get_stats() if self.data["projects"]: console = Console() table = Table(title=f"Top Project: {data[2]} | Total time: {data[4]}") table.add_column("Project", style="cyan", no_wrap=True) table.add_column("Time", style="magenta") table.add_column("Percent", justify="right", style="green") table.add_column("Coffers", justify="right", style="yellow") table.add_column("Ship Count", justify="right", style="blue") for project, time, percent in data[3]: if project in self.data["projects"]: table.add_row(project, str(time), f"{percent}%", str(self.data["projects"][project]["total_coffers"]), str(len(self.data["projects"][project]["ship_events"]))) console.print(table) else: print("You dont have any Siege projects.") self.command_wait("""You can do the following: a - Add project from Hackatime c - Create ship event to add coffers q - Exit to home""", {"a": self.add_project, "q": self.home, "c": self.create_ship_event}) def create_ship_event(self): print("Loading Hackatime stats...") data = self.hackatime_client.get_stats() if self.data["projects"]: console = Console() table = Table(title=f"Top Project: {data[2]} | Total time: {data[4]}") table.add_column("Project", style="cyan", no_wrap=True) table.add_column("Time", style="magenta") table.add_column("Percent", justify="right", style="green") table.add_column("Coffers", justify="right", style="yellow") table.add_column("Ship Count", justify="right", style="blue") for project, time, percent in data[3]: if project in self.data["projects"]: table.add_row(project, str(time), f"{percent}%", str(self.data["projects"][project]["total_coffers"]), str(len(self.data["projects"][project]["ship_events"]))) console.print(table) else: print("You dont have any Siege projects.") self.wait_for_exit() self.projects() return valid_project_names = [project_data[0] for project_data in data[3]] project_name = '' while project_name not in valid_project_names: project_name = input("To add a ship event, please put the project's name here: ") coffer_amount = '' while not coffer_amount.isnumeric() or coffer_amount >= 999: coffer_amount = input("Please enter the amount of coffers you got for the ship: ") coffer_amount = int(coffer_amount) hour_amount = '' while not hour_amount.isnumeric(): hour_amount = input("Please enter the amount of hours you did for the ship: ") hour_amount = int(hour_amount) ship_date = '' while not is_valid_date(ship_date): ship_date = input("Please enter the date of ship (format YYYY-MM-DD): ") self.data["projects"][project_name]["ship_events"].append((ship_date, coffer_amount, hour_amount)) self.data["projects"][project_name]["total_coffers"] += coffer_amount self.data["coffers"] += coffer_amount self.save_data() print(f"Succesfully added ship event to {project_name} on date {ship_date} for {hour_amount} hours and {coffer_amount} coffers!") self.wait_for_exit() self.projects() def add_project(self): print("Here are your Hackatime projects starting from September 1th, 2025.") print("Loading Hackatime stats...") data = self.hackatime_client.get_stats() console = Console() table = Table(title=f"Top Project: {data[2]} | Total time: {data[4]}") table.add_column("Project", style="cyan", no_wrap=True) table.add_column("Time", style="magenta") table.add_column("Percent", justify="right", style="green") for project, time, percent in data[3]: if not project in self.data["projects"]: table.add_row(project, str(time), f"{percent}%") console.print(table) valid_project_names = [project_data[0] for project_data in data[3]] project_name = '' while project_name not in valid_project_names: project_name = input("To add a project, please put its name here: ") self.data["projects"][project_name] = {"ship_events": [], "total_coffers": 0} self.save_data() print(f"Project {project_name} succesfully added to Siege projects!") self.wait_for_exit() self.projects() def stats_screen(self, today=False): print("Loading Hackatime stats...") data = self.hackatime_client.get_stats_for_today() if today else self.hackatime_client.get_stats() console = Console() table = Table(title=f"Top Language: {data[0]} | Total time: {data[4]}") table.add_column("Language", style="cyan", no_wrap=True) table.add_column("Time", style="magenta") table.add_column("Percent", justify="right", style="green") for lang, time, percent in data[1]: table.add_row(lang, str(time), f"{percent}%") console.print(table) self.wait_for_exit() self.home() def goals(self): from utils.constants import GOALS_SCREEN self.command_wait(GOALS_SCREEN.format(goals=self.data["goals"]), {"a": self.add_goal, "r": self.remove_goal, "q": self.home}) def add_goal(self): print("Loading Hackatime stats...") stats = self.hackatime_client.get_stats(end_date=self.hackatime_client.get_date()) goal_name = None while goal_name in self.data["goals"] or goal_name == None: goal_name = input("Goal Name (Cant exist already): ") goal_type = '' while goal_type not in ["coffers", "hours"]: goal_type = input("Goal Type (coffers/hours): ") goal_date = '' while not is_valid_date(goal_date): goal_date = input("Date to complete goal in (format: YYYY-MM-DD): ") goal_number = '' while not goal_number.isnumeric(): goal_number = input(f"Amount of {goal_type}: ") goal_number = int(goal_number) os.system('cls' if os.name == 'nt' else 'clear') remaining_days = (date(*map(int, goal_date.split("-"))) - date.today()).days print(f"You have {remaining_days} remaining days of siege to complete this goal!") if goal_type == "coffers": if self.data["coffers"] > goal_number: print("Goal already completed, skipping...") return print(f"You need {goal_number - self.data['data']['coffers']} more coffers to complete this goal!") elif goal_type == "hours": if stats[5] / 3600 > goal_number: print("Goal already completed, skipping...") return difference = goal_number - (stats[5] / 3600) daily_average_hours = (stats[7] / 3600) print(f"You need {round(difference, 1)} more hours to complete this goal!") print(f"Your daily average time is {stats[6]}") if difference > remaining_days * daily_average_hours: print(f"If you don't hurry up, you cant complete this goal!\nWith your current daily average, you would complete it in {round(difference / daily_average_hours, 1)} days!") else: print(f"With your daily average time, you can complete this goal this in {round(difference / daily_average_hours, 1)} days!") self.data["goals"][goal_name] = [goal_date, goal_type, goal_number] self.save_data() self.wait_for_exit() self.home() def remove_goal(self): goal_name = '' while goal_name not in self.data["goals"]: goal_name = input("Goal Name To Remove: ") del self.data["goals"][goal_name] self.save_data() def shop(self): from utils.constants import SHOP_SCREEN, shop_items print(SHOP_SCREEN) console = Console() table = Table(title=f"Shop | Coffers: {self.data['coffers']}") table.add_column("ID", style="cyan", no_wrap=True) table.add_column("Name", style="cyan", no_wrap=True) table.add_column("Price", style="magenta") table.add_column("Comment", justify="right", style="green") table.add_column("Stock", justify="right", style="yellow") n = 0 for name, comment, price, stock in shop_items: table.add_row(str(n), name, str(price), comment, str(stock)) n += 1 console.print(table) self.command_wait("""Please press one of the following keys to interact! b - Buy item q - Exit to home""", {"b": self.buy_item, "q": self.home}) def buy_item(self): from utils.constants import shop_items console = Console() table = Table(title=f"Shop | Coffers: {self.data['coffers']}") table.add_column("ID", style="cyan", no_wrap=True) table.add_column("Name", style="cyan", no_wrap=True) table.add_column("Price", style="magenta") table.add_column("Comment", justify="right", style="green") table.add_column("Stock", justify="right", style="yellow") n = 0 for name, comment, price, stock in shop_items: table.add_row(str(n), name, str(price), comment, str(stock - self.data["bought_items"].count(name))) n += 1 console.print(table) item_id = "" while not item_id.isnumeric() or not int(item_id) <= len(shop_items): item_id = input("Enter an item ID to buy: ") item_id = int(item_id) if shop_items[item_id][3] - self.data["bought_items"].count(name) < 1: print("There is no stock left for the item.") self.wait_for_exit() self.shop() return if not self.data["coffers"] >= shop_items[item_id][2]: print("You don't have enough coffers to buy this item.") print(f"You need {shop_items[item_id][2] - self.data['coffers']} more coffers!") self.wait_for_exit() self.shop() return print(f"You successfully bought the {shop_items[item_id][0]} item!") self.data["coffers"] -= shop_items[item_id][2] self.data["bought_items"].append(shop_items[item_id][0]) self.save_data() print(f"You now have {self.data['coffers']} remaining coffers!") self.wait_for_exit() self.shop() def run_cli(): cli = CLI() cli.home(start=True)