Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d07a50b
Merge pull request #1 from perslev/master
vanalmsick Aug 1, 2019
c932858
Add macos Statusbar
vanalmsick Aug 1, 2019
45d56c0
Add macos Statusbar
vanalmsick Aug 1, 2019
cba5175
Add macos StartUp installation file.
vanalmsick Aug 1, 2019
6c4acdd
Add MacOS StartUp installation file and resolve some bugs. Add comments.
vanalmsick Aug 2, 2019
b20de91
Adding ToDos.
vanalmsick Aug 2, 2019
4c4bfc3
Add MacOS Statusbar image for README
vanalmsick Aug 2, 2019
2d33c29
Add statusbar Info
vanalmsick Aug 2, 2019
591a384
Change picture dims.
vanalmsick Aug 2, 2019
a48878e
Change pic dims
vanalmsick Aug 2, 2019
9320ad3
Change pic dims
vanalmsick Aug 2, 2019
05a4f97
Change pic placement
vanalmsick Aug 2, 2019
a12252e
Some text edits
vanalmsick Aug 2, 2019
3cef1bd
Some text edits
vanalmsick Aug 2, 2019
cf05f01
Password is now saved in Keychain and Automatic Sync remembers last s…
vanalmsick Aug 14, 2019
870db5e
Password is now saved in Keychain and Automatic Sync remembers last s…
vanalmsick Aug 14, 2019
99dacd7
Merge remote-tracking branch 'origin/master'
vanalmsick Aug 14, 2019
22c549a
Add Windows System-Tray.
vanalmsick Aug 14, 2019
87a8e60
Add Windows Start-Up Installation function.
vanalmsick Aug 14, 2019
4465dc2
Bug fixes of MacOS Scheduler which won't start at startup.
vanalmsick Aug 16, 2019
e5a7f28
Fix bugs in Windows Startup.
vanalmsick Aug 16, 2019
ff76af3
Image of Windows system tray
vanalmsick Aug 16, 2019
1325f48
Update README.md
vanalmsick Aug 16, 2019
af1da80
Update README.md
vanalmsick Aug 16, 2019
12339ce
Scheduler bug fix.
vanalmsick Aug 20, 2019
f745b29
Merge remote-tracking branch 'origin/master'
vanalmsick Aug 20, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added CanvasSync/GUI/canvas_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
143 changes: 143 additions & 0 deletions CanvasSync/GUI/macos_statusbar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
"""
This script is the actual MacOS Statusbar for CanvasSync.
Execute this script to run the CanvasSync Statusbar.
Run startup_installer.py to add the CanvasSync Statsubar to the system StartUp.
"""
from rumps import *
import pathlib
import sys
import subprocess
import AppKit
import configparser
import os.path
import datetime
import keyring
import pymsgbox


class config_file:
def __init__(self, filepath):
self.filepath = filepath
if not os.path.exists(self.filepath):
open(self.filepath, 'a').close()
self.config = configparser.ConfigParser()
self.config.read(filepath)

def read(self, section, parameter):
if not self.config.has_option(section, parameter):
return None
else:
return self.config[section][parameter]

def write(self, section, parameter, value):
if not self.config.has_section(section):
self.config.add_section(section)
self.config.set(section, parameter, value)
with open(self.filepath, 'w') as configfile:
self.config.write(configfile)


from tkinter import *

def pop_up():
app = Tk()
app.title("CanvasSync Password")
label = Label(app, text="Please enter the CanvasSync Password:")
label.grid()
pwd = StringVar()
e1 = Entry(app, width=40, textvariable=pwd)
btn = Button(app, text="Ok", command=app.destroy)
btn.grid(row=2)
e1.grid(row=1)

app.mainloop()
return pwd.get()

def savepassword():
response = str(pop_up())
keyring.set_password('CanvasSync', 'xkcd', response)


def changeSchedule(ToNew):
"""
This function changes the scheduler settings file so that the selected interval in the settings file is saved there.
Arguments:
ToNew (str): The interval changed to/the new interval.
"""
config.write('Settings', 'interval', ToNew)


def adjust_interval(self):
# Change tick-mark in Statusbar on change
app.menu["Automatic sync"]['hourly'].state = 0
app.menu["Automatic sync"]['every 6 hours'].state = 0
app.menu["Automatic sync"]['daily'].state = 0
app.menu["Automatic sync"]['Do not sync'].state = 0
self.state = 1
# Save setting in Scheduler-Settings-File
if self.title == 'hourly':
changeSchedule('hourly')
elif self.title == 'every 6 hours':
changeSchedule('every 6 hours')
elif self.title == 'daily':
changeSchedule('daily')
elif self.title == 'Do not sync':
changeSchedule('Do not sync')


@clicked("Sync now")
def prefs(_):
# Manual Sync now
rumps.notification("Canvas Sync", "Syncing...", "The Canvas sync was started manually.")
# Add folder of canvas module to search directory
path = str(pathlib.Path(__file__).parent.parent.parent) + "/bin/"
sys.path.insert(0, path)
# Actual syncing
import canvas
settings = canvas.Settings()
password = keyring.get_password('CanvasSync', 'xkcd')
canvas.do_sync(settings, password)
rumps.notification("Canvas Sync", "Finished Synchronisation", "The Manual Canvas-Sync-task was finished.")
config.write('Last run', 'time', str(datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S")))


@clicked("Preferences")
def sayhi(_):
# Will be added later on
rumps.alert("Not yet available! In next version...")


hourly = MenuItem('hourly', callback=adjust_interval)
every6 = MenuItem('every 6 hours', callback=adjust_interval)
daily = MenuItem('daily', callback=adjust_interval)
no_sync = MenuItem('Do not sync', callback=adjust_interval)

if __name__ == "__main__":
if keyring.get_password('CanvasSync', 'xkcd') is None:
savepassword()

config = config_file(str(pathlib.Path(__file__).parent.parent) + "/scheduler/scheduler.ini")
interval = config.read('Settings', 'interval')

# Do not appear in Mac Dock
info = AppKit.NSBundle.mainBundle().infoDictionary()
info["LSBackgroundOnly"] = "1"

# Set Statusbar Properties
app = App('Canvas Sync', icon='canvas_logo.png')
app.menu = [("Sync now"), ("Automatic sync", [hourly, every6, daily, None, no_sync]), "Preferences"]
path = str(pathlib.Path(__file__).parent.parent) + '/scheduler/scheduler.py'

# Run Scheduler as independent subprocess
#subprocess.run(["python", path])
from subprocess import Popen, PIPE
p = subprocess.Popen([sys.executable, path],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)

# Get Current Sync-Setting from file and select the selected in Statusbar
if not interval == None:
app.menu["Automatic sync"][interval].state = 1

# Run Statusbar
app.run()
98 changes: 98 additions & 0 deletions CanvasSync/GUI/startup_installer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""
This script is to add/remove the CanvasSync Statusbar in MacOS to the LaunchAgent so that is automatically starts at startup.
Run this file or the function ActivateStartUpStatusbar() to add it to startup.
Run the function DeactivateStartUpStatusbar() to remove it from startup.
"""

import pathlib
import os
import sys
import platform

def CreateStartupFile():
with open(str(pathlib.Path(__file__).parent) + '/startup_template.plist', 'r') as file:
script = str(file.read())

script = script.replace('[@replaceCanvasPath]', str(pathlib.Path(__file__).parent))
script = script.replace('[@replacePythonPath]', str(sys.executable))

path_s = str(os.path.expanduser('~')) + "/Library/LaunchAgents/com.CanvasSync.Statusbar.plist"
with open(path_s, 'w') as file:
file.write(script)

def AddWinTaskScheduler(wkdir, command, enabled):
import datetime
import win32com.client

scheduler = win32com.client.Dispatch('Schedule.Service')
scheduler.Connect()
root_folder = scheduler.GetFolder('\\')
task_def = scheduler.NewTask(0)

# Create trigger
#end_time = datetime.datetime.now()
TASK_TRIGGER_TIME = 9
trigger = task_def.Triggers.Create(TASK_TRIGGER_TIME)
#trigger.EndBoundary = end_time.isoformat()
trigger.ExecutionTimeLimit = "PT5M"
trigger.Id = "LogonTriggerId"
import win32api
user = win32api.GetUserName()
trigger.UserId = user
trigger.ExecutionTimeLimit = "P0M2DT0H0M"
trigger.enabled = enabled

# Create action
TASK_ACTION_EXEC = 0
action = task_def.Actions.Create(TASK_ACTION_EXEC)
action.ID = 'DO NOTHING'
action.Path = 'cmd.exe'
action.Arguments = '/c "' + str(command) + '"'
action.WorkingDirectory = str(wkdir)

# Set parameters
task_def.RegistrationInfo.Description = 'Run CanvasSync at System Startup'
task_def.Settings.Enabled = True
task_def.Settings.StopIfGoingOnBatteries = False
task_def.Settings.DisallowStartIfOnBatteries = False
task_def.Settings.Hidden = True

# Register task
# If task already exists, it will be updated
TASK_CREATE_OR_UPDATE = 6
TASK_LOGON_NONE = 0
root_folder.RegisterTaskDefinition(
'CanvasSync', # Task name
task_def,
TASK_CREATE_OR_UPDATE,
'', # No user
'', # No password
TASK_LOGON_NONE)



def ActivateStartUpStatusbar():
# ToDo: In Windows subpress feedback e.g. when asking if run this package that is not in PATH.
if platform.system() == 'Windows':
path = str(pathlib.Path(__file__).parent)
AddWinTaskScheduler(path, r'python .\windows_systemtray.py -y', True)

else: #MacOS
CreateStartupFile()
load_command = "launchctl load " + str(os.path.expanduser('~')) + "/Library/LaunchAgents/com.CanvasSync.Statusbar.plist"
os.system(load_command)

def DeactivateStartUpStatusbar():
if platform.system() == 'Windows':
path = str(pathlib.Path(__file__).parent)
AddWinTaskScheduler(path, r'python .\windows_systemtray.py -y', False)
else: # MacOS
unload_command = "launchctl unload " + str(os.path.expanduser('~')) + "/Library/LaunchAgents/com.CanvasSync.Statusbar.plist"
stop_command = "launchctl stop " + str(os.path.expanduser('~')) + "/Library/LaunchAgents/com.CanvasSync.Statusbar.plist"
os.system(unload_command)
os.system(stop_command)


# If main module
if __name__ == u"__main__":
ActivateStartUpStatusbar()
19 changes: 19 additions & 0 deletions CanvasSync/GUI/startup_template.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.CanvasSync.Statusbar</string>
<key>ProgramArguments</key>
<array>
<string>[@replacePythonPath]</string>
<string>[@replaceCanvasPath]/macos_statusbar.py</string>
</array>
<key>StandardErrorPath</key>
<string>[@replaceCanvasPath]/statusbar.err</string>
<key>StandardOutPath</key>
<string>[@replaceCanvasPath]/statusbar.out</string>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
131 changes: 131 additions & 0 deletions CanvasSync/GUI/windows_systemtray.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
from PIL import Image
import pathlib, configparser, os, sys, datetime, keyring, subprocess
from pystray import Icon as icon, Menu as menu, MenuItem as item
import pystray
import PIL

class config_file:
def __init__(self, filepath):
self.filepath = filepath
if not os.path.exists(self.filepath):
open(self.filepath, 'a').close()
self.config = configparser.ConfigParser()
self.config.read(filepath)

def read(self, section, parameter):
if not self.config.has_option(section, parameter):
return None
else:
return self.config[section][parameter]

def write(self, section, parameter, value):
if not self.config.has_section(section):
self.config.add_section(section)
self.config.set(section, parameter, value)
with open(self.filepath, 'w') as configfile:
self.config.write(configfile)


def set_state(v):
def inner(icon, item):
global state
state = v
config.write('Settings', 'interval', state_dict[v])
return inner

from tkinter import *
def get_state(v):
def inner(item):
#return state == v
return config.read('Settings', 'interval') == state_dict[v]
return inner


def pop_up():
app = Tk()
app.title("CanvasSync Password")
label = Label(app, text="Please enter the CanvasSync Password:")
label.grid()
pwd = StringVar()
e1 = Entry(app, width=40, textvariable=pwd)
btn = Button(app, text="Ok", command=app.destroy)
btn.grid(row=2)
e1.grid(row=1)

app.mainloop()
return pwd.get()


def savepassword():
response = str(pop_up())
keyring.set_password('CanvasSync', 'xkcd', response)

def runSync():
print('sync')

# Import Canvas Module
path = str(pathlib.Path(__file__).parent.parent.parent) + "/bin/"
sys.path.insert(0, path)
import canvas

settings = canvas.Settings()
password = keyring.get_password('CanvasSync', 'xkcd')
canvas.do_sync(settings, password)
config.write('Last run', 'time', str(datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S")))

def preferences():
pass

def quit_icon():
#ToDo: Quit App does not work at the moment.
icon.stop()

dir_path = os.path.dirname(os.path.realpath(__file__))

if __name__ == '__main__':
image = PIL.Image.open('canvas_logo.png')

state = 0
state_dict = {
1: 'hourly',
2: 'every 6 hours',
3: 'daily',
4: 'Do not sync'
}

if keyring.get_password('CanvasSync', 'xkcd') is None:
savepassword()

# Run Scheduler as independent subprocess
path = str(os.path.abspath(os.path.join(os.path.join(os.path.abspath(__file__), '..'), '..'))) + '\\scheduler\\scheduler.py'
subprocess.Popen(["python", path])

config = config_file(str(os.path.abspath(os.path.join(os.path.join(os.path.abspath(__file__), '..'), '..'))) + "\\scheduler\\scheduler.ini")
icon('test', image, menu=menu(
item('Sync now', runSync),
item(
'Automatic sync',
menu(
item(
'hourly',
set_state(1),
checked=get_state(1),
radio=True),
item(
'every 6 hours',
set_state(2),
checked=get_state(2),
radio=True),
item(
'daily',
set_state(3),
checked=get_state(3),
radio=True),
item(
'Do not sync',
set_state(4),
checked=get_state(4),
radio=True))),
item('Preferences', preferences),
item('Quit now', quit_icon)
)).run()
Loading