├── healthywork ├── __init__.py ├── config.py └── app.py ├── icon.png ├── Screenshot.png ├── Screenshot_2.png ├── .gitignore ├── config.json ├── setup.py └── README.md /healthywork/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1zlab/1ZLAB-PyQT-Healthy-Work/HEAD/icon.png -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1zlab/1ZLAB-PyQT-Healthy-Work/HEAD/Screenshot.png -------------------------------------------------------------------------------- /Screenshot_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1zlab/1ZLAB-PyQT-Healthy-Work/HEAD/Screenshot_2.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.pot 3 | *.pyc 4 | __pycache__/ 5 | .vscode/ 6 | .directory 7 | venv/ 8 | dist/ 9 | *.egg-info 10 | 11 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "label_stylesheet": 3 | "color: rgb(255, 0, 127);font: 30pt \"WenQuanYi Micro Hei Mono\";", 4 | "button_stylesheet": 5 | "background-color: rgba(182, 176, 171, 90);color: rgb(255, 0, 127);font: 30pt \"WenQuanYi Micro Hei Mono\";", 6 | "message": "\u559d\u676f\u6c34\u4f11\u606f\u4e00\u4e0b\u5427", 7 | "count": " ", 8 | "time_work": "1800000", 9 | "time_rest": "300000", 10 | "wallpapers_dir": "~/wallpapers", 11 | "music_dir": "~/music", 12 | "with_music": "1" 13 | } 14 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import find_packages, setup 3 | 4 | 5 | setup( 6 | name='healthywork', 7 | version='1.1.0', 8 | packages=['healthywork'], 9 | include_package_data=True, 10 | license='MIT License', 11 | description='生活不止有屏幕上的代码,还有诗和远方.', 12 | url='https://github.com/Fuermohao/Healthy-Work', 13 | author='Fuermohao', 14 | author_email='Fuermohao@outlook.com', 15 | platforms='Linux,Unix,Windows', 16 | keywords='HealthyWork', 17 | install_requires=['pyqt5'], 18 | entry_points={ 19 | 'console_scripts': [ 20 | 'healthywork = healthywork.app:cli' 21 | ] 22 | } 23 | ) 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HealthyWork 2 | 生活不止有屏幕上的代码,还有诗和远方. 3 | 这是一款基于Python语言和PyQt图形化框架编写的桌面应用,用来提醒正在电脑前工作的人们注意休息,以保障身体健康。 4 | 5 | ## Features 6 | - 防颈椎病 7 | - 防腰间盘突出 8 | - 防痔疮 9 | - 防心脏病 10 | - 自定义壁纸 11 | - 自定义时间 12 | - 本地音乐播放 13 | - 全屏显示,窗口置顶 14 | - 界面简约(编不下去了) 15 | - 你值得拥有 16 | 17 | ![截图](https://github.com/1zlab/HealthyWork/blob/master/Screenshot.png) 18 | ![截图](https://github.com/1zlab/HealthyWork/blob/master/Screenshot_2.png) 19 | ## Dependence 20 | - python3 21 | - PyQt5 22 | 23 | 24 | ## Install 25 | ```sh 26 | pip install healthywork 27 | ``` 28 | 29 | ## How to use 30 | ```sh 31 | healthywork 32 | ``` 33 | ## Custom 34 | 35 | 初次运行会在用户目录下的.config文件夹中创建healthywork.json文件,存储程序基本的配置,你可以自行修改一下的所有选项: 36 | 37 | 38 | ```pytho 39 | DEFALUT_CONFIG = { 40 | 'label_stylesheet': "color: rgb(255, 0, 127);font: 30pt \"WenQuanYi Micro Hei Mono\";", 41 | 'button_stylesheet': "background-color: rgba(182, 176, 171, 90);color: rgb(255, 0, 127);font: 30pt \"WenQuanYi Micro Hei Mono\";", 42 | 'message': "喝杯水休息一下吧", 43 | 'count': " ", 44 | 'time_work': "2400000", 45 | 'time_rest': "600000", 46 | 'wallpapers_dir': "./wallpapers", 47 | 'music_dir': "./music", 48 | 'with_music': "1" 49 | } 50 | ``` 51 | 52 | - label_stylesheet: 界面上标签的样式 53 | - button_stylesheet:界面上按钮的样式 54 | - message:提醒的文字 55 | - count:给倒计时标签占位用的,方便计算label的位置 56 | - time_work: 工作时间间隔,单位毫秒,默认40分钟 57 | - time_rest: 休息时间间隔,单位毫秒,默认10分钟 58 | - wallpapers_dir: 存放壁纸的目录,默认为用户主目录下的Pictures 59 | - music_dir: 存放音频的目录,默认为用户主目录下的Music目录 60 | - with_music: 休息时是否播放音乐,1为播放,0为不播放。默认播放。 61 | -------------------------------------------------------------------------------- /healthywork/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | import json 7 | import pwd 8 | 9 | BASE_DIR = os.path.dirname("/home/%s/" % pwd.getpwuid(os.getuid())[0]) 10 | 11 | CONFIG_FILE_PATH = os.path.join(BASE_DIR, ".config/healthywork.json") 12 | # print(CONFIG_FILE_PATH) 13 | 14 | WALLPAPER_DIR = os.path.join(BASE_DIR, "Pictures") 15 | MUSIC_DIR = os.path.join(BASE_DIR, "Music") 16 | 17 | DEFALUT_CONFIG = { 18 | 'label_stylesheet': "color: rgb(255, 0, 127);font: 30pt \"WenQuanYi Micro Hei Mono\";", 19 | 'button_stylesheet': "background-color: rgba(182, 176, 171, 90);color: rgb(255, 0, 127);font: 30pt \"WenQuanYi Micro Hei Mono\";", 20 | 'message': "喝杯水休息一下吧", 21 | 'count': " "*16, 22 | 'time_work': "2400000", 23 | 'time_rest': "600000", 24 | 'wallpapers_dir': WALLPAPER_DIR, 25 | 'music_dir': MUSIC_DIR, 26 | 'with_music': "1" 27 | } 28 | 29 | 30 | class Config(): 31 | def __init__(self, *args, **kwargs): 32 | self.LABEL_STYLESHEET = self.read_config()['label_stylesheet'] 33 | self.BUTTON_STYLESHEET = self.read_config()['button_stylesheet'] 34 | self.MESSAGE = self.read_config()['message'] 35 | self.COUNT = self.read_config()['count'] 36 | self.TIME_WORK = self.read_config()['time_work'] 37 | self.TIME_REST = self.read_config()['time_rest'] 38 | self.DIR_WALLPAPERS = self.read_config()['wallpapers_dir'] 39 | self.DIR_MUSIC = self.read_config()['music_dir'] 40 | self.WITH_MUSIC = int(self.read_config()['with_music']) 41 | 42 | def read_config(self): 43 | 44 | if os.path.exists(CONFIG_FILE_PATH): 45 | with open(CONFIG_FILE_PATH, 'r') as file: 46 | config = file.read() 47 | else: 48 | with open(CONFIG_FILE_PATH, 'w') as file: 49 | config = json.dumps(DEFALUT_CONFIG) 50 | file.write(config) 51 | 52 | return json.loads(config) 53 | 54 | 55 | CONFIG = Config() 56 | -------------------------------------------------------------------------------- /healthywork/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton 6 | from PyQt5.QtGui import QPainter, QPixmap, QGuiApplication, QIcon 7 | from PyQt5.QtCore import Qt, QTimer, QUrl, QDir, QCoreApplication 8 | from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaPlaylist 9 | from healthywork.config import CONFIG 10 | import sys 11 | import os 12 | import random 13 | 14 | 15 | class HealthyWork(QWidget): 16 | def __init__(self): 17 | super().__init__() 18 | self.init_ui() 19 | self.init_timer() 20 | self.player = QMediaPlayer(self) 21 | 22 | def init_ui(self): 23 | # TODO 24 | # set a window icon 25 | # self.setWindowIcon(QIcon('./icon.png')) 26 | self.label_background = QLabel(self) 27 | self.button = QPushButton(self) 28 | self.button.setText('BACK TO WORK') 29 | self.button.setStyleSheet(CONFIG.BUTTON_STYLESHEET) 30 | self.button.resize(self.button.sizeHint()) 31 | self.set_position(self.button, Label='Message') 32 | self.button.clicked.connect(self.start_work) 33 | self.button.hide() 34 | self.label_message = QLabel(self) 35 | self.label_count = QLabel(self) 36 | self.label_message.setText(CONFIG.MESSAGE) 37 | self.label_count.setText(CONFIG.COUNT) 38 | self.label_message.setStyleSheet(CONFIG.LABEL_STYLESHEET) 39 | self.label_count.setStyleSheet(CONFIG.LABEL_STYLESHEET) 40 | self.label_message.resize(self.label_message.sizeHint()) 41 | self.label_count.resize(self.label_count.sizeHint()) 42 | self.set_position(self.label_message, Label='Message') 43 | self.set_position(self.label_count, Label='Count') 44 | self.setAttribute(Qt.WA_TranslucentBackground) 45 | self.setWindowFlags(Qt.FramelessWindowHint | 46 | Qt.WindowStaysOnTopHint | Qt.SubWindow) 47 | print('start healthywork ...') 48 | 49 | def init_timer(self): 50 | self.rest_time = int(CONFIG.TIME_REST) 51 | self.timer_work = QTimer() 52 | self.timer_rest = QTimer() 53 | self.timer_count = QTimer() 54 | self.timer_work.start(int(CONFIG.TIME_WORK)) 55 | self.timer_work.timeout.connect(self.start_rest) 56 | self.timer_rest.timeout.connect(self.show_button) 57 | self.timer_count.timeout.connect(self.count_down) 58 | print('work timer start with %s millseconds' % CONFIG.TIME_WORK) 59 | 60 | def start_rest(self): 61 | self.with_music(CONFIG.WITH_MUSIC) 62 | self.show_background_picture() 63 | self.timer_work.stop() 64 | print('work timer stop') 65 | self.timer_rest.start(int(CONFIG.TIME_REST)) 66 | self.rest_time = int(CONFIG.TIME_REST) 67 | print('rest timer start with %s millseconds' % CONFIG.TIME_REST) 68 | self.timer_count.start(1000) 69 | 70 | def start_work(self): 71 | self.button.hide() 72 | self.hide() 73 | self.timer_work.start(int(CONFIG.TIME_WORK)) 74 | print('work timer start with %s millseconds' % CONFIG.TIME_WORK) 75 | self.player.stop() 76 | 77 | def count_down(self): 78 | def format_time(mseconds): 79 | m, s = divmod(mseconds / 1000, 60) 80 | h, m = divmod(m, 60) 81 | # print("%02d:%02d:%02d" % (h, m, s)) 82 | return (h, m, s) 83 | self.label_count.setText("%02d:%02d:%02d" % 84 | format_time(self.rest_time - 1000)) 85 | self.rest_time = self.rest_time - 1000 86 | 87 | def show_button(self): 88 | self.timer_rest.stop() 89 | print('rest timer stop') 90 | self.timer_count.stop() 91 | self.label_count.hide() 92 | self.label_message.hide() 93 | self.button.show() 94 | 95 | def with_music(self, is_music_on): 96 | # 随机播放音乐,单曲,无列表,只播放一次 97 | def media(url): 98 | return QMediaContent( 99 | QUrl.fromLocalFile(QDir.absolutePath(QDir(url)))) 100 | if is_music_on and os.listdir(CONFIG.DIR_MUSIC): 101 | songs = [CONFIG.DIR_MUSIC + "/" + 102 | song for song in os.listdir(CONFIG.DIR_MUSIC) if os.path.isfile(CONFIG.DIR_MUSIC + "/" + song)] 103 | if songs: 104 | index = random.randint(0, len(songs) - 1) 105 | try: 106 | self.player.setMedia(media(songs[index])) 107 | except: 108 | pass 109 | self.player.play() 110 | 111 | def position(self, widget): 112 | # 计算label显示位置 113 | window_size = QApplication.desktop().screenGeometry() 114 | x = (window_size.width() - widget.width()) // 2 115 | y = (window_size.height() - widget.height()) // 2 116 | return (x, y, widget.width(), widget.height()) 117 | 118 | def set_position(self, label, **kwargs): 119 | pos = self.position(label) 120 | if kwargs['Label'] == 'Message': 121 | label.setGeometry(pos[0], pos[1], pos[2], pos[3]) 122 | else: 123 | label.setGeometry(pos[0], pos[1] + 80, pos[2], pos[3]) 124 | 125 | def show_background_picture(self): 126 | # 随机一张壁纸全屏显示 127 | self.showFullScreen() 128 | 129 | if os.listdir(CONFIG.DIR_WALLPAPERS): 130 | window_size = QApplication.desktop().screenGeometry() 131 | self.label_background.setGeometry( 132 | 0, 0, window_size.width(), window_size.height()) 133 | wallpapers = [CONFIG.DIR_WALLPAPERS + "/" + 134 | wallpaper for wallpaper in os.listdir(CONFIG.DIR_WALLPAPERS) if os.path.isfile(CONFIG.DIR_WALLPAPERS + "/" + wallpaper)] 135 | # print(wallpapers) 136 | if wallpapers: 137 | try: 138 | index = random.randint(0, len(wallpapers) - 1) 139 | self.label_background.setPixmap(QPixmap(QDir.absolutePath(QDir(wallpapers[index]))) 140 | .scaled(window_size.width(), window_size.height())) 141 | self.label_message.show() 142 | except: 143 | pass 144 | 145 | self.label_count.show() 146 | 147 | def cli(): 148 | app = QApplication(sys.argv) 149 | QCoreApplication.setApplicationName("HealthyWork") 150 | QGuiApplication.setApplicationDisplayName("HealthyWork") 151 | w = HealthyWork() 152 | sys.exit(app.exec_()) 153 | 154 | 155 | if __name__ == '__main__': 156 | cli() --------------------------------------------------------------------------------