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()