profile page stuff more

p2p
quadrismegistus 4 years ago
parent 83f88ea11a
commit dd912a2516

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 MiB

@ -35,6 +35,7 @@ from kivy.storage.jsonstore import JsonStore
from kivy.core.window import Window
from kivy.core.text import LabelBase
import shutil
from kivy.uix.image import Image
Window.size = WINDOW_SIZE
@ -92,6 +93,19 @@ def get_tor_python_session():
with tor_requests.get_session() as s:
return s
def draw_background(widget, img_fn='assets/bg.png'):
from kivy.core.image import Image as CoreImage
from kivy.graphics import Color, Rectangle
widget.canvas.before.clear()
with widget.canvas.before:
Color(.4, .4, .4, 1)
texture = CoreImage(img_fn).texture
texture.wrap = 'repeat'
nx = float(widget.width) / texture.width
ny = float(widget.height) / texture.height
Rectangle(pos=widget.pos, size=widget.size, texture=texture,
tex_coords=(0, 0, nx, 0, nx, ny, 0, ny))
class MainApp(MDApp):
title = 'Komrade'
@ -102,6 +116,8 @@ class MainApp(MDApp):
store = JsonStore('komrade.json')
login_expiry = 60 * 60 * 24 * 7 # once a week
#login_expiry = 5 # 5 seconds
texture = ObjectProperty()
def get_session(self):
# return get_async_tor_proxy_session()
@ -115,6 +131,11 @@ class MainApp(MDApp):
return ''
def build(self):
# bind bg texture
# self.texture = Image(source='assets/bg.png').texture
# self.texture.wrap = 'clamp_to_edge'
# self.texture.uvsize = (-2, -2)
self.username=''
# bind
global app,root
@ -122,6 +143,7 @@ class MainApp(MDApp):
#self.username = self.store.get('userd').get('username')
self.load_store()
self.root = root = Builder.load_file('root.kv')
draw_background(self.root)
# edit logo
logo=root.ids.toolbar.ids.label_title
@ -179,7 +201,7 @@ class MainApp(MDApp):
self.logged_in=True
self.username=un
# self.store.put('username',un)
self.store.put('user',username=un,logged_in=True,logged_in_when=time.time())
# self.store.put('user',username=un,logged_in=True,logged_in_when=time.time())
self.root.change_screen('feed')
@ -291,6 +313,14 @@ class MainApp(MDApp):
return jsond['posts']
return []
def get_my_posts(self):
with self.get_session() as sess:
with sess.get(self.api+'/posts/'+self.username) as r:
log(r.text)
jsond=r.json()
return jsond['posts']
return []
def get_posts_async(self):
result=[]
with self.get_session() as sess:

@ -0,0 +1,186 @@
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import (
BooleanProperty,
ListProperty,
NumericProperty,
ObjectProperty,
StringProperty,
)
from kivy.uix.boxlayout import BoxLayout
from kivymd.theming import ThemableBehavior
from kivymd.uix.button import MDIconButton
from kivymd.uix.stacklayout import MDStackLayout
Builder.load_string(
"""
#:import DEVICE_TYPE kivymd.material_resources.DEVICE_TYPE
<MyChooseChip>
adaptive_height: True
spacing: "5dp"
<MyChip>
size_hint: None, None
height: "26dp"
padding: 0, 0, "5dp", 0
width:
self.minimum_width - (dp(10) if DEVICE_TYPE == "desktop" else dp(20)) \
if root.icon != 'checkbox-blank-circle' else self.minimum_width
theme_text_color: 'Custom'
text_color:1,0,0,1
# canvas:
# Color:
# rgba: root.color
# RoundedRectangle:
# pos: self.pos
# size: self.size
# radius: [root.radius]
MDBoxLayout:
id: box_check
adaptive_size: True
pos_hint: {'center_y': .5}
MDBoxLayout:
adaptive_width: True
padding: dp(0)
MDIconButton:
id: icon
icon: root.icon
size_hint_y: None
height: "20dp"
pos_hint: {"center_y": .5}
user_font_size: "20dp"
disabled: True
md_bg_color_disabled: 0, 0, 0, 0
theme_text_color: "Custom"
text_color: 1,0,0,1
Label:
id: label
text: root.label
size_hint_x: None
width: self.texture_size[0]
color: root.text_color if root.text_color else (root.theme_cls.text_color)
font_name: "assets/font.otf"
font_size: "18sp"
"""
)
class MyChip(BoxLayout, ThemableBehavior):
label = StringProperty()
"""Chip text.
:attr:`label` is an :class:`~kivy.properties.StringProperty`
and defaults to `''`.
"""
icon = StringProperty("checkbox-blank-circle")
"""Chip icon.
:attr:`icon` is an :class:`~kivy.properties.StringProperty`
and defaults to `'checkbox-blank-circle'`.
"""
color = ListProperty()
"""Chip color in ``rgba`` format.
:attr:`color` is an :class:`~kivy.properties.ListProperty`
and defaults to `[]`.
"""
text_color = ListProperty()
"""Chip's text color in ``rgba`` format.
:attr:`text_color` is an :class:`~kivy.properties.ListProperty`
and defaults to `[]`.
"""
check = BooleanProperty(False)
"""
If True, a checkmark is added to the left when touch to the chip.
:attr:`check` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `False`.
"""
callback = ObjectProperty()
"""Custom method.
:attr:`callback` is an :class:`~kivy.properties.ObjectProperty`
and defaults to `None`.
"""
radius = NumericProperty("12dp")
"""Corner radius values.
:attr:`radius` is an :class:`~kivy.properties.NumericProperty`
and defaults to `'12dp'`.
"""
selected_chip_color = ListProperty()
"""The color of the chip that is currently selected in ``rgba`` format.
:attr:`selected_chip_color` is an :class:`~kivy.properties.ListProperty`
and defaults to `[]`.
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
if not self.color:
self.color = (1,0,0,1) #self.theme_cls.primary_color
def on_icon(self, instance, value):
if value == "":
self.icon = "checkbox-blank-circle"
self.remove_widget(self.ids.icon)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
md_choose_chip = self.parent
if self.selected_chip_color:
Animation(
color=self.theme_cls.primary_dark
if not self.selected_chip_color
else self.selected_chip_color,
d=0.3,
).start(self)
if issubclass(md_choose_chip.__class__, MDChooseChip):
for chip in md_choose_chip.children:
if chip is not self:
chip.color = self.theme_cls.primary_color
if self.check:
if not len(self.ids.box_check.children):
self.ids.box_check.add_widget(
MDIconButton(
icon="check",
size_hint_y=None,
height=dp(20),
disabled=True,
user_font_size=dp(20),
pos_hint={"center_y": 0.5},
)
)
else:
check = self.ids.box_check.children[0]
self.ids.box_check.remove_widget(check)
if self.callback:
self.callback(self, self.label)
class MDChooseChip(MDStackLayout):
def add_widget(self, widget, index=0, canvas=None):
if isinstance(widget, MyChip):
return super().add_widget(widget)

@ -38,10 +38,11 @@
<MyLabel>:
theme_text_color: 'Custom'
text_color: (1,0,0,1)
pos_hint: {'center_y': 0.5}
# pos_hint: {'center_y': 0.5}
halign: 'center'
height: self.texture_size[1]
font_family: 'Courier'
font_name: 'assets/font.otf'
size_hint:1,None
@ -56,15 +57,19 @@ MyLayout:
scr_mngr: scr_mngr
orientation: 'vertical'
height: self.minimum_height
md_bg_color:0,0,0,1
canvas:
Color:
rgba: 0.925,0.925,0.925,1 #get_color_from_hex(colors['Gray']['900'])
rgba: 0.925,0.925,0.925,0.99 #get_color_from_hex(colors['Gray']['900'])
# rgba: 0,0,0,0.9 #get_color_from_hex(colors['Gray']['900'])
Rectangle:
pos: self.pos
size: self.size
source: 'assets/komrade2.png'
source: 'assets/bg.png'
# texture: app.texture
MDToolbar:

@ -157,15 +157,12 @@
height: self.minimum_height
radius:[20,]
border_radius:20
# canvas:
# Color:
# rgb: 1,0,0,1
# Line:
# width: 1
# rectangle: (self.x, self.y, self.width, self.height)
# # radius:[20,]
# # border_radius:20
canvas:
Color:
rgba: 1,0,0,0.5
Line:
width: 1
rounded_rectangle: (self.x, self.y, self.width, self.height, 20, 20, 20, 20)

@ -59,32 +59,56 @@
<AuthorInfoLayout>:
cols:1
orientation:'vertical'
size_hint:None,None
size_hint:0.6666,None
md_bg_color:0,0,0,1
width: '300dp'
# width: '300dp'
height: self.minimum_height
pos_hint: {'center_x':0.5}
spacing:'10sp'
radius:[20,]
border_radius:20
padding:'10sp'
canvas:
Color:
rgba: 1,0,0,0.5
Line:
width: 1
rounded_rectangle: (self.x, self.y, self.width, self.height, 20, 20, 20, 20)
<AuthorName>:
pos_hint: {'center_x':0.5}
theme_text_color:'Custom'
text_color: 1,0,0,1
halign:'center'
<AuthorUsername>:
pos_hint: {'center_x':0.5}
theme_text_color:'Custom'
text_color: 1,0,0,1
halign:'center'
font_size:'28sp'
<AuthorDesc>:
halign:'left'
<AuthorPlace>:
theme_text_color: 'Custom'
text_color:1,0,0,1
<AuthorWebsite>:
theme_text_color: 'Custom'
text_color:1,0,0,1
<AuthorFollowers>:
theme_text_color: 'Custom'
text_color:1,0,0,1
size_hint:None,None
pos_hint:{'right':1}
<AuthorFollowing>:
theme_text_color: 'Custom'
text_color:1,0,0,1
pos_hint:{'left':1}
<ProfilePageLayout>:
cols:1
@ -96,4 +120,13 @@
<ProfileAvatar>:
size_hint:1,1
# width: '200dp'
# width: '200dp'
<FollowerLayout>:
cols:2
orientation:'horizontal'
spacing:'25dp'
height:self.minimum_height
size_hint:1,None
# md_bg_color:1,0,0,1
pos_hint: {'center_x':0.5,'center_y':0.5}

@ -1,9 +1,10 @@
from screens.base import BaseScreen
from main import log
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.chip import MDChip
from kivymd.uix.textfield import MDTextField
from kivymd.uix.button import MDRectangleFlatButton
from kivymd.uix.label import MDLabel
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
@ -12,12 +13,31 @@ from kivy.core.image import Image as CoreImage
import io
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
from misc import *
img_src = 'assets/avatar.jpg' #cache/img/1e6/587e880344d1e88cec8fda65b1148.jpeg'
# img_src = '/home/ryan/Pictures/Harrier.jpeg'
cover_img_src='assets/cover.jpg' #cache/img/60d/9de00e52e4758ade5969c50dc053f.jpg'
class ProfileAvatar(Image): pass
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
@ -36,14 +56,14 @@ def crop_square(pil_img, crop_width, crop_height):
(img_width + crop_width) // 2,
(img_height + crop_height) // 2))
def circularize_img(img_fn, width):
def circularize_img(img_fn, width, do_crop=True):
from PIL import Image, ImageOps, ImageDraw
im = Image.open(img_fn)
# get center
im = crop_square(im, width, width)
if do_crop: im = crop_square(im, width, width)
im = im.resize((width,width))
bigsize = (im.size[0] * 3, im.size[1] * 3)
mask = Image.new('L', bigsize, 0)
@ -67,15 +87,58 @@ def circularize_img(img_fn, width):
# 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,circ_img=self.avatar_img)
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)
class AuthorName(MDLabel): pass
class AuthorUsername(MDLabel): pass
class AuthorDesc(MDLabel): pass
class AuthorPlace(MDLabel): pass
class AuthorWebsite(MDLabel): pass
class AuthorFollowers(MDLabel): pass
class AuthorFollowing(MDLabel): pass
class ProfileScreen(BaseScreen):
@ -83,39 +146,109 @@ class ProfileScreen(BaseScreen):
# global app
# if app.is_logged_in():
# app.root.change_screen('feed')
username = None
clock_scheduled=None
def make_profile_img(self,width,do_crop=True,circ_img=None):
if not circ_img:
circ_img = circularize_img(img_src,width,do_crop=do_crop)
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=200):
# query author info
if not self.username: self.username=self.app.username
# @TODO
if not self.clock_scheduled:
Clock.schedule_interval(partial(update_screen_on_carousel_move, self), 0.1)
self.clock_scheduled=True
# clear
if not hasattr(self,'carousel'):
self.carousel = Carousel()
self.carousel.direction='right'
self.posts=[]
else:
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
circ_img = circularize_img(img_src,200)
self.avatar_layout = LayoutAvatar()
img = CoreImage(io.BytesIO(circ_img.read()),ext='png')
self.avatar = ProfileAvatar()
self.avatar.texture = img.texture
self.avatar_layout.height=dp(width)
self.avatar_layout.width=dp(width)
self.avatar_layout.add_widget(self.avatar)
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'
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 = AuthorUsername(text='@'+self.username)
self.author_name.font_name = 'assets/font.otf'
self.author_name.font_size = '28sp'
self.author_name.font_size = '20sp'
self.author_info_layout.add_widget(self.author_name)
## AUTHOR DESCRIPTION
self.author_desc = AuthorDesc(text='Blogging bad takes since 1999. Writing on abstraction as literary & capitalist form')
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='UK',icon='map-marker-outline')
## Website
self.author_website = AuthorWebsite(label='ryanheuser.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='777 following',icon='account-arrow-right')
## 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
@ -132,10 +265,16 @@ class ProfileScreen(BaseScreen):
def add_author_posts(self):
# add posts
lim=25
for i,post in enumerate(self.app.get_posts()):
for i,post in enumerate(self.app.get_my_posts()):
if i>lim: break
post_obj = PostCard(post)
log(post)
self.posts.append(post_obj)
self.carousel.add_widget(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

@ -37,6 +37,7 @@ class Handler(FileSystemEventHandler):
@staticmethod
def on_any_event(event):
if '/cache/' in str(event.src_path): return None
if '__pycache__' in str(event.src_path): return None
if event.is_directory:
return None

@ -187,7 +187,7 @@ def get_follows(name=None):
def get_posts(name=None):
if name:
person = Person.nodes.get_or_none(name=name)
data = [p.data for p in person.wrote.all] if person is not None else []
data = [p.data for p in person.wrote.all()] if person is not None else []
else:
data = [p.data for p in Post.nodes.order_by('-timestamp')]
# print(data)

Loading…
Cancel
Save