Update it + legacy ver #4

Open
win7he wants to merge 3 commits from win7he/r2chat:master into master
4 changed files with 211 additions and 54 deletions

View file

@ -0,0 +1 @@
{"v":"WL1","n":"bar","l":{"en":{"langname":"English","chat":"Chat","regusers":"Registered users","chlist":"Channel list","lchan":"Leave channel","insert":"Insert","emoticon":"Emoticon","gif":"GIF","status":"Status","statmes":"Status messages","onlinestat":"Online (All notifs)","inactstat":"Inactive (Pings only)","busystat":"Busy (No notifs)","offlinestat":"Appear offline","pref":"Preferences","prefl":"prefrences","help":"Help","user":"User","chans":"Channels","lseen":"Last seen","impmes":"Important message! ","save":"Save","cancel":"Cancel","btodef":"Back to defaults","interface":"Interface","ffam":"Font family","fsiz":"Font size","fthi":"Frame thickness","backc":"Background color","textc":"Text color","userc":"Username color","usernh":"Use {username} where you want\n your username to be.","joinm":"Join message","leavm":"Leave message","inacm":"Inactive message","busym":"Busy message","choose":"Choose..."}},"r":{"gb":"en","us":"en"},"d":"en"}

109
r2chat.py
View file

@ -1,15 +1,14 @@
import tkinter as tk
from tkinter import scrolledtext, messagebox
from tkinter import ttk, colorchooser, font as tkfont
import os, sys, json
import os, sys, json, time, getpass, webbrowser, re, subprocess
from pathlib import Path
import time
import getpass
from plyer import notification
import pygame as media
import webbrowser
import re
import subprocess
from random import randint
import wlang
wlang.setlangfile('assets/internal/lang.json')
if sys.platform == "win32":
ROOT = Path("C:/Users/Public")
@ -18,8 +17,8 @@ else:
try:
if sys.argv[1]!='chat':
CHANCHAN = sys.argv[1].replace(' ','_').replace('.','-')
CHANNEL = 'chat_'+CHANCHAN
CHANCHAN = sys.argv[1].replace(' ','_').replace('.','-').replace('\\','/').replace(':','/')
CHANNEL = 'chat_'+CHANCHAN.replace('/','#')
else:
CHANNEL = 'chat'
CHANCHAN = 'chat'
@ -49,11 +48,12 @@ DEFAULT_CONFIG = {
"border_width": 2,
"bg_color": "#f0f0f0",
"fg_color": "#1e1e1e",
"user_color": "#0000ff",
"user_color": f"#{['0000ff','af0000','00af00','ffaf00','ff00ff','00ffff','7f00ff','ff7f00','00ff7f','007fff'][randint(0,9)]}",
"status_join": "{username} is now online.",
"status_leave": "{username} is now offline.",
"status_inactive": "{username} will be right back.",
"status_busy": "{username} is busy."
"status_busy": "{username} is busy.",
"language": "en"
}
def load_config():
@ -76,8 +76,8 @@ class r2chat:
def __init__(self, root):
self.root = root
self.cfg = load_config()
self.root.title(f"r2chat :: {username} / #{CHANCHAN}")
self.root.title(f"r2chat :: {username} / #{CHANCHAN.replace('#','/')}")
wlang.setlang(self.cfg['language'])
self.last_size = 0
# configs
@ -98,28 +98,29 @@ class r2chat:
## chat menu
self.chatmenu = tk.Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label="Chat", menu=self.chatmenu)
self.chatmenu.add_command(label="Registered users", command=lambda: self.show_users())
self.chatmenu.add_command(label="Channel list", command=lambda: self.show_channels())
self.chatmenu.add_command(label="Leave channel", command=lambda: self.on_close())
self.menubar.add_cascade(label=wlang.getobj('chat'), menu=self.chatmenu)
self.chatmenu.add_command(label=wlang.getobj('regusers'), command=lambda: self.show_users())
self.chatmenu.add_command(label=wlang.getobj('chlist'), command=lambda: self.show_channels())
self.chatmenu.add_command(label=wlang.getobj('lchan'), command=lambda: self.on_close())
## insert menu
self.chatmenu = tk.Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label="Insert", menu=self.chatmenu)
self.chatmenu.add_command(label="Emoticon", command=lambda: print(""))
self.chatmenu.add_command(label="GIF", command=lambda: print(""))
self.menubar.add_cascade(label=wlang.getobj('insert'), menu=self.chatmenu)
self.chatmenu.add_command(label=wlang.getobj('emoticon'), command=lambda: print(""))
## its pronounced jif
self.chatmenu.add_command(label=wlang.getobj('gif'), command=lambda: print(""))
## status menu
self.chatmenu = tk.Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label="Status", menu=self.chatmenu)
self.chatmenu.add_command(label="Online (All notifs)", command=lambda: self.setstatus("online"))
self.chatmenu.add_command(label="Inactive (Pings only)", command=lambda: self.setstatus("inactive"))
self.chatmenu.add_command(label="Busy (No notifs)", command=lambda: self.setstatus("busy"))
self.chatmenu.add_command(label="Appear offline", command=lambda: self.setstatus("offline"))
self.menubar.add_cascade(label=wlang.getobj('status'), menu=self.chatmenu)
self.chatmenu.add_command(label=wlang.getobj('onlinestat'), command=lambda: self.setstatus("online"))
self.chatmenu.add_command(label=wlang.getobj('inactstat'), command=lambda: self.setstatus("inactive"))
self.chatmenu.add_command(label=wlang.getobj('busystat'), command=lambda: self.setstatus("busy"))
self.chatmenu.add_command(label=wlang.getobj('offlinestat'), command=lambda: self.setstatus("offline"))
## menu buttons
self.menubar.add_command(label="Preferences", command=lambda: self.openprefs())
self.menubar.add_command(label="Help", command=lambda: webbrowser.open_new_tab("https://forgejo.nishi.boats/Dogo6647/r2chat"))
self.menubar.add_command(label=wlang.getobj('pref'), command=lambda: self.openprefs())
self.menubar.add_command(label=wlang.getobj('help'), command=lambda: webbrowser.open_new_tab("https://forgejo.nishi.boats/Dogo6647/r2chat"))
# MAIN MENU STUFFS
self.entry = tk.Entry(root, relief='sunken', borderwidth=self.cfg["border_width"])
@ -135,7 +136,7 @@ class r2chat:
open(CHAT_FILE, "a").close()
self.update_chat()
self.write_system_message(f' {self.cfg["status_join"]}')
self.write_system_message(f'((#00af00 | ◉)) {self.cfg["status_join"]}')
def on_close(self):
self.write_system_message(f'{self.cfg["status_leave"]}')
@ -180,13 +181,13 @@ class r2chat:
status = new_status
if status == "online":
self.write_system_message(msg=f' {self.cfg["status_join"]}')
self.write_system_message(msg=f'((#00af00 | ◉)) {self.cfg["status_join"]}')
elif status == "offline":
self.write_system_message(msg=f'{self.cfg["status_leave"]}')
elif status == "inactive":
self.write_system_message(msg=f' {self.cfg["status_inactive"]}')
self.write_system_message(msg=f'((#ffaf00 | ◍)) {self.cfg["status_inactive"]}')
elif status == "busy":
self.write_system_message(msg=f' {self.cfg["status_busy"]}')
self.write_system_message(msg=f'((#af0000 | ◎)) {self.cfg["status_busy"]}')
self.user_data["status"] = status
self.save_userdata(self.user_data)
@ -213,15 +214,15 @@ class r2chat:
def show_users(self):
win = tk.Toplevel(self.root)
win.title("Registered users")
win.title(wlang.getobj('regusers'))
win.geometry("420x320")
tree = ttk.Treeview(win, columns=("user", "status", "channels", "last_seen"), show="headings")
tree.heading("user", text="User")
tree.heading("status", text="Status")
tree.heading("channels", text="Channels")
tree.heading("last_seen", text="Last seen")
tree.heading("user", text=wlang.getobj('user'))
tree.heading("status", text=wlang.getobj('status'))
tree.heading("channels", text=wlang.getobj('chans'))
tree.heading("last_seen", text=wlang.getobj('lseen'))
tree.column("user", width=80)
tree.column("status", width=60, anchor="center")
@ -250,7 +251,7 @@ class r2chat:
def show_channels(self):
win = tk.Toplevel(self.root)
win.title("Channel list")
win.geometry("200x320")
win.geometry("600x320")
tree = ttk.Treeview(win, columns=("channel"), show="headings")
tree.heading("channel", text="Channels")
@ -275,7 +276,7 @@ class r2chat:
tree.bind("<Double-1>", on_select)
def open_channel(self, channel):
self.write_system_message(f" {username} is chatting in {channel}.")
self.write_system_message(f"((#006fff | ⇄)) {username} is chatting in {channel.replace('#','/')}.")
if sys.platform == "win32":
subprocess.Popen(f'pythonw "{os.path.abspath(__file__)}" "{channel}"', shell=True)
else:
@ -317,7 +318,7 @@ class r2chat:
try:
current_size = os.path.getsize(CHAT_FILE)
if current_size > self.last_size:
if current_size != self.last_size:
with open(CHAT_FILE, "r", encoding="utf-8") as f:
f.seek(self.last_size)
new_data = f.read()
@ -326,7 +327,7 @@ class r2chat:
self.chat_area.config(state='normal')
if f"@{username} " in new_data and not "---" in new_data and not status == "busy" and not status == "offline":
media.mixer.Sound("assets/internal/ping.ogg").play()
messagebox.showinfo("Important message!", new_data)
messagebox.showinfo(wlang.getobj('impmes'), new_data)
if self.root.wm_state() == 'iconic':
if not f"@{username} " in new_data and not status == "busy" and not status == "inactive":
notification.notify(title="r2chat", message=new_data)
@ -347,7 +348,7 @@ class PreferencesWindow:
self.on_save = on_save
self.win = tk.Toplevel(parent)
self.win.title("r2chat prefs")
self.win.title(f"r2chat {wlang.getobj('prefl')}")
self.win.geometry("420x520")
self.win.resizable(False, False)
self.win.transient(parent)
@ -366,16 +367,16 @@ class PreferencesWindow:
btn_frame = tk.Frame(self.win)
btn_frame.pack(fill=tk.X, padx=10, pady=(0, 10))
tk.Button(btn_frame, text="Save", width=10, command=self._save).pack(side=tk.RIGHT, padx=(4, 0))
tk.Button(btn_frame, text="Cancel", width=10, command=self.win.destroy).pack(side=tk.RIGHT)
tk.Button(btn_frame, text="Back to defaults", command=self._reset).pack(side=tk.LEFT)
tk.Button(btn_frame, text=wlang.getobj('save'), width=10, command=self._save).pack(side=tk.RIGHT, padx=(4, 0))
tk.Button(btn_frame, text=wlang.getobj('cancel'), width=10, command=self.win.destroy).pack(side=tk.RIGHT)
tk.Button(btn_frame, text=wlang.getobj('btodef'), command=self._reset).pack(side=tk.LEFT)
def _build_appearance_tab(self, notebook):
frame = tk.Frame(notebook)
notebook.add(frame, text="Interface")
notebook.add(frame, text=wlang.getobj('interface'))
# font family
self._row(frame, 0, "Font family")
self._row(frame, 0, wlang.getobj('ffam'))
font_var = tk.StringVar(value=self.cfg["font_family"])
self.vars["font_family"] = font_var
families = sorted(tkfont.families())
@ -383,34 +384,34 @@ class PreferencesWindow:
font_combo.grid(row=0, column=1, padx=10, pady=6, sticky=tk.W)
# font size
self._row(frame, 1, "Font size")
self._row(frame, 1, wlang.getobj('fsiz'))
size_var = tk.IntVar(value=self.cfg["font_size"])
self.vars["font_size"] = size_var
tk.Spinbox(frame, from_=7, to=24, textvariable=size_var, width=6).grid(row=1, column=1, padx=10, pady=6, sticky=tk.W)
# border width
self._row(frame, 2, "Frame thickness")
self._row(frame, 2, wlang.getobj('fthi'))
bw_var = tk.IntVar(value=self.cfg["border_width"])
self.vars["border_width"] = bw_var
tk.Spinbox(frame, from_=0, to=6, textvariable=bw_var, width=6).grid(row=2, column=1, padx=10, pady=6, sticky=tk.W)
# color pickers
for i, (key, label) in enumerate([
("bg_color", "Background color"),
("fg_color", "Text color"),
("user_color", "Username color"),
("bg_color", wlang.getobj('backc')),
("fg_color", wlang.getobj('textc')),
("user_color", wlang.getobj('userc')),
], start=3):
self._row(frame, i, label)
self._color_picker_row(frame, i, key)
def _build_status_messages_tab(self, notebook):
frame = tk.Frame(notebook)
notebook.add(frame, text="Status messages")
notebook.add(frame, text=wlang.getobj('statmes'))
tk.Label(frame, text="Use {username} where you want your username to be.", fg="gray", font=("Lucida Console", 9)).grid(
tk.Label(frame, text=wlang.getobj('usernh'), fg="gray", font=("Lucida Console", 9)).grid(
row=0, column=0, columnspan=2, padx=10, pady=(10, 4), sticky=tk.W)
for i, (key, label) in enumerate([("status_join", "Join message"),("status_leave", "Leave message"),("status_inactive", "Inactive message"),("status_busy", "Busy message")], start=1):
for i, (key, label) in enumerate([("status_join", wlang.getobj('joinm')),("status_leave", wlang.getobj('leavm')),("status_inactive", wlang.getobj('inacm')),("status_busy", wlang.getobj('busym'))], start=1):
self._row(frame, i, label)
var = tk.StringVar(value=self.cfg[key])
self.vars[key] = var
@ -432,7 +433,7 @@ class PreferencesWindow:
v.set(result[1])
p.config(bg=result[1])
tk.Button(frame, text="Choose…", command=pick, width=8).grid(row=row, column=1, padx=(44, 0), pady=6, sticky=tk.W)
tk.Button(frame, text=wlang.getobj('choose'), command=pick, width=8).grid(row=row, column=1, padx=(44, 0), pady=6, sticky=tk.W)
def _save(self):
for key, var in self.vars.items():

100
r2chat_LEGACY.py Normal file
View file

@ -0,0 +1,100 @@
import tkinter as tk
from tkinter import scrolledtext
import os
import time
import getpass
from json import loads
CHAT_FILE = "C:/Users/Public/r2chat/chat.txt"
REFRESH_INTERVAL = 1000
BORDER_WIDTH = 3
THEMES = [['white','white','white','black','Basic'],['#000707','#002727','#001717','white','Aqua']]
username = getpass.getuser()
CONFIG_FILE = f'C:/r2chat/legacy_config/{username}.r2cc'
if not os.path.exists(CONFIG_FILE):
CFILE_C=open(CONFIG_FILE, "a")
CFILE_C.write('0\n is now online.\n is now offline.')
CFILE_C.close()
def conf_line(n):
return((open(CONFIG_FILE).read()).split('\n')[n])
THEME = int(conf_line(0))
JOIN_MESSAGE = conf_line(1)
LEAVE_MESSAGE = conf_line(2)
class r2chat:
def __init__(self, root):
self.root = root
self.root.title(f"r2chat Legacy :: {username}")
self.last_size = 0
self.chat_area = scrolledtext.ScrolledText(root, wrap='word', font=("Lucida Console", 11), bg=THEMES[THEME][1], fg=THEMES[THEME][3], relief='groove', borderwidth=BORDER_WIDTH)
self.chat_area.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)
self.chat_area.bind("<Key>", lambda e: "break")
self.entry = tk.Entry(root, font=("Lucida Console", 11), bg=THEMES[THEME][2], fg=THEMES[THEME][3], relief='groove', borderwidth=BORDER_WIDTH)
self.entry.pack(padx=10, pady=(0, 10), fill=tk.X)
self.entry.bind("<Return>", self.send_message)
if not os.path.exists(CHAT_FILE):
open(CHAT_FILE, "a").close()
self.update_chat()
self.write_system_message(f"{username}{JOIN_MESSAGE}")
def on_close(self):
self.write_system_message(f"{username}{LEAVE_MESSAGE}")
self.root.destroy()
def write_system_message(self, msg):
line = f"---- {msg} ----\n"
with open(CHAT_FILE, "a", encoding="utf-8") as f:
f.write(line)
def send_message(self, event=None):
msg = self.entry.get().strip()
if msg:
timestamp = time.strftime("%y/%m/%d %H:%M")
line = f"[{timestamp}] {username} (legacy): {msg}\n"
try:
with open(CHAT_FILE, "a", encoding="utf-8") as f:
f.write(line)
except Exception as e:
print("oh noes! ", e)
self.entry.delete(0, tk.END)
def update_chat(self):
try:
current_size = os.path.getsize(CHAT_FILE)
if current_size > self.last_size:
with open(CHAT_FILE, "r", encoding="utf-8") as f:
f.seek(self.last_size)
new_data = f.read()
self.last_size = current_size
self.chat_area.config(state='normal')
self.chat_area.insert(tk.END, new_data)
self.chat_area.config(state='disabled')
self.chat_area.yview(tk.END)
except Exception as e:
print("oh noes! ", e)
self.root.after(REFRESH_INTERVAL, self.update_chat)
if __name__ == "__main__":
root = tk.Tk()
app = r2chat(root)
root.geometry("500x520")
root.minsize(360, 520)
root.attributes('-topmost', True)
root.protocol("WM_DELETE_WINDOW", app.on_close)
root.configure(bg=THEMES[THEME][0])
root.mainloop()

55
wlang.py Normal file
View file

@ -0,0 +1,55 @@
import locale
import json
# default language file
langfile='lang.json'
# error and shit
try:
langfilecon=open(langfile).read()
except:
print('wlang error:Language file not found, continuing execution. Make sure to set the language file!')
# default language
lang='en'
deflangfull=locale.getdefaultlocale()[0]
deflang=deflangfull[3:len(deflangfull)].lower()
# functions
def setlangfile(lfile):
global langfile
global langfilecon
langfile=lfile
langfilecon=open(langfile).read()
def setlang(l):
global lang
lang=l
# get the d, n and v values
def getlangname():
return json.loads(langfilecon)["n"]
def getlangver():
return json.loads(langfilecon)["v"]
def getinlangdef():
return json.loads(langfilecon)["d"]
# the big one
def getobj(obj):
# sssdfg
obj=str(obj)
# get the thing
try:
return json.loads(langfilecon)["l"][lang][obj]
except:
# else use replaced
try:
return json.loads(langfilecon)["l"][json.loads(langfilecon)["r"][lang]][obj]
except:
# else use default
try:
return json.loads(langfilecon)["l"][json.loads(langfilecon)["d"]][obj]
except:
return '{'+obj+'}' # give up