pull/20/head
quadrismegistus 4 years ago
parent 5faec10f7c
commit 80d55b1487

@ -132,5 +132,8 @@ else:
COLOR_CARD = bone
COLOR_CARD_BORDER = COLOR_CARD
COLOR_ICON=COLOR_LOGO
COLOR_ACCENT = huntergreen
COLOR_ACCENT = huntergreen
COLOR_INACTIVE = COLOR_CARD
COLOR_ACTIVE = russiangreen

@ -81,7 +81,8 @@ class MyLayout(MDBoxLayout):
def change_screen_from_uri(self,uri,*args):
screen_name = route(uri)
self.app.screen = screen_name
return self.change_screen(screen_name,*args)
self.app.log(f'routing to {screen_name}')
self.scr_mngr.current = screen_name
def view_post(self,post_id):
self.post_id=post_id
@ -173,7 +174,8 @@ def draw_background(widget, img_fn='assets/bg.png'):
def route(uri):
prefix,channel,rest = uri.split('/',3)
if not '/' in uri: return None
prefix=uri.split('/')[1] #,channel,rest = uri.split('/',3)
mapd = {
'inbox':'feed',
@ -205,6 +207,7 @@ class MainApp(MDApp):
def change_screen_from_uri(self,uri,*args):
self.uri=uri
self.log('CHANGING SCREEN',uri,'??')
return self.root.change_screen_from_uri(uri,*args)
@property
@ -291,11 +294,13 @@ class MainApp(MDApp):
async def do():
dat = await self.api.register(un)
if 'success' in dat:
self.username=un
self.root.ids.login_screen.login_status.text=dat['success']
self.root.ids.login_screen.login_status.theme_text_color='Custom'
self.root.ids.login_screen.login_status.text_color=rgb(*COLOR_ACCENT)
await asyncio.sleep(1)
#self.save_login(dat)
self.change_screen_from_uri('/inbox/earth')
return True
elif 'error' in dat:
self.root.ids.login_screen.login_status.text=dat['error']
@ -353,7 +358,7 @@ class MainApp(MDApp):
async def get_post(self,post_id):
return await self.api.get_post(post_id)
async def get_posts(self,uri='/channel/earth'):
async def get_posts(self,uri='/inbox/earth'):
self.log(f'app.get_posts(uri={uri} -> ...')
data = await self.api.get_posts(uri)
self.log

@ -13,7 +13,7 @@ from kivy.uix.boxlayout import BoxLayout
from kivymd.theming import ThemableBehavior
from kivymd.uix.button import MDIconButton
from kivymd.uix.stacklayout import MDStackLayout
from main import COLOR_TEXT,rgb,COLOR_ICON
from main import COLOR_TEXT,rgb,COLOR_ICON,COLOR_ACCENT
Builder.load_string(
"""
@ -80,8 +80,6 @@ Builder.load_string(
"""
)
@ -90,6 +88,7 @@ def get_separator(height):
from kivymd.uix.boxlayout import MDBoxLayout
return MDBoxLayout(height=height,size_hint=(None,None))
class MyChip(BoxLayout, ThemableBehavior):
label = StringProperty()
"""Chip text.
@ -195,3 +194,172 @@ class MDChooseChip(MDStackLayout):
if isinstance(widget, MyChip):
return super().add_widget(widget)
#### DROPDOWN
from kivy.app import App
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import NumericProperty, ListProperty, BooleanProperty, ObjectProperty
from kivy.uix.recycleview import RecycleView
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
Builder.load_string('''
<Body>:
canvas:
Color:
rgba:(1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
<DropDownWidget>:
canvas:
Color:
rgba:(1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
orientation: 'vertical'
spacing: 2
txt_input: txt_input
rv: rv
MyTextInput:
id: txt_input
size_hint_y: None
height: 50
RV:
id: rv
<MyTextInput>:
readonly: False
multiline: False
<SelectableLabel>:
# Draw a background to indicate selection
color: 0,0,0,1
canvas.before:
Color:
rgba: (0, 0, 1, .5) if self.selected else (1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
<RV>:
canvas:
Color:
rgba: 0,0,0,.2
Line:
rectangle: self.x +1 , self.y, self.width - 2, self.height -2
bar_width: 10
scroll_type:['bars']
viewclass: 'SelectableLabel'
SelectableRecycleBoxLayout:
default_size: None, dp(20)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: False
''')
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableLabel(RecycleDataViewBehavior, Label):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableLabel, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
if is_selected:
print("selection changed to {0}".format(rv.data[index]))
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
class DropDownWidget(BoxLayout):
txt_input = ObjectProperty()
rv = ObjectProperty()
class MyTextInput(TextInput):
txt_input = ObjectProperty()
flt_list = ObjectProperty()
word_list = ListProperty()
#this is the variable storing the number to which the look-up will start
starting_no = NumericProperty(3)
suggestion_text = ''
def __init__(self, **kwargs):
super(MyTextInput, self).__init__(**kwargs)
def on_text(self, instance, value):
#find all the occurrence of the word
self.parent.ids.rv.data = []
matches = [self.word_list[i] for i in range(len(self.word_list)) if self.word_list[i][:self.starting_no] == value[:self.starting_no]]
#display the data in the recycleview
display_data = []
for i in matches:
display_data.append({'text':i})
self.parent.ids.rv.data = display_data
#ensure the size is okay
if len(matches) <= 10:
self.parent.height = (50 + (len(matches)*20))
else:
self.parent.height = 240
def keyboard_on_key_down(self, window, keycode, text, modifiers):
if self.suggestion_text and keycode[1] == 'tab':
self.insert_text(self.suggestion_text + ' ')
return True
return super(MyTextInput, self).keyboard_on_key_down(window, keycode, text, modifiers)
class Body(FloatLayout):
def __init__(self, **kwargs):
super(Body, self).__init__(**kwargs)
widget_1 = DropDownWidget(pos_hint = {'center_x':.5,'center_y':.5}, \
size_hint = (None, None), size = (600, 60))
widget_1.ids.txt_input.word_list = ['how to use python', 'how to use kivy', 'how to ...']
widget_1.ids.txt_input.starting_no = 3
self.add_widget(widget_1)

@ -1,5 +1,9 @@
#:import PostScreen screens.post.post.PostScreen
#:import COLOR_TEXT main.COLOR_TEXT
#:import COLOR_CARD main.COLOR_CARD
#:import COLOR_ACCENT main.COLOR_CARD
#:import COLOR_INACTIVE main.COLOR_INACTIVE
#:import COLOR_ACTIVE main.COLOR_ACTIVE
<AddPostTextField>
id: post_content_input
@ -31,6 +35,8 @@
pos_hint: {'center_x': .5, 'y':0.05}
# md_bg_color: 1,1,0,1
<UploadButton>:
id: file_chooser_button
text: "upload"
@ -128,14 +134,7 @@
pos_hint: {'center_x':0.5, 'center_y':0.5}
# radius:[20,]
# border_radius:20
canvas:
Color:
rgb: rgb(*COLOR_TEXT)
Line:
width: 1
rectangle: (self.x, self.y, self.width, self.height)
# radius:[20,]
# border_radius:20
MDLabel:
@ -155,3 +154,75 @@
<PostScreen>:
name: 'post'
id: post_screen
<ChannelLayout>:
adaptive_width: True
adaptive_height: True
height: self.minimum_height
width: self.minimum_width
size_hint: None,None
# height:'10sp'
# adaptive_height: True
size_hint:1,None
# md_bg_color: 1,1,0,1
spacing:0,0
padding:0,0,0,0
orientation: 'lr-tb'
<ChannelChip>
# size_hint: None, None
height: "26sp"
padding: 0, 0, 0, 0
# text: ""
md_bg_color: rgb(*COLOR_CARD)
on_release: self.callback()
icon: 'check-box-outline'
line_color: rgb(*COLOR_CARD)
color: rgb(*COLOR_CARD)
theme_text_color: 'Custom'
text_color: rgb(*COLOR_TEXT)
# MDBoxLayout:
# id: box_check
# adaptive_size: True
# pos_hint: {'center_y': .5}
# padding: dp(0)
# size_hint:None,None
# MDBoxLayout:
# id: chiplayout
# adaptive_width: True
# width: self.minimum_width
# size_hint:None,None
# padding: dp(0)
# # MDIconButton:
# # id: icon
# # icon: root.icon
# # size_hint_y: None
# # height: "26dp"
# # pos_hint: {"center_y": .5}
# # user_font_size: "12dp"
# # disabled: True
# # md_bg_color_disabled: 0, 0, 0, 0
# # theme_text_color: "Custom"
# # text_color: rgb(*COLOR_TEXT)
# # size_hint:None,None
# # width: "26dp"
# 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: "12sp"
# halign:"left"
# size_hint:None,None

@ -3,7 +3,8 @@ from plyer import filechooser
from kivymd.uix.label import MDLabel
from kivymd.uix.textfield import MDTextField
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDRectangleFlatButton, MDIconButton, MDRaisedButton
from kivymd.uix.stacklayout import MDStackLayout
from kivymd.uix.button import MDRectangleFlatButton, MDIconButton, MDRaisedButton,MDFillRoundFlatButton,MDRoundFlatIconButton
from kivy.properties import ListProperty,ObjectProperty
from kivy.app import App
from screens.feed.feed import *
@ -11,8 +12,27 @@ import os,time,threading
from threading import Thread
from kivymd.uix.dialog import MDDialog
from kivy.core.image import Image as CoreImage
from kivymd.uix.gridlayout import MDGridLayout
import io,shutil,asyncio
from main import rgb,COLOR_TEXT
from kivymd.uix.chip import MDChip
from main import rgb,COLOR_TEXT,COLOR_ACCENT,COLOR_CARD,COLOR_INACTIVE,COLOR_ACTIVE
from misc import *
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
from main import COLOR_TEXT,rgb,COLOR_ICON,COLOR_ACCENT,COLOR_INACTIVE
class ProgressPopup(MDDialog): pass
class MessagePopup(MDDialog): pass
@ -53,6 +73,100 @@ class PostButton(MDRectangleFlatButton): pass
class PostStatus(MDRectangleFlatButton): pass
class SelectAddressee(DropDownWidget):
def __init__(self, wordlist, **kwargs):
super().__init__(**kwargs)
self.pos_hint = {'center_x':.5,'center_y':.5}
self.size_hint = (None, None)
self.size = (600, 60)
self.ids.txt_input.word_list = wordlist
self.ids.txt_input.starting_no = 1
class ChannelLayout(MDStackLayout):
pass
class ChannelChip(MDRoundFlatIconButton):
def callback(self):
val=self.check if hasattr(self,'check') else False
self.check = not val
self.icon='checkbox-blank-outline' if self.check else 'check-box-outline'
# self.md_bg_color=rgb(*COLOR_INACTIVE) if not self.check else rgb(*COLOR_ACTIVE)
# raise Exception(['GOT VALL',val])
pass
# def on_icon(self, instance, value):
# self.log('on_icon',instance,value)
# if value == "":
# self.icon = "check-box-outline"
# self.remove_widget(self.ids.icon)
# def on_touch_down(self, touch):
# colorobj=self.children[1]
# if not self.check:
# self.check=True
# self.icon="check-box-outline"
# self.color=rgb(*COLOR_ACTIVE)
# self.selected_chip_color=rgb(*COLOR_ACTIVE)
# colorobj.md_bg_color=rgb(*COLOR_ACTIVE)
# self.log(f'check = {self.check} and icon = {self.icon} and color = {self.color}')
# else:
# self.selected_chip_color=rgb(*COLOR_INACTIVE)
# self.check=False
# self.icon="checkbox-blank-outline"
# self.color=rgb(*COLOR_INACTIVE)
# colorobj.md_bg_color=rgb(*COLOR_INACTIVE)
# self.log(f'check = {self.check} and icon = {self.icon} and color = {self.color}')
# self.md_bg_color=rgb(*COLOR_INACTIVE)
# self.parent.parent.to_channels[self.label]=self.check
# self.color=rgb(*COLOR_ACCENT) if self.check else (rgb(50,50,50))
# self.log(md_choose_chip.parent.to_channels)
# self.ids.chiplayout.md_bg_color=self.color
# 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-box-outline",
# 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 PostScreen(ProtectedScreen):
post_id = ObjectProperty()
@ -72,7 +186,39 @@ class PostScreen(ProtectedScreen):
post_TextField.font_name='assets/overpass-mono-regular.otf'
post_TextField.hint_text='word?'
#self.addressee = SelectAddressee(list(self.app.keys.keys()))
#post.add_widget(self.addressee)
# post.remove_widget(post.scroller)
self.channel_layout = ChannelLayout() #MDBoxLayout(size_hint=(1,None),orientation='horizontal',cols=3)
# self.channel_layout.orientation='horizontal'
# self.channel_layout.cols=1
# self.channel_layout.size_hint=(1,None)
# self.channel_layout.adaptive_height=True
# self.channel_layout.adaptive_=True
# self.channel_layout.spacing='20dp'
# self.channel_layout.padding='15dp'
# self.channel_layout.height='300sp' #self.channel_layout.minimum_height
post.add_widget(self.channel_layout,1)
self.post_card.to_channels = {}
for channel in self.app.keys:
chip = ChannelChip()
# chip.ids.icon.width='26sp'
self.log(f'adding channel {channel}')
chip.text = '@'+channel
# chip.color=rgb(*COLOR_INACTIVE)
# chip.ids.chiplayout.md_bg_color=chip.color
# chip.width='100sp'
chip.font_name='assets/font.otf'
chip.md_bg_color=rgb(*COLOR_INACTIVE)
# chip.theme_text_color='Custom'
# chip.text_color=rgb(*COLOR_INACTIVE)
self.channel_layout.add_widget(chip)
self.post_card.to_channels[channel]=False
post.scroller.remove_widget(post.post_content)
post.scroller.add_widget(post_TextField)
post.scroller.size=('300dp','300dp')

@ -86,7 +86,7 @@ class Api(object):
i = 0
self._node = await self.connect(port=port)
while True:
if not i%10: self.log(f'Node status (tick {i}): {self._node}')
if not i%60: self.log(f'Node status (tick {i}): {self._node}')
if i and not i%save_every: await self.flush()
i += 1
await asyncio.sleep(NODE_SLEEP_FOR)
@ -122,7 +122,7 @@ class Api(object):
async def get(self,key_or_keys,decode_data=True):
self.log(f'get({key_or_keys}) --> ...')
self.log(f'get({key_or_keys},decode_data={decode_data}) --> ...')
async def _get():
node=await self.node
res=None
@ -140,7 +140,7 @@ class Api(object):
val = await node.get(key)
res = await self.decode_data(val) if decode_data else val
# self.log(f'_get({key_or_keys}) --> {res}')
self.log(f'_get({key_or_keys}) --> {res}')
return res
return await _get()
@ -213,13 +213,19 @@ class Api(object):
return final_packet
async def decode_data(self,entire_packet,sep=BSEP,private_key=None,sep2=BSEP2):
if entire_packet is None: return entire_packet
#entire_packet = base64.b64decode(entire_packet)
async def decode_data(self,entire_packet_orig,sep=BSEP,private_key=None,sep2=BSEP2):
if entire_packet_orig is None: return entire_packet_orig
entire_packet = base64.b64decode(entire_packet_orig)
self.log('????',type(entire_packet))
self.log(entire_packet)
# get data
encrypted_payload, decryption_tools = entire_packet.split(sep)
decryption_tools=decryption_tools.split(sep2)
try:
encrypted_payload, decryption_tools = entire_packet.split(sep)
decryption_tools=decryption_tools.split(sep2)
except ValueError:
self.log('!! decode_data() got incorrect format')
return entire_packet_orig
# ### FIRST LINE OF PROTECTION
# # is the receiver's public id in our list of public IDs?
@ -311,6 +317,7 @@ class Api(object):
async def set(self,key_or_keys,value_or_values,private_signature_key=None,encode_data=True):
self.log(f'api.set({key_or_keys}) --> {type(value_or_values)}')
async def _set():
# self.log('async _set()',self.node)
# node=self.node
@ -496,9 +503,9 @@ class Api(object):
fnfn = os.path.join(KEYDIR,priv_key_fn)
print(fnfn)
priv_key=load_privkey_fn(fnfn)
pub_key=priv_key.public_key()
#pub_key=priv_key.public_key()
name_key= '.'.join(priv_key_fn.split('.')[1:-1])
res[name_key] = (pub_key, priv_key)
res[name_key] = priv_key
self.log(f'[API] found key {name_key} and added to keychain')
return res
@ -595,19 +602,21 @@ class Api(object):
async def post(self,data,channels = ['earth'], add_profile=True):
async def post(self,data,to_inbox,add_to_outbox=True):
post_id=get_random_id()
res = await self.set_json('/post/'+post_id, data)
self.log('Api.post() got data back from set_json():',res)
# ## add to channels
res = await asyncio.gather(*[
self.append_json(f'/posts/channel/{channel}',post_id) for channel in channels
])
if not res:
self.log('!! error, couldn\'t set post json')
return
# ## add to inbox
self.append_json(f'/inbox/{to_inbox}',post_id)
# ## add to user
un=data.get('author')
if un and add_profile: await self.append_json('/posts/author/'+un, post_id)
## add to outbox
if add_to_outbox:
un=data.get('author')
if un:
await self.append_json(f'/outbox/{un}', post_id)
if res:
asyncio.create_task(self.flush())
@ -627,15 +636,15 @@ class Api(object):
async def get_post(self,post_id):
return await self.get_json_val(post_id,decode_data=True)
async def get_posts(self,uri='/posts/channel/earth'):
async def get_posts(self,uri='/inbox/earth'):
# index = await self.get_json_val('/posts'+uri)
self.log(f'api.get_posts(uri={uri}) --> ...')
index = await self.get_json_val(uri,decode_data=True)
self.log('got index?',index)
if index is None: return []
if type(index)!=list: index=[index]
self.log('got index?',index)
index = [x for x in index if x is not None]
## get full json

Loading…
Cancel
Save