You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Comrad/comrad/app/screens/profile/profile.py

329 lines
11 KiB
Python

import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__),'..')),'..')))
from comrad import *
from screens.base import BaseScreen
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.chip import MDChip
from kivymd.uix.textfield import MDTextField
from kivymd.uix.button import MDRectangleFlatButton,MDRectangleFlatIconButton,MDIconButton
from kivymd.uix.label import MDLabel, MDIcon
from kivy.uix.image import AsyncImage, Image
from kivy.metrics import dp
from kivy.properties import StringProperty
from kivy.core.window import Window
from kivy.core.image import Image as CoreImage
import io,asyncio
from kivy.uix.carousel import Carousel
from screens.feed.feed import PostCard
from kivy.clock import Clock
from functools import partial
from copy import copy,deepcopy
from kivy.animation import Animation
from main import MyLabel,COLOR_ICON
from misc import *
class ProfileAvatar(Image):
def on_touch_down(self, touch):
if self.screen.carousel.index and self.collide_point(*touch.pos) and self.screen.carousel.slides:
start = self.screen.carousel.slides[0]
start.opacity=0
self.screen.carousel.index=0
anim = Animation(opacity=1, duration=0.1)
anim.start(start)
# start = self.screen.carousel.slides[0]
# log('????',start)
# self.screen.carousel.load_slide(start)
# self.screen.carousel.load_next()
class LayoutAvatar(MDBoxLayout): pass
class AuthorInfoLayout(MDBoxLayout): pass
class LayoutCover(MDBoxLayout):
source=StringProperty()
pass
class CoverImage(Image): pass
def binarize_image(image, threshold=200):
"""Binarize an image."""
image = image.convert('L') # convert image to monochrome
import numpy
image = numpy.array(image)
image = binarize_array(image, threshold)
imsave(target_path, image)
return image
def binarize_array(numpy_array, threshold=200):
"""Binarize a numpy array."""
import numpy
for i in range(len(numpy_array)):
for j in range(len(numpy_array[0])):
if numpy_array[i][j] > threshold:
numpy_array[i][j] = 255
else:
numpy_array[i][j] = 0
return numpy_array
def crop_square(pil_img, crop_width, crop_height):
img_width, img_height = pil_img.size
return pil_img.crop(((img_width - crop_width) // 2,
(img_height - crop_height) // 2,
(img_width + crop_width) // 2,
(img_height + crop_height) // 2))
def circularize_img(img_fn, width, im=None, do_crop=True,bw=False,resize=True,circularize=True):
from PIL import Image, ImageOps, ImageDraw
from kivy.app import App
import numpy as np
log=App.get_running_app().log
#if not im:
im = Image.open(img_fn)
log('??',im)
# get center
if do_crop: im = crop_square(im, width, width)
if resize: im = im.resize((width,width))
if bw:
thresh = 175
fn = lambda x : 255 if x > thresh else 0
im = im.convert('L').point(fn, mode='1').convert('RGB')
orig_color = (255,255,255)
replacement_color = COLOR_ICON #(255,0,0)
# img = im.convert('RGB')
data = np.array(im)
data[(data == orig_color).all(axis = -1)] = replacement_color
im = Image.fromarray(data, mode='RGB').convert('RGBA')
if circularize_img:
bigsize = (im.size[0] * 3, im.size[1] * 3)
mask = Image.new('L', bigsize, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0) + bigsize, fill=255)
mask = mask.resize(im.size, Image.ANTIALIAS)
im.putalpha(mask)
# give back bytes
log('!!',im)
output = ImageOps.fit(im, mask.size, centering=(0.5, 0.5))
imgByteArr = io.BytesIO()
output.save(imgByteArr, format='PNG')
# imgByteArr = imgByteArr.getvalue()
imgByteArr.seek(0)
return imgByteArr
# output.putalpha(mask)
# output.save('output.png')
# background = Image.open('back.jpg')
# background.paste(im, (150, 10), im)
# background.save('overlap.png')
# return output
class ProfilePageLayout(MDBoxLayout): pass
class FollowerLayout(MDBoxLayout): pass
class AuthorName(MyLabel): pass
class AuthorUsername(MyLabel): pass
class AuthorDesc(MyLabel): pass
class AuthorPronouns(MyChip): pass
class AuthorPlace(MyChip): pass
class AuthorWebsite(MyChip): pass
class AuthorFollowers(MyChip): pass
class AuthorFollowing(MyChip): pass
def update_screen_on_carousel_move(self,dt,width=75):
# screen.author_name.text=str(screen.carousel.index)
# avatar_layout = copy(screen.avatar_layout)
# avatar_layout.width=dp(100)
# avatar_layout.height=dp(100)
if self.carousel.index:
if not hasattr(self,'avatar_layout_small'):
self.avatar_img.seek(0)
img,byte,avatar,avatar_layout = self.make_profile_img(width,do_crop=False,bw=True,circularize=False)
avatar.screen = self
avatar_layout.pos_hint = {'right':0.995, 'top':0.995}
avatar_layout.opacity=0
# avatar_layout.animate()
self.add_widget(avatar_layout)
self.avatar_layout_small=avatar_layout
self.avatar_layout_small_visible=False
if not self.avatar_layout_small_visible:
self.avatar_layout_small_visible=True
anim = Animation(opacity=1, duration=0.25)
anim.start(self.avatar_layout_small)
else:
if hasattr(self,'avatar_layout_small'):
if self.avatar_layout_small_visible:
self.avatar_layout_small_visible=False
anim = Animation(opacity=0, duration=0.25)
anim.start(self.avatar_layout_small)
# self.remove_widget(self.avatar_layout_small)
# del self.avatar_layout_small
# avatar_layout = self.avatar_layout
# self.remove_widget(avatar_layout)
# self.add_widget(avatar_layout)
from screens.base import ProtectedScreen
class ProfileScreen(ProtectedScreen):
username = None
clock_scheduled=None
def make_profile_img(self,width,do_crop=True,circ_img=None,bw=False,circularize=True):
img_src = os.path.join(PATH_GUI_ASSETS, 'avatars', f'{self.app.username}.png')
if not os.path.exists(img_src):
img_src=PATH_DEFAULT_AVATAR
circ_img = circularize_img(img_src,width,do_crop=do_crop,bw=bw,circularize=circularize)
avatar_layout = LayoutAvatar()
byte=io.BytesIO(circ_img.read())
img = CoreImage(byte,ext='png')
avatar = ProfileAvatar()
avatar.texture = img.texture
avatar_layout.height=dp(width)
avatar_layout.width=dp(width)
avatar_layout.add_widget(avatar)
return (circ_img,byte,avatar,avatar_layout)
def on_pre_enter(self, width=300):
if not super().on_pre_enter(): return
if not self.clock_scheduled:
Clock.schedule_interval(partial(update_screen_on_carousel_move, self), 0.1)
self.clock_scheduled=True
# clear
if hasattr(self,'carousel'):
for post in self.posts:
self.carousel.remove_widget(post)
self.remove_widget(self.carousel)
del self.carousel
self.posts=[]
self.carousel = Carousel()
self.carousel.direction='right'
self.carousel.loop=True
self.posts=[]
# get circular image
self.avatar_img, self.avatar_img_bytes, self.avatar, self.avatar_layout = \
self.make_profile_img(width)
self.avatar.screen = self
## author info
self.author_info_layout = AuthorInfoLayout()
#self.app.name_irl = 'Marx Zuckerberg'
self.app.name_irl = 'Comrad @'+self.app.username
if hasattr(self.app,'name_irl'):
self.author_name_irl = AuthorName(text=self.app.name_irl)
self.author_name_irl.font_name = 'assets/font.otf'
self.author_name_irl.font_size = '28sp'
self.author_info_layout.add_widget(self.author_name_irl)
self.author_name = AuthorUsername(text='@'+self.app.username)
self.author_name.font_name = 'assets/font.otf'
self.author_name.font_size = '20sp'
# self.author_info_layout.add_widget(self.author_name)
## AUTHOR DESCRIPTION
self.author_desc = AuthorDesc(text='... etc ...')
self.author_desc.font_name='assets/font.otf'
self.author_desc.font_size='18sp'
# self.author_desc.halign='left'
## Pronouns
self.author_pronouns = AuthorPronouns(label='he/him',icon='gender-transgender')
## AUTHOR PLACE
self.author_place = AuthorPlace(label='Earth',icon='map-marker-outline')
## Website
self.author_website = AuthorWebsite(label='website.org', icon='link-variant')
## Followers
self.follower_layout = FollowerLayout()
# self.author_followers = AuthorFollowers(label='13 followers',icon='account-arrow-left')
self.author_following = AuthorFollowing(label='13 comrades',icon='account-multiple')
## add to layout
self.author_info_layout.add_widget(self.author_desc)
self.author_info_layout.add_widget(self.author_pronouns)
self.author_info_layout.add_widget(self.author_place)
# self.author_info_layout.add_widget(self.author_website)
self.follower_layout.add_widget(self.author_following)
# self.follower_layout.add_widget(self.author_followers)
self.author_info_layout.add_widget(self.follower_layout)
# class AuthorPlace(MDLabel): pass
# class AuthorWebsite(MDLabel): pass
# class AuthorFollowers(MDLabel): pass
# class AuthorFollowing(MDLabel): pass
## add root widgets
self.page_layout = ProfilePageLayout()
self.page_layout.add_widget(self.avatar_layout)
self.page_layout.add_widget(self.author_info_layout)
self.add_widget(self.carousel)
self.carousel.add_widget(self.page_layout)
## add posts
asyncio.create_task(self.add_author_posts())
async def add_author_posts(self):
# add posts
lim=25
posts=await self.app.get_my_posts()
self.log('POSTS!?',posts)
# stop
for i,post in enumerate(posts):
if i>lim: break
post_obj = PostCard(post)
self.log(post)
self.posts.append(post_obj)
self.carousel.add_widget(post_obj)
# def on_touch_move(self, ent):
# if self.carousel.index:
# self.author_name.text='moved!'
# else:
# self.author_name.text=self.username