Full completed project

This commit is contained in:
2025-02-10 12:37:33 +00:00
commit b9abff8012
229 changed files with 16866 additions and 0 deletions

6
android-client/bugs.txt Normal file
View File

@@ -0,0 +1,6 @@
--- Load toolbar ---
I fixed a teams help icon issue but made a major change unaware of consequences???
I made it so the organisation bottom item now passes the "self.page" to the teams page and occupation page on creation instead of just "self"
This is so these pages could have access to the load_toolbar method required to refresh the help button on previous pages
--- Load toolbar ---

View File

@@ -0,0 +1,144 @@
[Home:START]
(title:START)
Home page
(title:END)
(body:START)
This is your home page, below you will is where you will see your friends posts.
In the top left corner is your "profile" there you will be able to see all about you, and find friends
Next to that is yout notifications to keep you up-to-date with your colleges
Your settings panel is in the top left and additional areas are available in the navigation panel at the bottom of the page
(body:END)
[Home:END]
[Memories:START]
(title:START)
Memories page
(title:END)
(body:START)
Here is where you will see your own historical posts. This means posts from previous days.
Just select a month and then the day of the month and you will see your old post. You can still like
and comment on it but others will not be able to see these interactions.
(body:END)
[Memories:END]
[Organisation:START]
(title:START)
Organisation page
(title:END)
(body:START)
Here you will see the navigation to your teams panel, and soon some infomation about your organisations
Your teams panel is where you will be able to see all about your team.
You can only be part of one organisation, since your account is specifically tied to it.
(body:END)
[Organisation:END]
[Organisation-admin:START]
(title:START)
Organisation page
(title:END)
(body:START)
Here you will see the navigation to your teams panel, and soon some infomation about your organisations
Your teams panel is where you will be able to see all about your team.
Additionally since your are management/admin staff you can see the occupation area here you can accept and reject occupation change requests, create new occupations and edit or delete current ones.
(body:END)
[Organisation-admin:END]
[Profile:START]
(title:START)
Profile page
(title:END)
(body:START)
This page you can see all the infomation about the profile your viewing. For your own profile you should see edit buttons next to some of infomation this means you can change or request to change this info.
Your role is simply how you describe your role in your team for instance "assistant"
Your occupation determines what team you are put into, you can only be part of 1 team at a time.
(body:END)
[Profile:END]
[Notifications:START]
(title:START)
Notifications page
(title:END)
(body:START)
Here you will see notifications from your organisations admins and management, as well notifications about people interacting with your posts and when its time to make your post.
(body:END)
[Notifications:END]
[Settings:START]
(title:START)
Settings page
(title:END)
(body:START)
This is where you can configure some options, for instance to stop seeing these help buttons toggle "Help Dialogs".
(body:END)
[Settings:END]
[Team:START]
(title:START)
Teams page
(title:END)
(body:START)
Your sorted into a team via your occupation, each occupation will have a team associated with it.
People in the same team as you will see your posts and you will see theres. This means you will see posts from
your team alongside posts from your friends.
Team leaders act as the moderator for the team. This means they can delete your posts and comments even if your
commenting on your friends posts.
(body:END)
[Team:END]
[Occupation:START]
(title:START)
Occupations page
(title:END)
(body:START)
Here you can change edit and delete the occupations in your organisation, this panel is only available for management and admins.
You can also approve and deny occupation change requests here. For a member to change their occupation they have to submit an occupation change request including what occupation they want to switch to. This request must be approved by management or above. Once approved the member is switched to their new team.
(body:END)
[Occupation:END]
[Friends:START]
(title:START)
Friends page
(title:END)
(body:START)
In BeOpen you dont follow people but friend people, this means both people accepted to be friends with eachother. Meaning you both see eachothers posts in your feed.
On this page you will be able to see your current friends and remove them if wanted. On the requests page (button below) you can send new friend requests, and approve or deny current friend requests. On that page is also a list of recomended friends based on mutal friends.
To send a friend request to someone (who isnt in the recomended) type their username into the request box, their username has to match exactly.
(body:END)
[Friends:END]
[Camera:START]
(title:START)
Making a post
(title:END)
(body:START)
You will be able to make one of these posts once a day, you will see the countdown at the top this is how long you have to post. After this time has run out you will not be able to post for that day.
To make a post just take a picture of whatever your doing right now and head onto the next screen.
(body:END)
[Camera:END]
[PostReview:START]
(title:START)
Making a post
(title:END)
(body:START)
Here you can review the image you just took and retake it if needed.
You can also add a caption to your post, note that you cannot edit a post after its been created you can however delete it. So be sure this is what you want to post today since deleting means you will have to wait till tomorrow to post again.
When your ready just hit post!
(body:END)
[PostReview:END]

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

2387
android-client/main.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,42 @@
from PIL import Image
import io
from android.storage import app_storage_path
root_path = app_storage_path()
class profile():
def __init__(self):
pass
def username():
pass
def name(self, first_name=None, last_name=None):
if first_name:
self.first_name
if last_name:
self.last_name
if first_name and last_name:
pass
class image():
def __init__(self, post_id):
self.post_id = post_id
self.path = None
def load(self, image_bytes):
image_formats = ['png', 'jpg']
for form in image_formats:
try:
self.path = root_path + f"data/images/{self.post_id}.{form}"
with Image.open(io.BytesIO(image_bytes)) as recieved:
recieved.save(self.path)
print("saved image")
break
except:
print("cant save image")
self.path = None
def delete(self):
os.remove(self.path)

View File

@@ -0,0 +1,108 @@
# MODULES
from modules.session.session import wait
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
# MODULES
class request():
def __init__(self, sio, session=None, username=None):
self.sio = sio
self.session = session
self.username = username
def callback(self, callback, data):
self.session.transfer = data
def emit(self, event, info=None, callback_func="self.callback"):
if callback_func == "self.callback":
callback_func = self.callback
if callback_func == None:
self.sio.emit(event, info)
return
else:
self.sio.emit(event, info, callback=callback_func)
wait(self.session).wait()
return self.session.transfer
class account_page(request):
def refresh(self):
info = self.get_profile()
return info
def get_profile(self):
info = {'username': self.username, 'name': self.username, 'role': "", 'occupation_name': "", 'team_name': "", 'biography': ""}
profile_data = {'username': self.username, 'items': ['name', 'role', 'biography']}
profile_info = self.emit('profile_get', profile_data)
occupation_data = {'username': self.username, 'items': ['name']}
occupation_info = self.emit('occupation_get', occupation_data)
if dict_key_verify(occupation_info, 'name'):
info['occupation_name'] = occupation_info['name']
team_data = {'username': self.username, 'items': ['name']}
team_info = self.emit('team_get', team_data)
if dict_key_verify(team_info, 'name'):
info['team_name'] = team_info['name']
team_leader_info = self.emit('team_get_leaders')
if dict_key_verify(team_leader_info, 'leaders'):
if self.username in team_leader_info['leaders']:
info['team_name'] += " (team lead)"
for key in profile_info.keys():
if dict_key_verify(profile_info, key):
info[key] = profile_info[key]
return info
def set_profile(self, item, new_value, username=None):
profile = ['name', 'role', 'biography']
occupation = ['occupation_name']
team = ['team_name']
if item in profile:
event = 'profile_set'
if item == 'name':
new_values = new_value.split(" ")
if len(new_values) == 2:
items = ['first_name', 'last_name']
if item in occupation:
event = 'occupation_set'
item = 'name'
if item in team:
event = 'team_set'
item = 'name'
if type(item) != list:
items = [item]
if type(new_value) != list:
new_values = [new_value]
for value, item in zip(new_values, items):
data = {'username': None,'items': [item], item: value}
if username:
data['username'] = username
self.emit('profile_set', data, None)

View File

@@ -0,0 +1,143 @@
import time
import sqlite3
from android.storage import app_storage_path
root_path = app_storage_path()
class session_info():
def __init__(self):
self._logged_in = False
self.username = None
self.server_code = None
self.cycle_count = 0
self.auth_tokens = []
self.transfer = None
self.status = None
@property
def logged_in(self):
return self._logged_in
@logged_in.setter
def logged_in(self, value):
self._logged_in = value
self.cycle_count += 1
@property
def transfer(self):
return self._transfer
@transfer.setter
def transfer(self, value):
self._transfer = value
self.cycle_count += 1
def clear(self):
db().execute("DELETE FROM tokens WHERE username = ?", (self.username,))
self.__init__()
class wait():
def __init__(self, session):
self.session = session
self.update()
def update(self):
self.last = self.session.cycle_count
self.current = self.session.cycle_count
def current_update(self):
self.current = self.session.cycle_count
def wait(self, status=None):
while self.last == self.current:
time.sleep(0.05)
self.current_update()
return
def wait_username(self):
while not self.session.username:
time.sleep(0.05)
return
class db():
def __init__(self):
self.path = root_path + "/data/database.db"
self._create()
def _create(self):
con, cur = self._connect()
cur.execute("""CREATE TABLE IF NOT EXISTS tokens (
token TEXT NOT NULL PRIMARY KEY,
username TEXT NOT NULL,
expire TEXT NOT NULL
)""")
cur.execute("""CREATE TABLE IF NOT EXISTS settings (
title TEXT NOT NULL PRIMARY KEY,
description TEXT,
state BOOL,
value TEXT,
icon TEXT
)""")
self._close(con)
def _connect(self):
con = sqlite3.connect(self.path)
cur = con.cursor()
return con, cur
def execute(self, command, values=None):
# we use this method so that closing and connecting to the datbase is abstracted away
rez = None
con, cur = self._connect()
if values:
cur.execute(command, values)
else:
cur.execute(command)
if "SELECT" in command:
rez = cur.fetchall()
self._close(con)
if rez:
return rez
def _commit(self, con):
con.commit()
def _close(self, con):
con.commit()
con.close()
class setting():
def __init__(self, title):
self.title = title
self.db = db()
self.__fetch()
def __fetch(self):
setting_data = self.db.execute("SELECT * FROM settings WHERE title = ?", (self.title,))
if setting_data:
self.title = setting_data[0][0]
self.description = setting_data[0][1]
if not self.description:
self.description = ""
if setting_data[0][3] != None:
self.value = setting_data[0][3]
self.type = "text_field"
else:
self.value = setting_data[0][2]
self.type = "swtich"
if setting_data[0][4] != None:
self.icon = setting_data[0][4]
else:
self.icon = "cog"
def change_value(self, new_value):
if self.type == "swtich" and isinstance(new_value, bool):
self.db.execute("UPDATE settings SET state = ?", (new_value,))
elif self.type == "text_field" and isinstance(new_value, str):
self.db.execute("UPDATE settings SET value = ?", (new_value,))

View File

@@ -0,0 +1,63 @@
from datetime import date, timedelta, datetime
class timestamp():
@property
def start(self):
value = self.get_date_timestamp()
self._start = value
return self._start
@start.setter
def start(self, value):
value = self.get_date_timestamp()
self._start = value
@property
def end(self):
value = self.get_date_timestamp(day_mod=1) - 1
self._end = value
return self._end
@end.setter
def end(self, value):
value = self.get_date_timestamp(day_mod=1) - 1
self._end = value
@property
def now(self):
value = self.get_timestamp()
self._now = value
return value
@now.setter
def now(self, value):
value = self.get_timestamp()
self._now = value
@property
def date(self):
date = str(datetime.now().date())
self._date = date
return self._date
@date.setter
def date(self, value):
self._date = value
def get_date_timestamp(self, year_mod=0, month_mod=0, day_mod=0, *args, **kwargs):
modifier = [year_mod, month_mod, day_mod]
now_mod = (datetime.now()+timedelta(days=day_mod))
date = (str(now_mod.date()).replace("-0", "-")).split("-")
date = [int(string) for string in date]
timestamp = datetime(date[0], date[1], date[2]).timestamp()
return timestamp
def get_timestamp(self):
now = (float(datetime.now().timestamp()))
return now
def get_date(self, timestamp):
date = datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d')
return date
def get_days_month(self, month, year):
pass

3
android-client/modules/ui/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/ui.iml" filepath="$PROJECT_DIR$/.idea/ui.iml" />
</modules>
</component>
</project>

9
android-client/modules/ui/.idea/ui.iml generated Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
cython
python-socketio==5.8.0
eventlet==0.33.3
pathlib==1.0.1
datetime
pillow==9.5.0
setuptools
python-dotenv==1.0.0
pyinstaller==6.3.0
wheel==0.41.2
packaging==23.2
kivy[full]==2.3
kivymd==1.1.1