Skip to content

Commit

Permalink
docs(README.md): update download section with direct download link fo…
Browse files Browse the repository at this point in the history
…r better user experience

docs(README.md): enhance 'How to use Genzai?' section with more detailed steps for better understanding

refactor(genzai.py): rename 'client_id' to 'app_id' for better clarity
feat(genzai.py): add separate resizable options for X and Y axis
feat(genzai.py): add 'ERROR' color to STYLE dictionary
feat(genzai.py): set appearance mode to 'dark'
refactor(genzai.py): rename 'state' to 'party_state' for better context
refactor(genzai.py): rename 'label_error_state' to 'label_app_state' and modify its functionality to display general app messages
feat(genzai.py): add validation for large and small image settings
feat(genzai.py): add success message on successful presence update
refactor(genzai.py): rename 'set_error' to 'set_app_label' and modify its functionality to display messages with customizable color
refactor(genzai.py): rename 'validate_and_set_error' to 'validate_and_set_app_label' and modify its functionality to work with the updated 'set_app_label' method
  • Loading branch information
dinogomez committed Jun 8, 2024
1 parent 8cd02ce commit 2f7458e
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 54 deletions.
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ A lightweight Discord custom Rich Presence manager that runs on Linux and Window
<p align="center">
<img src="https://github.com/dinogomez/genzai/assets/41871666/0d384431-5226-491f-baca-8a1c075b06ce">

## Download
# Download

### Latest
### Latest [DOWNLOAD HERE](https://github.com/dinogomez/genzai/releases/tag/Latest)

The latest official release of Genzai is available for both Linux and Windows. Check the [Genzai Latest Release](https://github.com/dinogomez/genzai/releases/tag/Latest).

Expand All @@ -18,12 +18,14 @@ The latest official release of Genzai is available for both Linux and Windows. C

## How to use Genzai?

1. Make a new Discord application [here](https://discord.com/developers/applications).
2. Copy the `Client ID` and paste it in the `Client ID` field in Genzai.
3. Click `Connect`
4. Fill out the fields you want.
5. Click `Update`
6. Enjoy your new Discord Rich Presence!
1. Make a new Discord application, here in the [Discord Developer Portal](https://discord.com/developers/applications).
2. Click `New Application` on the top right.
3. Create your application name, this will be your `title` in your Discord Presence.
4. Copy the `Application ID` and paste it in the `App ID` field in Genzai.
5. Click `Connect`
6. Fill out the fields you want.
7. Click `Update`
8. Enjoy your new Discord Rich Presence!

## How to build Genzai from source

Expand Down
105 changes: 59 additions & 46 deletions genzai/genzai.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"APP_ICON": "assets/icon.png",
"APP_LOGO": "assets/logo.png",
"APP_GEOMETRY": "520x480",
"APP_RESIZABLE": False,
"APP_RESIZABLE_X": False,
"APP_RESIZABLE_Y": False,
"APP_DIMENSION": "520x480",
}

Expand All @@ -36,7 +37,8 @@
"NORMAL": "#2fa572",
"DISABLED": "#0e5637",
"ENTRY": "#343638",
"ENTRY_DISABLED": "#28292a"
"ENTRY_DISABLED": "#28292a",
"ERROR": "red"
}


Expand All @@ -61,9 +63,9 @@ class DiscordRPC:
def __init__(self):
self.RPC = Presence(None)

def connect(self, client_id):
def connect(self, app_id):
try:
self.RPC = Presence(client_id)
self.RPC = Presence(app_id)
self.RPC.connect()
self.RPC.update(state="Launching Genzai 🚀",
details="A user is preparing his presence.", start=int(time.time()))
Expand Down Expand Up @@ -102,22 +104,23 @@ def __init__(self):

# App Configs
ctk.set_default_color_theme("green")
ctk.set_appearance_mode("dark")
self.title(CONFIG["APP_TITLE"])
self.geometry(CONFIG["APP_DIMENSION"])
self.resizable(False, False)
self.resizable(CONFIG["APP_RESIZABLE_X"], CONFIG["APP_RESIZABLE_Y"])

# App Main Frame [Frame]
self.frame = ctk.CTkFrame(master=self)
self.frame.grid_columnconfigure((0, 1), weight=1)
self.frame.pack(padx=10, pady=10, fill="x")

# Client ID [Label,Entry]@Grid
self.label_client_id = ctk.CTkLabel(
self.frame, text="Client ID", font=("Consolas", 12))
self.label_client_id.grid(row=0, column=0, padx=5, pady=5)
# App [Label,Entry]@Grid
self.label_app_id = ctk.CTkLabel(
self.frame, text="App ID", font=("Consolas", 12))
self.label_app_id.grid(row=0, column=0, padx=5, pady=5)

self.entry_client_id = ctk.CTkEntry(self.frame)
self.entry_client_id.grid(
self.entry_app_id = ctk.CTkEntry(self.frame)
self.entry_app_id.grid(
row=0, column=1, columnspan=3, padx=5, pady=5, sticky="we")

# Connect [Button:connect()]@Grid
Expand All @@ -140,13 +143,13 @@ def __init__(self):
row=1, column=1, columnspan=5, padx=5, pady=5, sticky="ew")

# Party State [Label, Entry]@Grid
self.label_state = ctk.CTkLabel(
self.label_party_state = ctk.CTkLabel(
self.frame, text="State", font=("Consolas", 12))
self.label_state.grid(row=2, column=0, padx=5, pady=5)
self.label_party_state.grid(row=2, column=0, padx=5, pady=5)

self.entry_state = ctk.CTkEntry(self.frame)
self.entry_state.grid(row=2, column=1, columnspan=2,
padx=5, pady=5, sticky="we")
self.entry_party_state = ctk.CTkEntry(self.frame)
self.entry_party_state.grid(row=2, column=1, columnspan=2,
padx=5, pady=5, sticky="we")

# Party [Label]@Grid
self.label_party = ctk.CTkLabel(
Expand Down Expand Up @@ -295,25 +298,25 @@ def __init__(self):
self.label_connection_state.pack(padx=15, pady=(0, 5), side="right")

# Error State [Label]@Pack
self.label_error_state = ctk.CTkLabel(
master=self, text="", text_color="red", font=("Consolas", 12),)
self.label_error_state.pack(pady=(0, 5), padx=15, side="left")
self.label_app_state = ctk.CTkLabel(
master=self, text="", font=("Consolas", 12),)
self.label_app_state.pack(pady=(0, 5), padx=15, side="left")

# Vars
self.isConnected = False

def update(self):

# Reset any existing error message
self.set_error("")
self.set_app_label("")

# Init
self.timestamp = ""
self.buttons = []

# Fetch the values from the entries
self.details = self.entry_details.get()
self.party_state = self.entry_state.get()
self.party_state = self.entry_party_state.get()
self.party_min = self.entry_party_min.get()
self.party_max = self.entry_party_max.get()
self.large_img_url = self.entry_large_image_url.get()
Expand All @@ -326,39 +329,47 @@ def update(self):
self.button_two_url = self.entry_button_two_url.get()

# Validate required fields for minimum length
if self.validate_and_set_error(self.invalid_length(value=self.details), "Details needs 2 or more characters."):
if self.validate_and_set_app_label(self.invalid_length(value=self.details), "Details needs 2 or more characters."):
return
if self.validate_and_set_error(self.invalid_length(value=self.party_state), "Party State needs 2 or more characters."):
if self.validate_and_set_app_label(self.invalid_length(value=self.party_state), "Party State needs 2 or more characters."):
return
if self.validate_and_set_error(self.invalid_length(value=self.large_img_txt), "Large Image Text needs 2 or more characters."):
if self.validate_and_set_app_label(self.invalid_length(value=self.large_img_txt), "Large Image Text needs 2 or more characters."):
return
if self.validate_and_set_error(self.invalid_length(value=self.small_img_txt), "Small Image Text needs 2 or more characters."):
if self.validate_and_set_app_label(self.invalid_length(value=self.small_img_txt), "Small Image Text needs 2 or more characters."):
return

# Validate party settings
if self.party_min:
if self.validate_and_set_error(not self.party_state, "Party number needs a state."):
if self.validate_and_set_app_label(not self.party_state, "Party number needs a state."):
return
if self.validate_and_set_error(not self.party_max, "Max is required."):
if self.validate_and_set_app_label(not self.party_max, "Max is required."):
return
if self.validate_and_set_error(int(self.party_min) > int(self.party_max), "Min must not exceed Max"):
if self.validate_and_set_app_label(int(self.party_min) > int(self.party_max), "Min must not exceed Max"):
return

# Validate large image settings
if self.validate_and_set_app_label(self.large_img_url and not self.large_img_txt, "Large Image URL requires Large Image Text."):
return

# Validate small image settings
if self.validate_and_set_app_label(self.small_img_url and not self.small_img_txt, "Small Image URL requires Small Image Text."):
return

# Validate button settings
if self.button_one_url:
if self.button_one_txt:
self.buttons.append(
{"url": self.button_one_url, "label": self.button_one_txt})
else:
self.set_error("Button 1 needs a label.")
self.set_app_label("Button 1 needs a label.")
return

if self.button_two_url:
if self.button_two_txt:
self.buttons.append(
{"url": self.button_two_url, "label": self.button_two_txt})
else:
self.set_error("Button 2 needs a label.")
self.set_app_label("Button 2 needs a label.")
return

# Parse custom timestamp if selected in combobox
Expand All @@ -371,7 +382,7 @@ def update(self):
custom_timestamp, "%B %d, %Y %I:%M:%S %p")
self.selected_timestamp = int(time.mktime(dt.timetuple()))
except ValueError:
self.set_error("Invalid custom timestamp.")
self.set_app_label("Invalid custom timestamp.")
return

# Validate URLs
Expand All @@ -384,7 +395,7 @@ def update(self):

for field_name, url in urls_to_validate.items():
if url and not is_valid_url(url):
self.set_error(f"Invalid {field_name}.")
self.set_app_label(f"Invalid {field_name}.")
return

# Prepare data for updating presence if connected
Expand All @@ -411,17 +422,18 @@ def update(self):
# Call the update on the discord RPC
self.discord_rpc.update_presence(**update_kwargs)
self.update_timestamp = datetime.now().timestamp()
self.set_app_label("Presence Updated", "white")

def connect(self):
# Retrieve the client ID entered by the user
self.client_id = self.entry_client_id.get()
# Retrieve the Application ID entered by the user
self.app_id = self.entry_app_id.get()

# Validate the client ID; if invalid, display an error and return
if self.validate_and_set_error(not self.client_id, "Client ID is required."):
# Validate the Application ID; if invalid, display an error and return
if self.validate_and_set_app_label(not self.app_id, "Application ID is required."):
return

# Attempt to connect to the Discord RPC with the provided client ID
success, res = self.discord_rpc.connect(self.client_id)
# Attempt to connect to the Discord RPC with the provided Application ID
success, res = self.discord_rpc.connect(self.app_id)

if success:
# If connection is successful, update the connection state
Expand All @@ -434,10 +446,10 @@ def connect(self):
self.button_update.configure(
state="normal", fg_color=STYLE["NORMAL"])
# Clear any previous error messages
self.set_error("")
self.set_app_label("")
else:
# If connection fails, display the error message
self.set_error(f"Connection Failed. {res.message}")
self.set_app_label(f"Connection Failed. {res.message}")

def disconnect(self):
# Check if already disconnected
Expand All @@ -457,7 +469,7 @@ def disconnect(self):
self.button_update.configure(
state="disabled", fg_color=STYLE["DISABLED"])
# Clear any existing error messages
self.set_error("")
self.set_app_label("")

def combobox_timestamp_callback(self, choice):
# Disable the custom timestamp entry field if the selected choice is not the custom option
Expand Down Expand Up @@ -487,15 +499,16 @@ def combobox_timestamp_callback(self, choice):
"%B %d, %Y %I:%M:%S %p") # Set placeholder to current time
)

def set_error(self, msg):
def set_app_label(self, msg, color=STYLE["ERROR"]):
# Display an error message in the label
self.label_error_state.configure(
text=msg)
self.label_app_state
self.label_app_state.configure(
text=msg, text_color=color)

def validate_and_set_error(self, condition, error_message):
def validate_and_set_app_label(self, condition, error_message):
# Set error message if condition is true and return True, otherwise return False
if condition:
self.set_error(error_message)
self.set_app_label(error_message)
return True
return False

Expand Down

0 comments on commit 2f7458e

Please sign in to comment.