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/feed/feed.py

372 lines
13 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 kivymd.uix.label import MDLabel
from kivy.uix.gridlayout import GridLayout
from kivy.uix.image import AsyncImage, Image
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.card import MDCard, MDSeparator
from kivy.uix.scrollview import ScrollView
from screens.base import ProtectedScreen,BaseScreen
from kivy.properties import ListProperty
import os,time
from datetime import datetime
from kivy.app import App
from threading import Thread
import asyncio
from misc import *
from kivy.core.window import Window
import logging
logger=logging.getLogger(__name__)
### POST CODE
class PostTitle(MDLabel): pass
class PostGridLayout(GridLayout): pass
class PostImage(AsyncImage): pass
# class PostImage(CoreImage)
class PostImageBytes(Image): pass
class PostContent(MDLabel):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.bind(width=lambda s, w: s.setter('text_size')(s, (w, None)))
self.bind(texture_size=self.setter('size'))
self.font_name='assets/overpass-mono-regular.otf'
#pass
class PostAuthorLayout(MDBoxLayout):
pass
class PostImageLayout(MDBoxLayout): pass
class PostAuthorLabel(MDLabel):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.bind(width=lambda s, w: s.setter('text_size')(s, (w, None)))
self.bind(texture_size=self.setter('size'))
self.font_name='assets/overpass-mono-regular.otf'
#self.to_changeable=False
# def on_touch_down(self,*x,**y):
# print('weeeeeee')
# stop
#def on_touch_down(self, touch):
# '''Receive a touch down event.
# :Parameters:
# `touch`: :class:`~kivy.input.motionevent.MotionEvent` class
# Touch received. The touch is in parent coordinates. See
# :mod:`~kivy.uix.relativelayout` for a discussion on
# coordinate systems.
# :Returns: bool
# If True, the dispatching of the touch event will stop.
# If False, the event will continue to be dispatched to the rest
# of the widget tree.
# '''
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
# username=self.text.strip().split()[1][1:]
app=App.get_running_app()
app.view_profile(self.username)
return True
pass
class PostTimestampLabel(MDLabel):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.bind(width=lambda s, w: s.setter('text_size')(s, (w, None)))
self.bind(texture_size=self.setter('size'))
self.font_name='assets/overpass-mono-regular.otf'
class PostAuthorAvatar(AsyncImage):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
app=App.get_running_app()
app.view_profile(self.username)
return True
# stop
pass
class PostLayout(MDBoxLayout): pass
class PostScrollView(ScrollView): pass
class PostCard(MDCard):
@property
def app(self): return App.get_running_app()
def log(self,*x,**y): self.app.log(*x)
def __init__(self, data):
super().__init__()
# self.log('PostCard() got data: '+str(data))
self.author = data.get('author','[Anonymous]')
self.recipient = data.get('to_name','')
self.post_data = data.get('post_data', {})
self.screen=data.get('screen')
self.post_id=data.get('post_id')
if not self.recipient:
self.recipient=self.app.channel
# self.img_id = data.get('file_id','')
# self.img_ext = data.get('file_ext','')
# self.img_src=self.img_id[:3]+'/'+self.img_id[3:]+'.'+self.img_ext if self.img_id else ''
# self.cache_img_src = os.path.join('cache',self.img_src) if self.img_src else ''
self.cache_img_src = self.img_src = data.get('img_src','')
if not self.cache_img_src:
if self.post_data.get('prompt_id')=='addcontact':
other_data=self.post_data.get('other_data',{})
if other_data:
img_avtr_b=other_data.get('img_avatar')
if img_avtr_b:
tmp_fnfn = os.path.join(PATH_COMRAD_TMP,get_random_id()+'.png')
with open(tmp_fnfn,'wb') as of:
of.write(img_avtr_b)
self.cache_img_src=self.img_src=tmp_fnfn
self.img_loaded = self.img_src and os.path.exists(self.img_src)
self.content = data.get('content','')
self.timestamp = data.get('timestamp',None)
# self.bind(minimum_height=self.setter('height'))
author_prefix=data.get('author_prefix','Comrad @')
author_label_font_size=data.get('author_label_font_size','24sp')
recip_label_font_size=data.get('author_label_font_size','14sp')
# minwidth = 400
# maxwidth = 800
# abouts = int(Window.size[0]/1.5)
# if abouts < minwidth: self.width=f'{minwidth}sp'
# if abouts > maxwidth: self.width=f'{maxwidth}sp'
# self.width=f'{abouts}sp'
# self.log('PostCard.img_id =',self.img_id)
# self.log('PostCard.img_ext =',self.img_ext)
# self.log('PostCard.img_src =',self.img_src)
# self.log('PostCard.cache_img_src =',self.cache_img_src)
# pieces
self.author_section_layout = author_section_layout = PostAuthorLayout()
self.author_label = author_label = PostAuthorLabel(text=author_prefix+self.author)
self.author_label.font_name='assets/overpass-mono-semibold.otf'
if self.recipient:
recip=self.recipient
recip='@'+recip if not recip.startswith('@') else recip #(recip if recip and recip[0].isalpha() else recip[1:])
# recip=author_prefix+recip #(recip if recip and recip[0].isalpha() else recip[1:])
self.author_label.text+=f'\n[size={recip_label_font_size}]to '+recip+'[/size]'
self.author_label.markup=True
self.author_label.font_size = author_label_font_size
self.author_label.username=self.author
avatar_img_src = os.path.join(PATH_AVATARS, f'{self.author}.png')
if not os.path.exists(avatar_img_src):
avatar_img_src = os.path.join(PATH_GUI_ASSETS, 'avatars', f'{self.author}.png')
if not os.path.exists(avatar_img_src):
avatar_img_src=PATH_DEFAULT_AVATAR
self.author_avatar = author_avatar = PostAuthorAvatar(source=avatar_img_src) #self.img_src)
self.author_avatar.username=self.author
self.author_section_layout.add_widget(author_avatar)
self.author_section_layout.add_widget(author_label)
# self.author_section_layout.add_widget(MDSeparator(height='1sp',size_hint=(None,None)))
# self.recipient_label = author_label = PostAuthorLabel(text='--> @'+self.recipient)
# self.recipient_label.font_size = '14sp'
# self.author_label.add_widget(self.recipient_label)
# timestamp
timestr=''
#log(self.timestamp)
if self.timestamp:
dt_object = datetime.fromtimestamp(self.timestamp)
timestr = dt_object.strftime("%-d %b %Y %H:%M")
#log('timestr: '+timestr)
self.timestamp_label=PostTimestampLabel(text=timestr)
self.timestamp_label.font_size='14sp'
author_section_layout.add_widget(self.timestamp_label)
# author_section_layout.add_widget(author_avatar)
# self.add_widget(author_section_layout)
if self.cache_img_src:
image_layout = PostImageLayout()
self.image = image = PostImage(source=self.cache_img_src)
image.height = '300sp'
image_layout.add_widget(image)
image_layout.height='300sp'
# self.log(image.image_ratio)
self.post_content = PostContent(text=self.content)
self.post_content.font_size = '24sp'
# post_layout = PostGridLayout()
#content = PostContent()
# add to screen
# self.add_widget(title)
# post_layout.add_widget(author_section_layout)
# post_layout.add_widget(image_layout)
# post_layout.add_widget(content)
self.scroller = scroller = PostScrollView()
self.add_widget(author_section_layout)
# self.add_widget(MDLabel(text='hello'))
#log('img_src ' + str(bool(self.img_src)))
if self.img_src: self.add_widget(image_layout)
def estimate_height(minlen=100,maxlen=600):
num_chars = len(self.content)
# num_lines = num_chars
height = num_chars*1.1
if height>maxlen: height=maxlen
if height<minlen: height=minlen
return height
scroller.size = ('300sp','%ssp' % estimate_height())
# scroller.bind(size=('300sp',scroller.setter('height'))
scroller.add_widget(self.post_content)
self.add_widget(scroller)
# self.add_widget(post_layout)
###
# Any prompts?
if self.post_data.get('type')=='prompt':
if self.post_data.get('prompt_id')=='addcontact':
def on_touch_down(touch):
if hasattr(self,'_touched') and self._touched: return
if self.collide_point(*touch.pos):
asyncio.create_task(
self.app.prompt_addcontact(
self.post_data,
screen=self.screen,
post_id=self.post_id,
post_card=self,
)
)
# self._touched=True
self.on_touch_down=on_touch_down
# self.log('?????',self.cache_img_src, os.path.exists(self.cache_img_src), os.stat(self.cache_img_src).st_size)
if self.cache_img_src and (not os.path.exists(self.cache_img_src) or not os.stat(self.cache_img_src).st_size):
async def do_download_later():
self.log('downloading...')
await self.app.download(self.img_id, self.cache_img_src)
self.image.reload()
return True
#self.open_dialog('posting')
#Thread(target=do_download).start()
asyncio.create_task(do_download_later())
@property
def app(self):
return App.get_running_app()
def load_image(self):
if not self.img_src: return
if self.img_loaded: return
# otherwise load image...
self.app.get_image(self.img_src)
self.log('done getting image!')
self.image.reload()
self.img_loaded=True
#####
class PostCardPopup(PostCard):
def __init__(self,*x,msg_dialog=None,**y):
super().__init__(*x,**y)
self.ok_to_continue=False
self.msg_dialog=msg_dialog
def on_touch_down(self,touch):
# if self.collide_point(*touch.pos):# and not self.ok_to_continue:
# logger.info('ouch!!!')
# The touch has occurred inside the widgets area. Do stuff!
self.ok_to_continue=True
if self.msg_dialog: self.msg_dialog.ok_to_continue=True
return True
class PostCardInputPopup(PostCardPopup):
def on_touch_down(self,touch):
pass
class FeedScreen(ProtectedScreen):
posts = ListProperty()
updated = None
def on_pre_enter(self):
if not super().on_pre_enter(): return
if self.updated:
if False: # @HACK!!!
# if not self.app.comrad.updated or self.updated>=self.app.comrad.updated:
self.log('NOT UPDATING!')
return
# self.root.clear_widgets()
self.log('UPDATING!')
if self.app.map:
self.app.map.dismiss()
self.root.remove_widget(self.app.map)
if not hasattr(self,'get_posts'): self.get_posts=self.app.comrad.posts
self.carousel = self.ids.post_carousel
for post in self.posts:
self.ids.post_carousel.remove_widget(post)
i=0
lim=25
async def go():
# do not get updates! leave that to refresh button!
# await self.app.get_updates()
posts=self.get_posts()
for i,post in enumerate(posts):
if i>lim: break
data = {
'author':post.from_name,
'to_name':post.to_name,
'content':post.msg.get('txt') if type(post.msg)==dict else str(post.msg),
'timestamp':post.timestamp,
'post_data':post.data,
'screen':self,
'post_id':post.post_id,
}
post_obj = PostCard(data)
self.posts.append(post_obj)
self.ids.post_carousel.add_widget(post_obj)
self.updated = time.time()
asyncio.create_task(go())
return True
# def on_pre_enter(self):
# self.clear_deck()
# # for i,x