This repository has been archived on 2025-02-10. You can view files and clone it, but cannot push or open issues or pull requests.
Files
beopen/client/main.py
2025-02-10 12:37:33 +00:00

2365 lines
84 KiB
Python

import kivy
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.clock import Clock
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDIconButton, MDRaisedButton
from kivymd.uix.behaviors.magic_behavior import MagicBehavior
from kivymd.uix.textfield import MDTextField
from kivymd.uix.list import OneLineAvatarIconListItem, TwoLineAvatarIconListItem, ThreeLineAvatarIconListItem, IconRightWidget, MDList
from kivymd.uix.fitimage import FitImage
from kivymd.uix.snackbar import Snackbar
from kivymd.uix.menu import MDDropdownMenu
from kivymd.uix.bottomnavigation import MDBottomNavigationItem
from kivymd.uix.list import IRightBodyTouch
from kivy.uix.camera import Camera
from kivymd.uix.screen import MDScreen
from kivymd.uix.screenmanager import MDScreenManager
from kivy.core.window import Window
from kivymd.uix.controllers import WindowController
from kivymd.uix.dialog import MDDialog
from kivymd.uix.button import MDFlatButton
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.relativelayout import MDRelativeLayout
import socketio
import os
## remove before production
import time
## remove before production
kivy.require('2.1.0')
__version__ = "0.0.2"
# IMPORTS
import uuid as uniqueid
from modules.session.session import session_info, wait, db
from modules.session.time import timestamp
from modules.session.session import setting as setting_info
from modules.handler.request import request, account_page
from modules.handler.info import image as image_info
def generate_uuid():
uuid = str(uniqueid.uuid4())
return uuid
def dict_key_verify(dictionary, keys, mode="and", *args, **kwargs):
if mode != "and" and mode != "or":
mode = "and"
if type(keys) != list:
keys = [keys]
verified = []
if type(keys) != list:
keys = [keys]
for key in keys:
if type(dictionary) != dict or key not in dictionary or not dictionary[key]:
verified.append(False)
else:
verified.append(True)
if mode == "and":
if all(verified) == True:
return True
if mode == "or":
if True in verified:
return True
return False
def go_to(string, previous_line, file):
line = previous_line
while line != string:
line = file.readline().strip()
return line
def read_to(string, file):
line = file.readline().strip()
lines = []
while line != string:
lines.append(line)
line = file.readline().strip()
return lines
def get_dialog_content(dialog_title):
with open("./data/assets/help.txt", "r") as f:
line = f.readline().strip()
line = go_to(f"[{dialog_title}:START]", line, f)
line = go_to(f"(title:START)", line, f)
title = read_to(f"(title:END)", f)
line = go_to(f"(body:START)", line, f)
body_lines = read_to(f"(body:END)", f)
body = ""
for line in body_lines:
body += line + "\n"
body = body[:-2]
return {'title': title[0], 'body': body}
def open_help(app, page, dialog_title):
content = get_dialog_content(dialog_title)
page.dialog_help = HelpDialog(page, app, title=content['title'], text=content['body'])
page.dialog_help.open()
# IMPORTS
#================== socketio START ==================
sio = socketio.Client()
session = session_info()
# http://localhost:9999
def start_client(sio, url):
print("DEBUG: starting socketio client...")
try:
if not url:
url = "http://localhost:9999"
print(f"DEBUG: Connecting with url {url}")
sio.connect(url)
print("DEBUG: socketio client online!")
return True
except:
print("DEGUB: socketio client failed to connect!")
return False
def stop_client(sio):
print("DEBUG: stopping socketio client...")
sio.disconnect()
# connect/disconnect START
@sio.event
def connect():
print("DEBUG: Connected!")
@sio.event
def connect_error(data):
print("DEBUG: connection error")
@sio.event
def disconnect():
print("Disconnected")
# connect/disconnect END
@sio.event
def recv_status(data):
session.status = data
string = f"{data['time']} | {data['level']} | {data['message']}"
print(string)
#:import Snackbar kivymd.uix.snackbar.Snackbar
# auth START
@sio.event
def recv_token(data):
wait(session).wait_username()
session.auth_tokens.append(data['token'])
db().execute("INSERT INTO tokens(token, username, expire) VALUES(?, ?, ?)", (data['token'], session.username, data['expire']))
def login_cred(username="user", password="pass"):
data = {'username': username, 'password': password}
sio.emit('login', data, callback=auth)
def auth(callback, data):
pass
# auth END
# other events START
@sio.event
def notification(data):
pass
# other events END
#================== socketio END ==================
#================== kivy START ==================
# Utility START
class ExpandText(MDLabel):
pass
class ExpandPage(MDScreen):
def __init__(self, expand_text, banner, previous_page, **kwargs):
super(ExpandPage, self).__init__(**kwargs)
self.expand_text = expand_text
self.previous_page = previous_page
self.load_content()
self.toolbar.title = banner
@property
def expand_text(self):
return self._expand_text
@expand_text.setter
def expand_text(self, value):
if type(value) != str or type(value) != list:
if type(value) == str:
value = [value]
else:
value=None
self._expand_text = value
def load_content(self):
self.text_area.clear_widgets()
for text in self.expand_text:
item = ExpandText(text=text)
self.text_area.add_widget(item)
def back(self, app):
app.set_screen(self.previous_page.name, "right")
app.sm.remove_widget(self)
class HelpDialog(MDDialog):
def __init__(self, page, app, **kwargs):
kwargs["buttons"] = [MDFlatButton(text="Close", on_release=self.close, theme_text_color = "Custom", text_color=app.theme_cls.primary_color), MDFlatButton(text="Turn off help?", on_release=self.settings, theme_text_color = "Custom", text_color=app.theme_cls.primary_color)]
super().__init__(**kwargs)
self.page = page
self.app = app
def close(self, button):
self.page.dialog_help.dismiss()
def settings(self, button):
self.close(button)
if self.page.name == "SettingsPageScreen":
return
settings_screen_name = "SettingsPageScreen"
settings_screen = SettingsPage(self.page, name=settings_screen_name)
self.app.sm.add_widget(settings_screen)
self.app.set_screen(settings_screen_name, "left")
# Utility END
# HomePage START
class HomeSwiper(MDBoxLayout):
@property
def username(self):
return self._username
@username.setter
def username(self, value):
self.ids.username.text = value
self._username = value
@property
def caption(self):
return self._caption
@caption.setter
def caption(self, value):
if value == None:
value = ""
self.ids.caption.text = value
self._caption = value
@property
def content(self):
return self._content
@content.setter
def content(self, value):
self.load_image(value)
self.ids.content.source = self.image.path
self._content = self.image.path
def __init__(self, page, post_id, **kwargs):
super().__init__(**kwargs)
self.post_id = post_id
self.page = page
self.action_menu = None
self.load_content()
def load_image(self, value):
self.image = image_info(self.post_id)
self.image.load(value)
self.ids.content.source = self.image.path
def load_content(self):
post_data = {'post_id': self.post_id}
post_content = request(sio, session).emit('post_get', post_data)['posts']
self.username = post_content['username']
self.caption = post_content['caption']
self.content = post_content['content']
user_impression_data = {'items': ['username'], 'post_id': self.post_id, 'impression_type': "like"}
post_likes = request(sio, session).emit('post_impression_get_post', user_impression_data)['impressions']
impression_data = {'post_id': self.post_id, 'impression_type': "like"}
num_post_likes = request(sio, session).emit('post_impression_count', impression_data)['impression_count']
self.ids.like_number.text = str(num_post_likes)
if post_likes:
for like in post_likes:
if self.page.username in like['username']:
self.ids.like.icon = "heart"
def like(self):
server = request(sio, session)
if self.ids.like.icon == "heart-outline":
self.ids.like.icon = "heart"
data = {'impression_type': "like", 'post_id': self.post_id}
server.emit('post_impression_set', data, None)
self.ids.like_number.text = str(int(self.ids.like_number.text) + 1)
else:
self.ids.like.icon = "heart-outline"
data = {'impression_type': "like", 'post_id': self.post_id, 'items': ['username','impression_id']}
impression_info = server.emit('post_impression_get_post', data)
if dict_key_verify(impression_info, 'impressions'):
for impression in impression_info['impressions']:
if impression['username'] == self.page.username:
impression_id = impression['impression_id']
data = {'impression_type': "like", 'impression_id': impression_id}
server.emit('post_impression_delete', data, None)
self.ids.like_number.text = str(int(self.ids.like_number.text) - 1)
def switch_to_comments(self, app, direction='up'):
comments_screen_name = "CommentsPageScreen_"+self.post_id
comments_screen = CommentsPage(self.post_id, name=comments_screen_name)
app.sm.add_widget(comments_screen)
app.set_screen(comments_screen_name, direction)
def post_options(self, app, direction='right'):
data = {'post_id': self.post_id}
delete_allowed = request(sio, session).emit("post_get_permissions", data)['delete']
if delete_allowed:
profile_item = {'text': "view profile", 'viewclass': "OneLineListItem", 'on_release': lambda x=app: self.switch_to_account(app)}
delete_item = {'text': "delete post", 'viewclass': "OneLineListItem", 'on_release': lambda: self.delete_post()}
items = [profile_item, delete_item]
self.action_menu = MDDropdownMenu(caller=self.account_button, items=items, width_mult=3)
self.action_menu.open()
else:
self.switch_to_account(app, direction)
def delete_post(self):
if self.action_menu:
self.action_menu.dismiss()
data = {'post_id': self.post_id}
request(sio, session).emit("post_delete", data, None)
self.page.home_swiper_grid.remove_widget(self)
if len(self.page.home_swiper_grid.children) == 1:
self.page.load_home()
def switch_to_account(self, app, direction='right'):
if self.action_menu:
self.action_menu.dismiss()
self.page.switch_to_account(app, self.username, direction)
class HomeLoadButton(MDBoxLayout):
def __init__(self, **kwargs):
if 'home_obj' in kwargs and kwargs['home_obj']:
if kwargs['home_obj']:
self.home_obj = kwargs['home_obj']
del kwargs['home_obj']
super().__init__(**kwargs)
def load_content(self):
self.home_obj.home_swiper_grid.remove_widget(self)
self.home_obj.load_home()
class NoPostLabel(MDBoxLayout):
pass
class MemoriesMonth(MDBoxLayout):
def get_memories_swiper_height(self):
swiper_height = Window.height * 0.8 * 0.02
return swiper_height
class SwiperMagicButton(MagicBehavior,MDIconButton):
pass
class MemoriesSwiper(MDBoxLayout):
pass
class OccupationPageButton(MDRaisedButton):
def __init__(self, tab, page, **kwargs):
super().__init__(**kwargs)
self.tab = tab
self.page = page
def switch_to_occupation(self, app):
self.tab.switch_to_occupation(app)
class OrganisationBottomItem(MDBottomNavigationItem):
def __init__(self, page, username, **kwargs):
super().__init__(**kwargs)
self.page = page
self.load_content()
self.username = username
def load_content(self):
occupation_button = OccupationPageButton(self, self.page)
level = request(sio, session).emit('auth_get')['level']
if level != "member":
self.occupation_button_area.add_widget(occupation_button)
def switch_to_occupation(self, app, direction="left"):
occupation_screen_name = "OccupationPageScreen"
occupation_screen = OccupationPage(self.page, name=occupation_screen_name)
app.sm.add_widget(occupation_screen)
app.set_screen(occupation_screen_name, direction)
def switch_to_team(self, app, direction="left"):
team_screen_name = "TeamPageScreen"
team_screen = TeamPage(self.page, self.username, name=team_screen_name)
app.sm.add_widget(team_screen)
app.set_screen(team_screen_name, direction)
class MonthListItem(OneLineAvatarIconListItem):
def __init__(self, date, posts, month_list, **kwargs):
super().__init__(**kwargs)
self.month_list = month_list
self.posts = posts
self.date = date
def day_view(self):
day_list = DayList(self.date, self.posts, self.month_list)
self.month_list.page.root_scroll.remove_widget(self.month_list)
self.month_list.page.root_scroll.add_widget(day_list)
class MonthList(MDBoxLayout):
def __init__(self, page, **kwargs):
super().__init__(**kwargs)
self.page = page
self.back_stack = [self]
self.load_content()
def load_content(self):
month_list = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
data = {'items': ['post_id', 'date']}
post_response = request(sio, session).emit("post_get_memories", data)
if dict_key_verify(post_response, 'posts'):
posts = post_response['posts']
post_months = {}
for post in posts:
if dict_key_verify(post, 'date'):
date = post['date']
date_list = date.split("-")
if dict_key_verify(post_months, date):
post_months[date].append(post)
else:
post_months[date] = [post]
for post_group in post_months:
date = post_group.split("-")
month_name = month_list[int(date[1])-1]
date_string = date[0] + ": " + month_name
item = MonthListItem(date, post_months[post_group], self, text=date_string)
self.scroll.add_widget(item)
else:
item = OneLineAvatarIconListItem(text="No memories :(")
self.scroll.add_widget(item)
class DayListItem(OneLineAvatarIconListItem):
def __init__(self, date, post, day_list, **kwargs):
super().__init__(**kwargs)
self.day_list = day_list
self.post = post
self.date = date
def post_open(self):
memory = MemoryLayout(self.post, self.day_list)
area = self.day_list.month_list.page.root_scroll
area.clear_widgets()
area.add_widget(memory)
class DayList(MDBoxLayout):
def __init__(self, date, posts, month_list, **kwargs):
super().__init__(**kwargs)
self.month_list = month_list
self.posts = posts
self.date = date
self.back_stack = self.month_list.back_stack
self.back_stack.append(self)
self.load_content()
def load_content(self):
for post in self.posts:
date_string = self.date[2]
item = DayListItem(self.date, post, self, text=date_string)
self.scroll.add_widget(item)
def back(self):
last = len(self.back_stack)-1
self.month_list.page.root_scroll.clear_widgets()
self.month_list.page.root_scroll.add_widget(self.back_stack[last-1])
self.back_stack.pop(last)
class MemoryLayout(MDBoxLayout):
def __init__(self, post, day_list, **kwargs):
super().__init__(**kwargs)
self.post = post
self.day_list = day_list
self.page = self.day_list.month_list.page
self.back_stack = self.day_list.back_stack
self.back_stack.append(self)
self.load_content()
def remove_username(self, post):
post.ids.username.text = self.post['date']
post.ids.profile_area.remove_widget(post.ids.account_button)
def load_content(self):
post = HomeSwiper(self.page, self.post['post_id'])
self.remove_username(post)
self.post_area.add_widget(post)
class HomePage(MDScreen, WindowController):
def __init__(self, username=None, app=None, **kwargs):
super().__init__(**kwargs)
post_login()
self.username = username
self.app = app
self.account_screens = []
self.notifications_screens = []
self.settings_screen = None
self.settings_screen_name = None
self.posts_displayed = []
self.post_exist = False
self.camera_widget_exists = False
self.camera_page_screen = None
self.organisation_item_exists = False
self.post_slot = request(sio, session).emit("post_slot_get")
self.posted_today()
self.load_content()
self.selected_tab = "Home"
self.help_tool = ["help", lambda x: self.open_help(self.app)]
def login(self):
login_cred()
def load_content(self):
self.load_home()
self.load_memories()
self.load_organisation()
Clock.schedule_interval(self.check_post_time, 1)
self.load_toolbar()
def load_toolbar(self):
if not setting_info("Help boxes").value:
for i, option in enumerate(self.toolbar.right_action_items):
if option[0].lower() == "help":
self.toolbar.right_action_items.pop(i)
else:
toolbar_len = len(self.toolbar.right_action_items)
for i in range(toolbar_len):
if self.toolbar.right_action_items[i][0] == "help":
return
new_toolbar = [self.help_tool] + self.toolbar.right_action_items[0:]
self.toolbar.right_action_items = new_toolbar
def on_tab_press(self, name):
self.selected_tab = name
def open_help(self, app):
level = request(sio, session).emit('auth_get')['level']
if self.selected_tab == "Home":
open_help(app, self, "Home")
elif self.selected_tab == "Memories":
open_help(app, self, "Memories")
elif self.selected_tab == "Organisation" and level == "member":
open_help(app, self, "Organisation")
elif self.selected_tab == "Organisation" and level != "member":
open_help(app, self, "Organisation-admin")
# SWITCHING
def switch_to_settings(self, app, direction='left'):
settings_screen_name = "SettingsPageScreen"
settings_screen = SettingsPage(self, name=settings_screen_name)
app.sm.add_widget(settings_screen)
app.set_screen(settings_screen_name, direction)
def switch_to_account(self, app, username=None, direction='right', *args, **kwargs):
if not username:
username = self.username
account_screen_name = "AccountPageScreen_"+username
account_screen = AccountPage(username, self, name=account_screen_name)
app.sm.add_widget(account_screen)
app.set_screen(account_screen_name, direction)
def switch_to_notifications(self, app, username=None, direction='right', *args, **kwargs):
if not username:
username = self.username
notifications_screen_name = "NotificationsScreen-"+username
notifications_screen = NotificationsPage(username, self, name=notifications_screen_name)
app.sm.add_widget(notifications_screen)
app.set_screen(notifications_screen_name, direction)
# FETCHING DATA
def fetch_posts(self):
data = {'items': ['post_id']}
posts = request(sio, session).emit('post_get_feed', data)['posts']
post_list = []
if self.post_made:
post = request(sio, session).emit("post_get_user")
if dict_key_verify(post, "posts"):
post = post['posts']
if dict_key_verify(post, "post_id"):
if post['post_id'] not in self.posts_displayed:
post_list.append(post)
if posts:
for i, post in enumerate(posts):
if post:
post_list.append(post)
return post_list
# HOME
def load_home(self):
posts = self.fetch_posts()
post_list = []
if posts:
for i, post in enumerate(posts):
if post['post_id'] not in self.posts_displayed:
exists = False
for existing_post in post_list:
if existing_post['post_id'] == post['post_id']:
exists = True
if not exists:
post_list.append(post)
posts = post_list
for i, post in enumerate(posts):
if not self.post_exist:
self.home_swiper_grid.clear_widgets()
self.post_exist = True
home_swiper = HomeSwiper(self, post['post_id'])
if i == 0:
first_home_swiper = home_swiper
# adds your own post to the top of the post list
# its done in this way below because there is no way to pre-pend with kivy widgets
# the only way is to manually modify the child list which is not recomended
if home_swiper.username == self.username:
# saves the previous post list
old_grid = self.home_swiper_grid.children[1:]
# clears the grid
self.home_swiper_grid.clear_widgets()
# adds your new post at the top
self.home_swiper_grid.add_widget(home_swiper)
# adds the rest of the previous posts
for old_post in old_grid:
self.home_swiper_grid.add_widget(old_post)
first_home_swiper = home_swiper
else:
self.home_swiper_grid.add_widget(home_swiper)
self.posts_displayed.append(post['post_id'])
if i == 4:
break
if "first_home_swiper" in locals():
self.home_swiper_scroll.scroll_to(first_home_swiper)
if not posts:
Snackbar(text="Sorry, no more posts").open()
else:
if not self.post_exist:
self.home_swiper_grid.clear_widgets()
self.home_swiper_grid.add_widget(NoPostLabel())
self.load_more_button = HomeLoadButton(home_obj=self)
self.home_swiper_grid.add_widget(self.load_more_button)
def get_home_swiper_height(self):
swiper_height = Window.height * 0.70
return swiper_height
# MEMORIES
def get_memories_swiper_height(self):
month_height = self.get_memories_month_height()
swiper_height = month_height * 0.8 * 0.02
return swiper_height
def get_memories_month_height(self):
month_height = Window.height * 2
return month_height
def load_memories(self):
self.root_scroll.clear_widgets()
item = MonthList(self)
self.root_scroll.add_widget(item)
# STATS
def load_stats(self):
pass
# ORGANISATION
def load_organisation(self):
if not self.organisation_item_exists:
self.organisation_item_exists = True
self.bottom_navigation.add_widget(OrganisationBottomItem(self, self.username))
# SIZE
def update(self):
self.home_swiper_grid.row_default_height = self.get_home_swiper_height()
def on_size(self, *args):
self.update()
# Post time
def posted_today(self):
date = {'items': ['date']}
posts = request(sio, session).emit("post_get_memories", date)['posts']
if posts:
date = request(sio, session).emit("get_date")['date']
for post in posts:
if date == post['date']:
self.post_made = True
return
self.post_made = False
def check_post_time(self, dt):
now = timestamp().now
if self.post_slot['post_slot_start'] < now and self.post_slot['post_slot_end'] > now and not self.post_made:
if not self.camera_widget_exists:
self.toolbar.right_action_items.append(["camera", lambda x: self.switch_to_camera(self.app, direction='up')])
self.camera_widget_exists = True
else:
for i, action_item in enumerate(self.toolbar.right_action_items):
if "camera" in action_item:
self.toolbar.right_action_items.pop(i)
break
def switch_to_camera(self, app, direction="up"):
camera_page_screen_name = "CameraPageScreen"
self.camera_page_screen = CameraPage(self, name=camera_page_screen_name)
app.sm.add_widget(self.camera_page_screen)
app.set_screen(camera_page_screen_name, direction)
# First time
def check_first_time(self, app):
occupation = request(sio, session).emit("occupation_get")
profile = request(sio, session).emit("profile_get", {'items': ['role', 'name']})
friends = request(sio, session).emit("friend_get")['friends']
if not occupation['occupation_id'] and not friends and not profile['role'] and not profile['name']:
first_time_page_screen_name = "FirstTimePage"
first_time_page_screen = FirstTimePage(name=first_time_page_screen_name)
app.sm.add_widget(first_time_page_screen)
app.set_screen(first_time_page_screen_name, "down")
# HomePage END
# Comments START
class CommentContainer(IRightBodyTouch, MDBoxLayout):
pass
class Comment(TwoLineAvatarIconListItem):
def __init__(self, username, comment_id, page, **kwargs):
super().__init__(**kwargs)
self.username = username
self.comment_id = comment_id
self.page = page
self.screen_prefix = "comment"
self.action_menu = None
self.load_content()
def liked_previously(self):
data = {'comment_id': self.comment_id}
impressions = request(sio, session).emit("comment_impression_get_comment", data)['impressions']
if impressions:
for impression in impressions:
if dict_key_verify(impression, "username"):
if session.username == impression['username']:
self.impression_id = impression['impression_id']
return True
return False
def load_content(self):
if self.liked_previously():
self.like_button.icon = "heart"
data = {'impression_type': "like", 'comment_id': self.comment_id}
count = request(sio, session).emit("comment_impression_count", data)['impression_count']
self.like_count.text = str(count)
def expand(self, app):
expand_page_name = f"{self.screen_prefix}_expand_page_{self.username}"
expand_page = ExpandPage(self.secondary_text, self.text+"'s comment", self.page, name=expand_page_name)
app.sm.add_widget(expand_page)
app.set_screen(expand_page_name, "left")
def like(self):
if self.like_button.icon == "heart-outline":
data = {'impression_type': "like", 'comment_id': self.comment_id}
request(sio, session).emit('comment_impression_set', data, None)
if self.liked_previously():
self.like_button.icon = "heart"
self.like_count.text = str(int(self.like_count.text)+1)
else:
self.like_button.icon = "heart-outline"
data = {'impression_id': self.impression_id}
request(sio, session).emit("comment_impression_delete", data, None)
self.like_count.text = str(int(self.like_count.text)-1)
def profile(self, app):
if self.action_menu:
self.action_menu.dismiss()
account_page_name = f"{self.screen_prefix}_account_page_{self.username}"
account_page = AccountPage(self.username, self.page, remove_on_exit=True, name=account_page_name)
app.sm.add_widget(account_page)
app.set_screen(account_page_name, "right")
def delete_comment(self):
if self.action_menu:
self.action_menu.dismiss()
data = {'comment_id': self.comment_id}
request(sio, session).emit("comment_delete", data, None)
self.page.comment_stack.remove_widget(self)
if not self.page.comment_stack.children:
self.page.load_content()
def action_options(self, app):
data = {'comment_id': self.comment_id}
delete_allowed = request(sio, session).emit("comment_get_permissions", data)['delete']
if delete_allowed:
profile_item = {'text': "view profile", 'viewclass': "OneLineListItem", 'on_release': lambda x=app: self.profile(app)}
delete_item = {'text': "delete comment", 'viewclass': "OneLineListItem", 'on_release': lambda: self.delete_comment()}
items = [profile_item, delete_item]
self.action_menu = MDDropdownMenu(caller=self.profile_button, items=items, width_mult=3)
self.action_menu.open()
else:
self.profile(app)
class CommentsPage(MDScreen):
def __init__(self, post_id, **kwargs):
super(CommentsPage, self).__init__(**kwargs)
self.post_id = post_id
self.comments = []
self.comments_exist = False
self.load_content()
def get_comments(self):
data = {'post_id': self.post_id}
comments = request(sio, session).emit("comment_get_post", data)['comments']
return comments
def add_comment(self, comment):
if not self.comments:
self.comment_stack.clear_widgets()
comment_id = comment['comment_id']
username = comment['username']
comment_item = Comment(username, comment_id, self, text=username, secondary_text=comment['content'])
self.comments.append(comment_id)
self.comment_stack.add_widget(comment_item)
# LOADING
def load_content(self):
self.comment_stack.clear_widgets()
comments = self.get_comments()
if comments:
for comment in comments:
self.add_comment(comment)
else:
item = OneLineAvatarIconListItem(text="No comments :(")
self.comment_stack.add_widget(item)
def submit(self):
content = self.comment_field.text
data = {'post_id': self.post_id, 'content': content}
request(sio, session).emit("comment_set", data, None)
self.comment_field.text = ""
comments = self.get_comments()
for comment in comments:
if comment['username'] == session.username and comment['content'] == content and comment['comment_id'] not in self.comments:
self.add_comment(comment)
break
# SWITCHING
def switch_to_home(self, app):
app.set_screen("HomePageScreen", 'down')
app.sm.remove_widget(self)
# Comments END
# Post START
class CameraPage(MDScreen):
def __init__(self, previous_page, **kwargs):
super(CameraPage, self).__init__(**kwargs)
self.path = "data/images/post.png"
self.post_slot = request(sio, session).emit("post_slot_get")
self.previous_page = previous_page
Window.size = (800, 600)
self.load_content()
self.refresh_time()
Clock.schedule_interval(self.refresh_time, 1)
def load_content(self):
self.camera = Camera(play=True)
self.camera_area.add_widget(self.camera)
if not setting_info("Help boxes").value:
for i, option in enumerate(self.toolbar.right_action_items):
if option[0].lower() == "help":
self.toolbar.right_action_items.pop(i)
def open_help(self, app):
open_help(app, self, "Camera")
def format_time(self, time_left):
time_left = int(time_left)
seconds = time_left%60
minutes = time_left//60
hours = 0
if minutes > 60:
hours = minutes//60
minutes = minutes - hours*60
time_format = f"{hours}:{minutes}:{seconds}"
return time_format
def refresh_time(self, dt=None):
length = self.post_slot['post_slot_end'] - self.post_slot['post_slot_start']
time_in = timestamp().now - self.post_slot['post_slot_start']
time_left = round(length - time_in, 2)
time_format = self.format_time(time_left)
self.toolbar.title = f"Time left: {time_format}"
def capture(self, app):
self.camera.export_to_png(self.path)
self.camera_to_post(app)
def camera_to_post(self, app):
post_review_page_screen_name = "PostReviewPage"
post_review_page_screen = PostReviewPage(self, self.path, name=post_review_page_screen_name)
app.sm.add_widget(post_review_page_screen)
app.set_screen(post_review_page_screen_name, "left")
def exit(self, app):
app.set_screen("HomePageScreen", "down")
app.sm.remove_widget(self)
Window.size = (800, 1000)
class PostReviewPage(MDScreen):
def __init__(self, camera_page, path, **kwargs):
super(PostReviewPage, self).__init__(**kwargs)
self.path = path
self.camera_page = camera_page
self.post_slot = request(sio, session).emit("post_slot_get")
self.load_content()
self.refresh_time()
Clock.schedule_interval(self.refresh_time, 1)
def load_content(self):
self.image.source = self.path
if not setting_info("Help boxes").value:
for i, option in enumerate(self.toolbar.right_action_items):
if option[0].lower() == "help":
self.toolbar.right_action_items.pop(i)
def open_help(self, app):
open_help(app, self, "PostReview")
def refresh_time(self, dt=None):
length = self.post_slot['post_slot_end'] - self.post_slot['post_slot_start']
time_in = timestamp().now - self.post_slot['post_slot_start']
time_left = round(length - time_in, 2)
time_format = self.camera_page.format_time(time_left)
self.toolbar.title = f"Time left: {time_format}"
def post(self, app):
with open(self.path, "rb") as image:
image_data = image.read()
data = {'content': image_data, 'caption': self.caption.text}
request(sio, session).emit("post_set", data, None)
self.camera_page.previous_page.post_made = True
self.image.source = ""
os.remove(self.path)
self.exit(app, "down")
self.camera_page.previous_page.load_memories()
self.camera_page.previous_page.load_home()
def retake(self, app):
os.remove(self.path)
self.post_to_camera(app)
def post_to_camera(self, app, direction="right"):
app.set_screen(self.camera_page.name, direction)
self.ids.image_area.remove_widget(self.image)
app.sm.remove_widget(self)
def exit(self, app, direction="down"):
app.set_screen("HomePageScreen", "down")
if not self.camera_page.previous_page.post_made:
os.remove(self.path)
app.sm.remove_widget(self.camera_page)
app.sm.remove_widget(self)
Window.size = (800, 1000)
# Post END
# Acccount START
class ProfileInfo(TwoLineAvatarIconListItem):
def __init__(self, account_page=None, info_type=None, **kwargs):
super().__init__(**kwargs)
self.info_type = info_type
self.account_page = account_page
def set_title(self, text):
if text and type(text) == str:
text = (text.replace("_", " ")).capitalize()
self.text = text
def set_content(self, text):
if text and type(text) == str:
self.secondary_text = text
def make_editable(self):
button = InfoEditButton(self.account_page, self.info_type)
self.add_widget(button)
class InfoEditButton(IconRightWidget):
def __init__(self, account_page_obj=None, info_type=None, **kwargs):
super().__init__(**kwargs)
self.info_type = info_type
self.account_page_obj = account_page_obj
self.account_page_obj.currently_editing = None
def change_info(self):
if self.icon == "pencil":
if self.account_page_obj.currently_editing:
self.account_page_obj.currently_editing.icon = "pencil"
self.account_page_obj.currently_editing = self
self.account_page_obj.picture_to_textbox(self.info_type)
else:
self.account_page_obj.textbox_to_picture()
class BioEditButton(MDIconButton):
def __init__(self, account_page_obj=None, info_type="biography", **kwargs):
super().__init__(**kwargs)
self.info_type = info_type
self.account_page_obj = account_page_obj
self.account_page_obj.currently_editing = None
def change_info(self):
if self.icon == "pencil":
if self.account_page_obj.currently_editing:
self.account_page_obj.currently_editing.icon = "pencil"
self.account_page_obj.currently_editing = self
self.account_page_obj.picture_to_textbox(self.info_type)
else:
self.account_page_obj.textbox_to_picture()
class ProfilePicture(FitImage):
pass
class InfoChangeBox(MDBoxLayout):
def __init__(self, page, info_type, username=session.username, **kwargs):
super().__init__(**kwargs)
self.username = username
self.info_type = info_type
self.page = page
self.load_content()
def load_content(self):
self.text_field.text = self.page.info[self.info_type]
def save(self):
new_value = self.text_field.text
self.page.info[self.info_type] = new_value
account_page(sio).set_profile(self.info_type, new_value, self.username)
self.page.textbox_to_picture()
class OccupationChange(MDBoxLayout):
def __init__(self, page=None, **kwargs):
super().__init__(**kwargs)
self.occupations = request(sio, session).emit('occupation_get_all')
self.current_selection = None
self.occupations_info = []
self.menu = None
if page:
self.page = page
def selection_menu(self):
if dict_key_verify(self.occupations, 'occupations'):
self.occupations_info = self.occupations['occupations']
items = []
for i, occupation in enumerate(self.occupations_info):
item = {'text': occupation['name'], 'viewclass': "OneLineListItem", 'on_release': lambda x=i: self.selection(x)}
items.append(item)
self.menu = MDDropdownMenu(caller=self.occupation_select, items=items, width_mult=2)
self.menu.open()
else:
message = "No occupations"
Snackbar(text=message).open()
def selection(self, item_num):
self.occupation_select.text = self.occupations_info[item_num]['name']
self.occupation_description.text = self.occupations_info[item_num]['description']
self.current_selection = item_num
self.menu.dismiss()
class UserOccupationChange(OccupationChange):
def __init__(self, page=None, **kwargs):
super().__init__(page, **kwargs)
self.load_content()
def cancel(self):
request(sio, session).emit('occupation_delete_request', {}, None)
message = f"{session.status['level']}: {session.status['message']}"
Snackbar(text=message).open()
self.load_content()
self.page.textbox_to_picture()
def submit(self):
if self.current_selection or self.current_selection == 0:
data = {'occupation_id': self.occupations_info[self.current_selection]['occupation_id']}
request(sio, session).emit('occupation_set_request', data, None)
else:
message = "No selection made"
Snackbar(text=message).open()
self.load_content()
self.occupation_select.text = "Select an occupation"
self.occupation_description.text = ""
self.page.textbox_to_picture()
def load_content(self):
occupation_request = request(sio, session).emit('occupation_get_request')
if dict_key_verify(occupation_request, 'occupation_id'):
occupation = request(sio, session).emit('occupation_get', {'occupation_id': occupation_request['occupation_id']})
if occupation:
self.request_occupation.text = occupation['name']
if occupation_request['approved']:
request_status = "Approved"
else:
request_status = "Pending"
self.request_status.text = "Status: "+request_status
else:
Snackbar(text=session.status).open()
class ManagementOccupationChange(OccupationChange):
def __init__(self, page, **kwargs):
super().__init__(**kwargs)
self.page = page
def submit(self):
if self.occupations_info:
data = {'occupation_id': self.occupations_info[self.current_selection]['occupation_id']}
request(sio, session).emit('occupation_set', data, None)
message = f"{session.status['message']}"
self.occupation_select.text = "Select an occupation"
self.occupation_description.text = ""
else:
message = f"No occupation selected"
Snackbar(text=message).open()
if self.occupations_info:
self.page.textbox_to_picture()
class AccountPage(MDScreen):
def __init__(self, username=session.username, previous_page=None, remove_on_exit=True, **kwargs):
super(AccountPage, self).__init__(**kwargs)
self.username = username
self.info_objs = []
self.bio_edit_button = None
self.load_content()
self.friend_page_screen = None
self.remove_on_exit = remove_on_exit
if previous_page == None:
self.previous_page = "HomePageScreen"
else:
self.previous_page = previous_page.name
def load_content(self):
self.above_info.clear_widgets()
self.profile_info_view.clear_widgets()
if self.bio_edit_button:
self.profile_bio_view.remove_widget(self.bio_edit_button)
req = request(sio, session)
data = {'username': self.username}
self.info = req.emit("profile_get", data)
permissions_data = {'username': session.username, 'target_username': self.username}
self.permissions = req.emit("profile_get_permissions", permissions_data)
if self.username != session.username:
self.toolbar.title = self.username+"'s Profile"
level = req.emit('auth_get')['level']
if level == "member":
self.toolbar.left_action_items = []
if dict_key_verify(self.info, "occupation_id"):
team_data = {'occupation_id': self.info['occupation_id'], 'items': ["name"]}
self.info['team'] = req.emit("team_get", team_data)['name']
occupation_data = {'occupation_id': self.info['occupation_id'], 'items': ["name"]}
self.info['occupation'] = req.emit("occupation_get", occupation_data)['name']
else:
self.info['team'] = ""
self.info['occupation'] = ""
del self.info['occupation_id']
self.info['username'] = self.username
order = ['username', 'name', 'role', 'occupation', 'team']
self.bio_edit_button = BioEditButton(self)
if self.info['biography']:
self.biography_content.text = self.info['biography']
else:
self.biography_content.text = ""
self.info['biography'] = ""
if self.permissions['edit']:
self.profile_bio_view.add_widget(self.bio_edit_button)
for key in order:
if not self.info[key]:
self.info[key] = ""
profile_info = ProfileInfo(self, key)
if self.permissions['edit'] and key in ['name', 'role', 'occupation', 'team']:
profile_info.make_editable()
profile_info.set_title(key)
profile_info.set_content(self.info[key])
self.profile_info_view.add_widget(profile_info)
self.info_objs.append(profile_info)
self.profile_picture = ProfilePicture()
self.above_info.add_widget(self.profile_picture)
if not setting_info("Help boxes").value:
for i, option in enumerate(self.toolbar.right_action_items):
if option[0].lower() == "help":
self.toolbar.right_action_items.pop(i)
def open_help(self, app):
open_help(app, self, "Profile")
def refresh_content(self):
self.load_content()
def picture_to_textbox(self, info_type):
self.currently_editing.icon = "close"
self.above_info.clear_widgets()
level = request(sio, session).emit('auth_get')['level']
if info_type == 'occupation' or info_type == 'team':
if level == "member":
self.change = UserOccupationChange(self)
else:
self.change = ManagementOccupationChange(self)
else:
self.change = InfoChangeBox(self, info_type, self.username)
self.above_info.add_widget(self.change)
def textbox_to_picture(self):
self.above_info.clear_widgets()
self.above_info.add_widget(self.profile_picture)
self.currently_editing.icon = "pencil"
self.refresh_content()
def switch_to_friend(self, app, direction="right"):
friend_page_screen_name = "FriendPageScreen_" + self.username
friend_page_screen = FriendPage(self, self.username, name=friend_page_screen_name)
app.sm.add_widget(friend_page_screen)
app.set_screen(friend_page_screen_name, direction)
def back(self, app, direction="left"):
app.set_screen(self.previous_page, direction)
if self.remove_on_exit:
app.sm.remove_widget(self)
# Acccount END
# Settings START
class SettingRoot(MDBoxLayout):
def __init__(self, title, page, **kwargs):
super().__init__(**kwargs)
self.title = title
self.page = page
self.load_content()
def load_content(self):
self.setting = setting_info(self.title)
self.set_title(self.setting.title)
self.set_description(self.setting.description)
self.setting_icon.icon = self.setting.icon
def set_title(self, text):
if text and type(text) == str:
self.setting_title.text = text
def set_description(self, text):
if text and type(text) == str:
self.setting_description.text = text
class SettingSwitch(SettingRoot):
def load_content(self):
super().load_content()
self.toggle.active = self.setting.value
def on_toggle(self, app):
self.page.help_tool = ["help", lambda app: self.page.open_help(app)]
self.setting.change_value(self.toggle.active)
self.page.load_toolbar()
app.homepage_screen.load_toolbar()
class SettingTextField(SettingRoot):
def __init__(self, title, **kwargs):
super().__init__(title, **kwargs)
self.submission_func = self.submit_url
def load_content(self):
super().load_content()
self.input_field.text = self.setting.value
def submit_func(self):
self.setting.change_value(self.input_field.text)
self.submission_func()
self.page.load_toolbar()
app.homepage_screen.load_toolbar()
def submit_url(self):
self.error = True
try:
result = urlopen(self.text)
except HTTPError as e:
pass
except URLError as e:
pass
except ValueError as e:
pass
else:
self.error = False
class ShutdownButton(MDRaisedButton):
def __init__(self, page, **kwargs):
super().__init__(**kwargs)
self.page = page
def shutdown(self, app):
request(sio, session).emit("shutdown", None, None)
#app.disconnected()
class SettingsPage(MDScreen):
def __init__(self, previous_page, **kwargs):
super(SettingsPage, self).__init__(**kwargs)
self.previous_page = previous_page
self.load_content()
def load_content(self):
self.settings_stack.clear_widgets()
settings = db().execute("SELECT title, state FROM settings")
if settings:
for setting in settings:
if setting[1] != None:
setting_obj = SettingSwitch(setting[0], self)
else:
setting_obj = SettingTextField(setting[0], self)
self.settings_stack.add_widget(setting_obj)
self.level = request(sio, session).emit('auth_get')['level']
if self.level == "admin":
button = ShutdownButton(self)
self.static_buttons.add_widget(button)
self.load_toolbar()
def load_toolbar(self):
if not self.toolbar.right_action_items:
self.toolbar.right_action_items = [self.help_tool]
if not setting_info("Help boxes").value:
for i, option in enumerate(self.toolbar.right_action_items):
if option[0].lower() == "help":
self.toolbar.right_action_items.pop(i)
def open_help(self, app):
open_help(app, self, "Settings")
def logout(self, app):
clean_directories()
session.clear()
app.switch_to_login()
def back(self, app):
app.sm.remove_widget(self)
self.previous_page.load_content()
app.set_screen(self.previous_page.name, "right")
# Settings END
# Notification START
class NotificationItem(TwoLineAvatarIconListItem):
def __init__(self, page, notification_id, username, **kwargs):
super().__init__(**kwargs)
self.notification_id = notification_id
self.username = username
self.page = page
self.content = ""
def set_title(self, text):
if text and type(text) == str:
self.text = text
self.title = text
def set_content(self, text):
if text and type(text) == str:
self.secondary_text = text
self.content = text
def delete(self):
data = {'notification_id': self.notification_id, 'username': self.username}
request(sio, session).emit('notification_remove', data, None)
self.page.notification_stack.remove_widget(self)
self.page.load_content()
def expand(self, app):
expand_page = ExpandPage([self.title, self.content], app)
app.sm.add_widget(expand_page)
class NotificationsPage(MDScreen):
def __init__(self, username=None, previous_page=None, **kwargs):
super(NotificationsPage, self).__init__(**kwargs)
session.notification_page = self
self.username = username
self.previous_page = previous_page
self.notifications = None
self.load_content()
def load_content(self):
self.notifications = request(sio, session).emit('notification_get', {'username': self.username})['notifications']
self.notification_stack.clear_widgets()
if self.notifications:
for notification in self.notifications:
notification_obj = NotificationItem(self, notification['notification_id'], self.username)
if dict_key_verify(notification, 'title'):
notification_obj.set_title(notification['title'])
if dict_key_verify(notification, 'content'):
content_text = notification['content']
notification_obj.set_content(content_text)
self.notification_stack.add_widget(notification_obj)
else:
item = OneLineAvatarIconListItem(text="No notifications")
self.notification_stack.add_widget(item)
if self.username and self.username != session.username:
self.toolbar.title = self.username+"'s Notifications"
if not setting_info("Help boxes").value:
for i, option in enumerate(self.toolbar.right_action_items):
if option[0].lower() == "help":
self.toolbar.right_action_items.pop(i)
def open_help(self, app):
open_help(app, self, "Notifications")
def add_notification(self, notification):
notification_item = NotificationItem(self, notification['notification_id'], self.username)
content_text = notification['title']
if dict_key_verify(notification, 'content'):
notification_item.set_content(notification['content'])
self.notification_stack.add_widget(notification_item)
def back(self, app, direction="left"):
app.set_screen(self.previous_page.name, direction)
app.sm.remove_widget(self)
# Notification END
# Friend START
class BaseFriendItem(OneLineAvatarIconListItem):
def __init__(self, obj=None, **kwargs):
super().__init__(**kwargs)
self.page_obj = obj
self.friend_profile_screen_name = None
self.friend_profile_screen = None
def refresh_content(self):
if self.page_obj:
self.page_obj.load_content()
def profile(self, app):
new_friend_profile_screen_name = self.profile_prefix+"ProfilePage"+self.text
if new_friend_profile_screen_name != self.friend_profile_screen_name:
if self.friend_profile_screen_name:
app.sm.remove_widget(self.friend_profile_screen)
self.friend_profile_screen_name = new_friend_profile_screen_name
self.friend_profile_screen = AccountPage(self.text, self.page_obj, name=self.friend_profile_screen_name)
app.sm.add_widget(self.friend_profile_screen)
app.set_screen(self.friend_profile_screen_name, "right")
class IncomingRequestItem(BaseFriendItem):
def __init__(self, obj=None, **kwargs):
super().__init__(obj, **kwargs)
self.profile_prefix = "IncomingRequest"
def accept(self):
self.verdict('approve')
def reject(self):
self.verdict('reject')
def verdict(self, verdict):
data = {'friend_username': self.text}
request(sio, session).emit('friend_'+verdict+'_request', data, None)
self.refresh_content()
self.page_obj.friend_page.load_content()
class OutgoingRequestItem(BaseFriendItem):
def __init__(self, obj=None, **kwargs):
super().__init__(obj, **kwargs)
self.profile_prefix = "OutgoingRequest"
def cancel(self):
data = {'friend_username': self.text}
request(sio, session).emit('friend_remove_request', data, None)
self.refresh_content()
class RecomendationItem(BaseFriendItem):
def __init__(self, obj=None, **kwargs):
super().__init__(obj, **kwargs)
self.profile_prefix = ""
def add_friend(self):
self.page_obj.add_friend(self.text)
class FriendItem(BaseFriendItem):
def __init__(self, obj=None, **kwargs):
super().__init__(obj, **kwargs)
self.profile_prefix = "Friend"
def remove(self):
data = {'friend_username': self.text}
request(sio, session).emit('friend_remove', data, None)
self.refresh_content()
class FriendPage(MDScreen):
def __init__(self, account_page, username, **kwargs):
super(FriendPage, self).__init__(**kwargs)
self.account_page = account_page
self.username = username
self.friend_request_screens = []
self.load_content()
def load_content(self):
data = {'username': self.username}
self.friends = request(sio, session).emit("friend_get")['friends']
self.friend_list.clear_widgets()
if self.friends:
for friend in self.friends:
friend_info = FriendItem(self, text=friend['username'])
self.friend_list.add_widget(friend_info)
else:
friend_info = OneLineAvatarIconListItem(text="No friends")
self.friend_list.add_widget(friend_info)
if not setting_info("Help boxes").value:
for i, option in enumerate(self.toolbar.left_action_items):
if option[0].lower() == "help":
self.toolbar.left_action_items.pop(i)
self.account_page.load_content()
def open_help(self, app):
open_help(app, self, "Friends")
def switch_to_friend_request(self, app, username=None, direction='right'):
if not username:
username = self.username
friend_request_screen_name = "FriendRequestPageScreen_"+username
friend_request_screen = FriendRequestPage(self, username, name=friend_request_screen_name)
app.sm.add_widget(friend_request_screen)
app.set_screen(friend_request_screen_name, direction)
def switch_to_account(self, app):
app.set_screen(self.account_page.name, "left")
app.sm.remove_widget(self)
class FriendRequestPage(MDScreen):
def __init__(self, friend_page, username, **kwargs):
super(FriendRequestPage, self).__init__(**kwargs)
self.username = username
self.friend_page = friend_page
self.load_content()
def _get_request(self, mode="incoming", username=None):
requests_data = request(sio, session).emit("friend_get_requests", {'username': username, 'mode': mode})
if dict_key_verify(requests_data, "requests"):
requests = requests_data['requests']
else:
requests = []
return requests
def load_content(self):
self.incoming_requests.clear_widgets()
self.outgoing_requests.clear_widgets()
self.recomendations.clear_widgets()
self.incoming = self._get_request("incoming", self.username)
if not self.incoming:
self.incoming = []
self.incoming_requests.add_widget(OneLineAvatarIconListItem(text="No incoming requests"))
self.outgoing = self._get_request("outgoing", self.username)
if not self.outgoing:
self.outgoing = []
self.outgoing_requests.add_widget(OneLineAvatarIconListItem(text="No outgoing requests"))
for incoming in self.incoming:
self.incoming_requests.add_widget(IncomingRequestItem(self, text=incoming))
for outgoing in self.outgoing:
self.outgoing_requests.add_widget(OutgoingRequestItem(self, text=outgoing))
data = {'amount': 5}
self.friend_recomends = request(sio, session).emit('friend_get_recomendations', data)
if dict_key_verify(self.friend_recomends, "recomended"):
self.friend_recomends = self.friend_recomends["recomended"]
else:
self.friend_recomends = []
self.recomendations.add_widget(OneLineAvatarIconListItem(text="No recommendations sorry"))
for recomend in self.friend_recomends:
self.recomendations.add_widget(RecomendationItem(self, text=recomend['username']))
def add_friend_search(self):
message = "No username entered"
if self.username_select.text:
self.add_friend(self.username_select.text)
if session.status['level'].lower() != "info":
self.username_select.error = True
else:
self.username_select.text = ""
else:
self.username_select.error = True
def add_friend(self, username):
data = {'friend_username': username}
request(sio, session).emit('friend_add_request', data, None)
message = f"{session.status['level']}: {session.status['message']}"
Snackbar(text=message).open()
self.load_content()
def switch_to_friend(self, app, username=None, direction='left'):
app.set_screen(self.friend_page.name, direction)
app.sm.remove_widget(self)
# Friend END
# OCCUPATION START
class ManageOccupationChange(OccupationChange):
def submit(self):
if self.current_selection:
data = {'occupation_id': occupations[i]['occupation_id'], 'username': self.username_select.text}
request(sio, session).emit('occupation_set', data)
message = f"{session.status['level']}: {session.status['message']}"
Snackbar(text=message).open()
if session.status['level'].lower() != "info":
self.username_select.error = True
else:
message = "No selection made"
Snackbar(text=message).open()
class BaseOccupationItem(ThreeLineAvatarIconListItem):
def __init__(self, occupation_id, obj=None, **kwargs):
super().__init__(**kwargs)
self.occupation_id = occupation_id
self.page_obj = obj
data = {'occupation_id': self.occupation_id}
class OccupationItem(BaseOccupationItem):
def edit(self):
self.page_obj.occupation_edit(self.occupation_id, self.text, self.secondary_text)
def delete(self):
self.page_obj.occupation_delete(self.occupation_id)
self.page_obj.load_content()
class OccupationRequestItem(BaseOccupationItem):
def refresh_content(self):
self.page_obj.load_content()
def accept(self):
self.verdict("approve")
def reject(self):
self.verdict("reject")
def verdict(self, verdict):
data = {'username': self.text}
request(sio, session).emit('occupation_'+verdict+'_request', data, None)
self.refresh_content()
class OccupationEdit(MDBoxLayout):
def __init__(self, page, occupation_id, name, description, **kwargs):
super().__init__(**kwargs)
self.name = name
self.description = description
self.occupation_id = occupation_id
self.page = page
self.load_content()
def load_content(self):
self.ids.name.text = self.name
self.ids.description.text = self.description
def submit(self):
data = {'name': self.ids.name.text, 'description': self.ids.description.text, 'occupation_id': self.occupation_id}
request(sio, session).emit('occupation_edit', data, None)
self.page.load_content()
self.page.edit_area.clear_widgets()
self.page.edit_area.add_widget(OccupationCreate(self))
class OccupationCreate(MDBoxLayout):
def __init__(self, page, **kwargs):
super().__init__(**kwargs)
self.page = page
def create(self):
data = {'name': self.ids.name.text, 'description': self.ids.description.text}
request(sio, session).emit('occupation_create', data, None)
message = f"{session.status['level']}: {session.status['message']}"
Snackbar(text=message).open()
self.ids.name.text = ""
self.ids.description.text = ""
self.page.load_content()
class OccupationPage(MDScreen):
def __init__(self, previous_page, **kwargs):
super(OccupationPage, self).__init__(**kwargs)
self.previous_page = previous_page
self.load_content()
def load_content(self):
occupations = request(sio, session).emit('occupation_get_all')['occupations']
self.occupations.clear_widgets()
if occupations:
for occupation in occupations:
item = OccupationItem(occupation['occupation_id'], self, text=occupation['name'], secondary_text=occupation['description'])
self.occupations.add_widget(item)
else:
item = OneLineAvatarIconListItem(text="No occupations")
self.occupations.add_widget(item)
self.edit_area.clear_widgets()
self.edit_area.add_widget(OccupationCreate(self))
if not setting_info("Help boxes").value:
for i, option in enumerate(self.toolbar.right_action_items):
if option[0].lower() == "help":
self.toolbar.right_action_items.pop(i)
self.previous_page.load_toolbar()
def open_help(self, app):
open_help(app, self, "Occupation")
def occupation_edit(self, occupation_id, name, description):
edit_space = OccupationEdit(self, occupation_id, name, description)
self.edit_area.clear_widgets()
self.edit_area.add_widget(edit_space)
def occupation_delete(self, occupation_id):
data = {'occupation_id': occupation_id}
request(sio, session).emit('occupation_delete_occupation', data, None)
Snackbar(text="Occupation deleted").open()
def switch_to_occupation_request(self, app, direction='left'):
occupation_request_screen_name = "OccupationRequestPageScreen"
occupation_request_screen = OccupationRequestPage(self, name=occupation_request_screen_name)
app.sm.add_widget(occupation_request_screen)
app.set_screen(occupation_request_screen_name, direction)
def back(self, app, direction="right"):
app.set_screen("HomePageScreen", direction)
app.sm.remove_widget(self)
class OccupationRequestPage(MDScreen):
def __init__(self, previous_page, **kwargs):
super(OccupationRequestPage, self).__init__(**kwargs)
self.previous_page = previous_page
self.load_content()
def load_content(self):
requests = request(sio, session).emit('occupation_get_all_requests')['requests']
self.change_requests.clear_widgets()
if requests:
for request_info in requests:
data = {'occupation_id': request_info['occupation_id']}
occupation = request(sio, session).emit('occupation_get', data)
occupation_request = OccupationRequestItem(request_info['occupation_id'], self, text=request_info['username'], secondary_text = occupation['name'], tertiary_text=occupation['description'])
self.change_requests.add_widget(occupation_request)
else:
self.change_requests.add_widget(OneLineAvatarIconListItem(text="No requests"))
def back(self, app, direction='right'):
app.set_screen(self.previous_page.name, direction)
app.sm.remove_widget(self)
# OCCUPATION END
# TEAM START
class LeaderItem(OneLineAvatarIconListItem):
def __init__(self, leader_username, page=None, **kwargs):
super().__init__(**kwargs)
self.page = page
self.leader_username = leader_username
self.text = leader_username
def delete(self):
data = {'leaders': [{'username': self.leader_username}]}
request(sio, session).emit('team_delete_leaders', data, None)
self.page.load_content()
class AddLeaderButton(MDRaisedButton):
def __init__(self, page=None, **kwargs):
super().__init__(**kwargs)
self.page = page
def add_leader(self):
self.page.button_to_add()
class ChangeNameButton(MDRaisedButton):
def __init__(self, page=None, **kwargs):
super().__init__(**kwargs)
self.page = page
def change_name(self):
self.page.button_to_add("name")
class AddLeader(MDBoxLayout):
def __init__(self, page=None, **kwargs):
super().__init__(**kwargs)
self.page = page
def submit(self):
data = {'leaders': [{'username': self.ids.username.text}]}
request(sio, session).emit('team_set', data, None)
self.page.add_to_button()
class ChangeName(MDBoxLayout):
def __init__(self, page=None, **kwargs):
super().__init__(**kwargs)
self.page = page
def submit(self):
team_data = {'name': self.ids.name.text}
request(sio, session).emit('team_set', team_data, None)
self.page.add_to_button()
class TeamPage(MDScreen):
def __init__(self, previous_page, username, **kwargs):
super(TeamPage, self).__init__(**kwargs)
self.previous_page = previous_page
self.username = username
self.load_content()
def load_content(self):
server = request(sio, session)
leaders = []
members = []
leaders_info = server.emit('team_get_leaders')
if dict_key_verify(leaders_info, 'leaders'):
leaders = leaders_info['leaders']
members_info = server.emit('team_get_members')
if dict_key_verify(members_info, 'members'):
members = members_info['members']
team = server.emit('team_get')
self.members.clear_widgets()
self.leaders.clear_widgets()
self.edit_area.clear_widgets()
if leaders:
for leader in leaders:
item = LeaderItem(leader['username'], self)
self.leaders.add_widget(item)
else:
item = OneLineAvatarIconListItem(text="No members")
self.leaders.add_widget(item)
self.level = server.emit('auth_get')['level']
if self.level != "member" or self.username in leaders:
if members:
self.edit_area.add_widget(ChangeNameButton(self))
self.edit_area.add_widget(AddLeaderButton(self))
if members:
self.team_name.text = team['name']
for member in members:
item = OneLineAvatarIconListItem(text=member['username'])
self.members.add_widget(item)
if not self.members:
item = OneLineAvatarIconListItem(text="No members")
self.members.add_widget(item)
else:
item = OneLineAvatarIconListItem(text="No members")
self.members.add_widget(item)
if self.team_name.text == "":
self.team_name.text = "No team"
if not setting_info("Help boxes").value:
for i, option in enumerate(self.toolbar.right_action_items):
if option[0].lower() == "help":
self.toolbar.right_action_items.pop(i)
self.previous_page.load_toolbar()
def button_to_add(self, input_mode="leader"):
self.edit_area.clear_widgets()
if input_mode == "leader":
add_widget = AddLeader(self)
elif input_mode == "name":
add_widget = ChangeName(self)
self.edit_area.add_widget(add_widget)
def add_to_button(self):
self.load_content()
def open_help(self, app):
open_help(app, self, "Team")
def back(self, app, direction="right"):
app.set_screen("HomePageScreen", direction)
app.sm.remove_widget(self)
# TEAM END
# Auth START
class Auth():
def load_content(self, obj, obj_id):
for field in obj.fields:
if "password" in field.lower():
auth_field = PasswordField(info_type=field)
else:
auth_field = AuthField(info_type=field)
obj_id.add_widget(auth_field)
obj.auth_field_objs.append(auth_field)
class PasswordField(MDRelativeLayout):
def __init__(self, info_type=None, **kwargs):
super().__init__(**kwargs)
self.info_type = info_type.lower()
self.load_content()
def load_content(self):
self.ids.password_field.hint_text = self.info_type.capitalize()
class AuthField(MDTextField):
def __init__(self, info_type=None, **kwargs):
super().__init__(**kwargs)
self.info_type = info_type.lower()
self.load_content()
def load_content(self):
self.hint_text = self.info_type.capitalize()
def change_hint(self, text):
self.hint_text = text
class AuthButton(MDRaisedButton):
def __init__(self, function=None, text=None, **kwargs):
super().__init__(**kwargs)
self.function = function
self.text = text
def action(self, app):
self.function(app)
def change_text(self, text):
self.text = text
class LoginPage(MDScreen):
def __init__(self, app, **kwargs):
super(LoginPage, self).__init__(**kwargs)
self.app = app
self.fields = ["Username", "Password"]
self.auth_field_objs = []
self.register_page = None
self.logged_in = False
self.load_content()
self.login_token()
def load_content(self):
Auth().load_content(self, self.login_view)
self.login_view.add_widget(AuthButton(self.login, 'Login'))
self.login_view.add_widget(AuthButton(self.register, 'Register'))
def login_token(self):
results = db().execute("SELECT * FROM tokens")
data = {'logged_in': False}
if results:
for result in results:
token = result[0]
expire = float(result[2])
if timestamp().now > float(expire):
db().execute("DELETE FROM tokens WHERE token = ?", (token,))
else:
info = {'token': token}
data = request(sio, session).emit("login", info)
if data['logged_in']:
username = request(sio, session).emit("auth_get", {'items': ['username']})['username']
self.login_confirmation(self.app, data, username)
def login(self, app):
username = self.auth_field_objs[0].text
password = self.auth_field_objs[1].text
if not username and not password:
username = "user"
password = "pass"
info = {'username': username, 'password': password}
data = request(sio, session).emit('login', info)
self.login_confirmation(app, data, username)
def login_confirmation(self, app, data, username):
message = f"{session.status['level']}: {session.status['message']}"
if data['logged_in'] == True:
app.switch_to_homepage("down", username)
session.username = username
session.level = request(sio, session).emit('auth_get')['level']
self.logged_in = True
else:
for field in self.auth_field_objs:
field.error = True
self.logged_in = False
Snackbar(text=message).open()
def register(self, app):
register_page = RegisterPage(name='RegisterPageScreen')
app.sm.add_widget(register_page)
app.set_screen('RegisterPageScreen', 'left')
class RegisterPage(MDScreen):
def __init__(self, **kwargs):
super(RegisterPage, self).__init__(**kwargs)
self.fields = ["Username", "Password", "Re-enter Password", "Registration Code"]
self.auth_field_objs = []
self.load_content()
self.mode = "member"
def load_content(self):
Auth().load_content(self, self.register_view)
self.register_view.add_widget(AuthButton(self.register, 'Register'))
self.mode_button = AuthButton(self.mode, 'Admin Register')
self.register_view.add_widget(self.mode_button)
def register(self, app):
info_points = ['username', 'password', 'repassword', 'key']
info = {point: self.auth_field_objs[i].text for i, point in enumerate(info_points)}
if self.mode == "member":
event = "register"
else:
event = "admin_register"
data = request(sio, session).emit(event, info)
self.register_confirmation(data, app)
def register_confirmation(self, data, app):
message = f"{session.status['level']}: {session.status['message']}"
if data['is_registered'] == True:
app.set_screen("LoginPageScreen", "right")
app.sm.remove_widget(self)
else:
Snackbar(text=message).open()
for field in self.auth_field_objs:
field.error = True
Snackbar(text=message).open()
def mode(self, app):
for field in self.auth_field_objs:
if "code" in field.info_type:
break
if self.mode == "member":
self.mode_button.change_text("Member Register")
field.hint_text = "Admin Registration Code"
self.mode = "admin"
else:
self.mode_button.change_text("Admin Register")
field.hint_text = "Registration Code"
self.mode = "member"
class ServerPage(MDScreen):
def __init__(self, **kwargs):
super(ServerPage, self).__init__(**kwargs)
def get_server_code(self):
response = request(sio, session).emit("server_code_get")
if dict_key_verify(response, 'server_code'):
session.server_code = response['server_code']
else:
message = "WARNING: Badly behaving server, please contact administrator"
Snackbar(text=message).open()
def connect(self, app):
connected = start_client(sio, self.url.text)
if not connected:
self.url.error = True
message = "Unsuccessful connection"
else:
self.get_server_code()
app.switch_to_decrypt()
message = "Successful connection"
Snackbar(text=message).open()
class ShareInput(MDBoxLayout):
pass
class DecryptPage(MDScreen):
def __init__(self, app, **kwargs):
super(DecryptPage, self).__init__(**kwargs)
self.share_inputs = []
self.min_shares = None
self.app = app
self.load_content()
def load_content(self):
mode_info = request(sio, session).emit("get_mode")
self.sss_enabled = mode_info['sss']
if self.sss_enabled:
self.min_shares = int(mode_info['min_shares'])
for i in range(self.min_shares):
share_input = ShareInput()
self.share_inputs.append(share_input)
self.input_area.add_widget(share_input)
def submit(self):
encrypt_data = {'shares': None, 'password': None}
data = {'success': False}
if self.en_password.text:
encrypt_data['password'] = self.en_password.text
data = request(sio, session).emit("decrypt", encrypt_data)
elif self.sss_enabled:
encrypt_data['shares'] = []
for share in self.share_inputs:
try:
share_num = int(share.share_num.text)
share_secret = int(share.share_secret.text)
except:
share.share_num.error = True
share.share_secret.error = True
continue
encrypt_data['shares'].append({'num': share_num, 'secret': share_secret})
if len(encrypt_data['shares']) >= self.min_shares:
data = request(sio, session).emit("decrypt", encrypt_data)
if data['success']:
self.app.sm.remove_widget(self)
self.app.switch_to_login()
else:
self.en_password.error = True
if encrypt_data['shares']:
for share in self.share_inputs:
share.share_num.error = True
share.share_secret.error = True
# Auth END
class FirstTimePage(MDScreen):
def __init__(self, **kwargs):
super(FirstTimePage, self).__init__(**kwargs)
self.load_content()
def load_content(self):
data = {'items': ['level']}
level = request(sio, session).emit("auth_get", data)['level']
if level == "member":
occupation_change = UserOccupationChange(self)
occupation_change.ids.new_request_area.remove_widget(occupation_change.ids.new_request_title)
elif level == "management" or level == "admin":
occupation_change = ManagementOccupationChange(self)
self.ids.step3.add_widget(occupation_change)
ntfy_topic = request(sio, session).emit("get_ntfy_topic")['topic']
self.ids.topic_name.text = ntfy_topic
def set_role(self):
if self.role_input.text:
request(sio, session).emit("profile_set", {'role': self.role_input.text}, None)
def set_name(self):
if self.name_input.text:
request(sio, session).emit("profile_set", {'name': self.name_input.text}, None)
def textbox_to_picture(self):
pass
def done(self, app):
self.set_name()
self.set_role()
app.set_screen("HomePageScreen", "down")
app.sm.remove_widget(self)
class BeOpen(MDApp):
def set_screen(self, screen, trans):
self.sm.current = screen
self.sm.transition.direction = trans
def build(self):
Builder.load_file('./modules/ui/beopen.kv')
self.theme_cls.material_style = "M3"
self.theme_cls.theme_style = "Light"
self.theme_cls.primary_palette = "Orange"
self.homepage_screen = None
self.login_screen = None
self.sm = MDScreenManager()
self.sm.add_widget(ServerPage(name='ServerPageScreen'))
Window.size = (800, 1000)
return self.sm
def disconnected(self):
self.sm.clear_widgets()
stop_client(sio)
self.sm.add_widget(ServerPage(name='ServerPageScreen'))
def switch_to_comments(self, transition='up'):
self.comments_screen = CommentsPage(name='CommentsPageScreen')
self.sm.add_widget(self.comments_screen)
self.set_screen('CommentsPageScreen', transition)
def switch_to_homepage(self, transition=None, username=None):
if self.homepage_screen:
self.sm.remove_widget(self.homepage_screen)
self.homepage_screen = HomePage(username, self, name='HomePageScreen')
self.sm.add_widget(self.homepage_screen)
if self.first_time_login():
first_time_page_screen_name = "FirstTimePage"
first_time_page_screen = FirstTimePage(name=first_time_page_screen_name)
self.sm.add_widget(first_time_page_screen)
self.set_screen(first_time_page_screen_name, "down")
else:
self.sm.switch_to(self.homepage_screen)
def switch_to_decrypt(self):
crypt_data = request(sio, session).emit("get_mode")
if crypt_data['mode'] == "decrypt":
decrypt_screen_name = 'DecryptPageScreen'
decrypt_screen = DecryptPage(self, name=decrypt_screen_name)
self.sm.add_widget(decrypt_screen)
self.set_screen(decrypt_screen_name, "down")
else:
self.switch_to_login()
def switch_to_login(self, transition="up"):
login_screen_name = "LoginPageScreen"
if self.login_screen:
self.sm.remove_widget(self.login_screen)
self.login_screen = LoginPage(self, name=login_screen_name)
if not self.login_screen.logged_in:
self.sm.add_widget(self.login_screen)
self.set_screen(login_screen_name, transition)
def comments_to_homepage(self, transition='down'):
self.set_screen('HomePageScreen', transition)
self.sm.remove_widget(self.comments_screen)
def first_time_login(self):
occupation = request(sio, session).emit("occupation_get")
profile = request(sio, session).emit("profile_get", {'items': ['role', 'name']})
friends = request(sio, session).emit("friend_get")['friends']
if not occupation['occupation_id'] and not friends and not profile['role'] and not profile['name']:
return True
else:
return False
first_time_page_screen_name = "FirstTimePage"
first_time_page_screen = FirstTimePage(name=first_time_page_screen_name)
self.sm.add_widget(first_time_page_screen)
self.set_screen(first_time_page_screen_name, "down")
#================== kivy END ==================
def create_settings():
settings = [{'title': "Help boxes",
'description': "Turn of the help buttons that appear as clickable question marks",
'default_value': True,
'icon': "help"}]
settings_db = db()
saved_settings = settings_db.execute("SELECT title FROM settings")
for setting in settings:
if saved_settings:
if (setting['title'],) in saved_settings:
continue
if isinstance(setting['default_value'], bool):
settings_db.execute("INSERT INTO settings (title, description, state, icon) VALUES (?, ?, ?, ?)", (setting['title'], setting['description'], setting['default_value'], setting['icon']))
else:
settings_db.execute("INSERT INTO settings (title, description, value, icon) VALUES (?, ?, ?, ?)", (setting['title'], setting['description'], setting['default_value'], setting['icon']))
def create_directories():
paths = ["data", "data/images"]
for path in paths:
if not os.path.exists(path):
os.mkdir(path)
def clean_directories():
paths = ["data/images"]
for path in paths:
for file in os.listdir(path):
os.remove(os.path.join(path, file))
def setup():
create_directories()
clean_directories()
create_settings()
def post_login():
db().execute("DELETE FROM tokens WHERE username != ?", (session.username,))
def main():
setup()
BeOpen().run()
stop_client(sio)
if __name__ == "__main__":
main()