mirror of
https://github.com/ComradCollective/Comrad
synced 2024-11-01 21:40:32 +00:00
416 lines
12 KiB
Python
416 lines
12 KiB
Python
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
|
|
|
|
Builder.load_string(
|
|
"""
|
|
#:import DEVICE_TYPE kivymd.material_resources.DEVICE_TYPE
|
|
#:import COLOR_TEXT main.COLOR_TEXT
|
|
#:import COLOR_ICON main.COLOR_ICON
|
|
#:import rgb main.rgb
|
|
|
|
<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:rgb(*COLOR_TEXT)
|
|
|
|
# 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: rgb(*COLOR_TEXT)
|
|
|
|
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"
|
|
|
|
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
def get_separator(height,width=None,debug=False):
|
|
from kivymd.uix.boxlayout import MDBoxLayout
|
|
x=MDBoxLayout(height=height,size_hint=(None,None))
|
|
# if debug: x.md_bg_color=(1,1,0,1)
|
|
if width: x.width=width
|
|
return x
|
|
|
|
|
|
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 = rgb(*COLOR_TEXT) #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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 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('''
|
|
#:import COLOR_CARD main.COLOR_CARD
|
|
#:import rgb main.rgb
|
|
|
|
<Body>:
|
|
canvas:
|
|
Color:
|
|
rgba:rgb(*COLOR_CARD)
|
|
Rectangle:
|
|
pos: self.pos
|
|
size: self.size
|
|
|
|
|
|
<DropDownWidget>:
|
|
canvas:
|
|
Color:
|
|
rgba:rgb(*COLOR_CARD)
|
|
Rectangle:
|
|
pos: self.pos
|
|
size: self.size
|
|
|
|
orientation: 'vertical'
|
|
spacing: 2
|
|
size_hint:None,None
|
|
# width:self.minimum_width
|
|
txt_input: txt_input
|
|
rv: rv
|
|
|
|
MyTextInput:
|
|
id: txt_input
|
|
size_hint_y: None
|
|
height: 50
|
|
RV:
|
|
id: rv
|
|
|
|
<MyTextInput>:
|
|
readonly: False
|
|
multiline: False
|
|
size_hint:1,None
|
|
|
|
|
|
<SelectableLabel>:
|
|
# Draw a background to indicate selection
|
|
color: 0,0,0,1
|
|
font_name: 'assets/font.otf'
|
|
|
|
canvas.before:
|
|
Color:
|
|
rgba: (0, 0, 8, .5) if self.selected else rgb(*COLOR_CARD)
|
|
Rectangle:
|
|
pos: self.pos
|
|
size: self.size
|
|
<RV>:
|
|
# height:'400sp'
|
|
canvas:
|
|
Color:
|
|
rgba: 0,0,0,0
|
|
|
|
Line:
|
|
rectangle: self.x +1 , self.y, self.width - 2, self.height -2
|
|
|
|
bar_width: 0
|
|
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'
|
|
size_hint:None,None
|
|
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
|
|
# raise Exception(str([is_selected, rv.data[index]]))
|
|
if is_selected:
|
|
# raise Exception(str([is_selected, rv.data[index]]))
|
|
newval=rv.data[index]['text']
|
|
try:
|
|
pcard=self.parent.parent.parent.parent.parent
|
|
except AttributeError:
|
|
return
|
|
|
|
recip=pcard.recipient=newval[1:]
|
|
pcard.parent.recipient=newval[1:]
|
|
pcard.parent.close_author_option()
|
|
|
|
alabel=pcard.author_label
|
|
#alabel.text=f'@{pcard.author}\n[size=14sp]to @{pcard.recipient}[/size]'
|
|
|
|
pcard.parent.to_whom_btn.ids.txt_input.text = '@'+recip
|
|
|
|
pcard.parent.remove_widget(pcard.parent.to_whom_btn)
|
|
# pcard.author_section_layout.remove_widget(pcard.author_section_layout.children[2])
|
|
# pcard.remove_widget(pcard.parent.to_whom_btn)
|
|
# pcard.remove_widget(self.parent.parent.parent)
|
|
#raise Exception(type())
|
|
# self.parent.parent.parent.children[1].text = rv.data[index]['text']
|
|
#raise Exception(type(=self.te))
|
|
#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*2:
|
|
self.parent.height = (50*2 + (len(matches)*20*2))
|
|
else:
|
|
self.parent.height = 240*2
|
|
|
|
def keyboard_on_key_down(self, window, keycode, text, modifiers):
|
|
|
|
# pcard = self.parent.parent.parent
|
|
# # raise Exception(type(pcard))
|
|
|
|
# recip = pcard.parent.to_whom_btn.ids.txt_input.text.strip()
|
|
# recip = recip[1:] if recip and recip[0]=='@' else recip
|
|
# pcard.recipient = recip
|
|
# alabel=pcard.author_label
|
|
# #alabel.text=f'@{pcard.author}\n[size=14sp]to @{pcard.recipient}'
|
|
|
|
|
|
|
|
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)
|
|
|