Skip to content

Commit

Permalink
Merge pull request #4 from YUChoe/dev-v4
Browse files Browse the repository at this point in the history
Dev v4
  • Loading branch information
YUChoe authored Jul 15, 2021
2 parents 061efcc + 0d1f347 commit d1ac9b8
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 40 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@
*.onefile-build
venv
.venv
.vscode

*.cmd
*.sh
req.txt
config.json
*.exe
169 changes: 129 additions & 40 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os
import time
# import time
import datetime
import random
from enum import Enum
Expand All @@ -13,23 +13,109 @@
import json

"""
# AFKSaver
# AFKSaver
### v4 - 20200715
- Save and Load config.json
- Smaller window 360*320 to 300*200
- PEP8
- RUN/STOP button has greenish/reddish colours
"""
_appname = 'ASKSaver'
_version = '3(20200710)'
_version = '4(20200710)'


notepad_hwnd = None
gkeypressed = False
# notepad_hwnd = None
# gkeypressed = False



def todayAt (hr, min=0, sec=0, micros=0):
def todayAt(hr, min=0, sec=0, micros=0):
now = datetime.datetime.now()
return now.replace(hour=hr, minute=min, second=sec, microsecond=micros)


class ConfigJSON(dict):
def __setitem__(self, key, item):
self.__dict__[key] = item

def __getitem__(self, key):
return self.__dict__[key]

def __repr__(self):
return repr(self.__dict__)

def __len__(self):
return len(self.__dict__)

def __delitem__(self, key):
del self.__dict__[key]

def clear(self):
return self.__dict__.clear()

def copy(self):
return self.__dict__.copy()

def has_key(self, k):
return k in self.__dict__

def update(self, *args, **kwargs):
return self.__dict__.update(*args, **kwargs)

def keys(self):
return self.__dict__.keys()

def values(self):
return self.__dict__.values()

def items(self):
return self.__dict__.items()

def pop(self, *args):
return self.__dict__.pop(*args)

def __cmp__(self, dict_):
return self.__cmp__(self.__dict__, dict_)

def __contains__(self, item):
return item in self.__dict__

def __iter__(self):
return iter(self.__dict__)

def __init__(self, fn='config.json'):
if not os.path.isfile(fn):
self.__dict__ = self.init_config_file()
else:
with open(fn) as fp:
self.__dict__ = json.load(fp)
self.fn = fn

def init_config_file(self):
c = self.__dict__
c['interval'] = 10
c['counter'] = 5
c['time_start_working'] = '0800'
c['time_end_working'] = '2200'
c['window_geometry'] = ''
c['quote'] = "You cannot learn how to write drama without writing plays, putting it on in front of an audience and getting humiliated." # David Mamet
self.save_all()
return c

def save(self, key, value):
self.__dict__[key] = value
self.save_all()

def save_all(self):
with open(self.fn, "w") as json_file:
dict_to_save = self.__dict__.copy()
try:
del dict_to_save['fn']
except AttributeError:
pass
json.dump(dict_to_save, json_file, indent=4, sort_keys=True)


class APP_STATUS(Enum):
STOPPED = 0
DEACTIVATED = 1
Expand All @@ -45,28 +131,21 @@ class Main_App():
conf = {}

def __init__(self, version=_version):
self.app.title (f"{_appname} - v{_version}")
window_width = 360
window_height = 320
self.conf = ConfigJSON(fn='config.json')

self.app.title(f"{_appname} - v{_version}")
window_width = 300
window_height = 200
screen_width = self.app.winfo_screenwidth()
screen_height = self.app.winfo_screenheight()

x_cordinate = int((screen_width / 2) - (window_width / 2))
y_cordinate = int((screen_height / 2) - (window_height / 2))
# app_geo = f"{window_width}x{window_height}+{x_cordinate}+{y_cordinate}"
app_geo = self.conf['window_geometry'] if self.conf['window_geometry'] else f"{window_width}x{window_height}+{x_cordinate}+{y_cordinate}"

self.app.geometry(f"{window_width}x{window_height}+{x_cordinate}+{y_cordinate}")
self.app.geometry(app_geo)
self.app.resizable(height=False, width=False)

# status label
# button start / stop
# textarea
# configuration - off time begin / finish
# - text to write
self.conf['interval'] = 10
self.conf['counter'] = 5
self.conf['time_start_working'] = None
self.conf['time_end_working'] = None

# init UI
status_label = tk.Label(self.app, text='Stopped')
status_label.pack(fill=tk.BOTH, expand=True)
Expand All @@ -88,8 +167,14 @@ def __init__(self, version=_version):
status_kbd.pack(side='left')
self.ui['status_kbd'] = status_kbd

# opt_button = tk.Button(self.app, text='RUN', command=self.opt_button_handler)
opt_button = tk.Button(self.app, text='RUN')
frame2 = tk.Frame(self.app)
frame2.pack(anchor=tk.CENTER)

worktime_txt = 'W[{} - {}]'.format(self.conf['time_start_working'], self.conf['time_end_working'])
worktime_lbl = tk.Label(frame2, text=worktime_txt)
worktime_lbl.pack()

opt_button = tk.Button(self.app, text='RUN', bg='#41B199')
opt_button.bind('<Button-1>', self.opt_button_handler)
opt_button.bind('<Double-Button-1>', self.opt_button_handler)
opt_button.pack(fill=tk.BOTH, expand=True)
Expand All @@ -99,25 +184,27 @@ def __init__(self, version=_version):
notepad.pack(fill=tk.BOTH, expand=True)
self.ui['notepad'] = notepad

# TODO: configuration UI


def run(self):
self.app.protocol("WM_DELETE_WINDOW", self.on_closing)
self.app.mainloop()

def on_closing(self):
self.conf.save('window_geometry', self.app.winfo_geometry()) # #3
self.app.destroy()

def opt_button_handler(self, event):
if self.status == APP_STATUS.STOPPED:
self._thread_handler = MockingUser(self, conf=self.conf, sleep_interval=self.conf['interval'])
self._thread_handler.start()
self.set_status('deactivate')
self.ui['opt_button']['text'] = 'STOP'
# print(time.asctime(), 'started')
self.ui['opt_button']['text'] = 'STOP'
self.ui['opt_button']['bg'] = '#FF6F4F'
else:
self._thread_handler.kill()
del self._thread_handler
self.set_status('stop')
self.ui['opt_button']['text'] = 'RUN'
# print(time.asctime(), 'stopped')
self.ui['opt_button']['text'] = 'RUN'
self.ui['opt_button']['bg'] = '#41B199'

def focus(self):
self.app.focus_force()
Expand All @@ -128,18 +215,17 @@ def focus(self):
self.focused = True
self.ui['notepad'].focus_set()


def press(self):
txt = "You cannot learn how to write drama without writing plays, putting it on in front of an audience and getting humiliated." # David Mamet
s = txt.strip().split()
word = s[random.randint(0, len(s)-1)]
word = s[random.randint(0, len(s) - 1)]
# print(f'{time.asctime()} writing: {word}')
self.ui['notepad'].delete(1.0, 'end')
pyautogui.write(word, interval=0.25)
pyautogui.write(' ')

def set_status(self, status_str):
if status_str == 'activate' and self.status != APP_STATUS.ACTIVATED :
if status_str == 'activate' and self.status != APP_STATUS.ACTIVATED:
self.ui['status_label']['text'] = 'Running - Activated'
self.status = APP_STATUS.ACTIVATED
# print(f'{time.asctime()} {status_str}')
Expand All @@ -160,6 +246,7 @@ def update_cmk_status(self, c, m, k):
self.ui['status_mouse']['text'] = f'M[{m}]'
self.ui['status_kbd']['text'] = f'K[{k}]'


class MockingUser(threading.Thread):
kpressed = False
mmoved = False
Expand All @@ -180,13 +267,14 @@ def key_on_press(self, key):
self.kpressed = True

def working_time(self):
self.conf['time_start_working'] = todayAt(hr=8, min=30)
self.conf['time_end_working'] = todayAt(hr=22, min=0)
if self.conf['time_start_working'] < datetime.datetime.now() < self.conf['time_end_working']:
# print("working_time", True, self.conf['time_start_working'], datetime.datetime.now(), self.conf['time_end_working'])
s = self.conf['time_start_working']
e = self.conf['time_end_working']
time_start_working = todayAt(hr=int(s[:2]), min=int(s[2:]))
time_end_working = todayAt(hr=int(e[:2]), min=int(e[2:]))

if time_start_working < datetime.datetime.now() < time_end_working:
return True
else:
print("working_time", False, self.conf['time_start_working'], datetime.datetime.now(), self.conf['time_end_working'])
return False

def run(self):
Expand Down Expand Up @@ -219,7 +307,8 @@ def run(self):
def kill(self):
self._kill.set()


if __name__ == '__main__':
app = Main_App()
app.run()
exit()
exit()

0 comments on commit d1ac9b8

Please sign in to comment.