From 08bb63c783a68f5ffddb1f3fac18c438e3585e18 Mon Sep 17 00:00:00 2001 From: Emendir Date: Fri, 14 Mar 2025 07:44:32 +0100 Subject: [PATCH] profiles dropdown --- install_prereqs.sh | 20 +++++++++++ src/endra_app/_load_kivy.py | 40 +++++++++++++++++++++ src/endra_app/chat_page.kv | 6 ++-- src/endra_app/main.py | 6 ++-- src/endra_app/profiles.kv | 50 ++++++++++++++++++++++++++ src/endra_app/profiles.py | 72 +++++++++++++++++++++++++++++++++++++ src/endra_app/settings.kv | 6 ++-- src/endra_app/settings.py | 6 ++-- src/endra_app/side_bar.kv | 33 +++++++++++++---- src/endra_app/side_bar.py | 15 +++++--- src/endra_app/utils.kv | 4 +-- 11 files changed, 235 insertions(+), 23 deletions(-) create mode 100644 install_prereqs.sh create mode 100644 src/endra_app/_load_kivy.py create mode 100644 src/endra_app/profiles.kv create mode 100644 src/endra_app/profiles.py diff --git a/install_prereqs.sh b/install_prereqs.sh new file mode 100644 index 0000000..a5c42f4 --- /dev/null +++ b/install_prereqs.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +## Install kivy with more advanced font handling +## See https://kivy.org/doc/stable/gettingstarted/installation.html#from-source + +# the absolute path of this script's directory +SCRIPT_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +cd $SCRIPT_DIR + +set -e # Exit if any command fails + +sudo apt install libfreetype6-dev libpango1.0-dev libpangoft2-1.0-0 + +cd "$(mktemp -d)" +curl https://raw.githubusercontent.com/kivy/kivy/master/tools/build_linux_dependencies.sh -o build_kivy_deps.sh +chmod +x build_kivy_deps.sh +./build_kivy_deps.sh +KIVY_DEPS_ROOT=$(pwd)/kivy-dependencies +export KIVY_DEPS_ROOT +python -m pip install "kivy[full]" kivy_examples --no-binary kivy diff --git a/src/endra_app/_load_kivy.py b/src/endra_app/_load_kivy.py new file mode 100644 index 0000000..66d388f --- /dev/null +++ b/src/endra_app/_load_kivy.py @@ -0,0 +1,40 @@ +"""This script tries to load kivy with more advanced font handling if possible. +""" +import os +USING_PANGO = False +try: + os.environ['KIVY_TEXT'] = 'pango' + import kivy + from kivy.core.text import FontContextManager as FCM + FCM.create('system://myapp') + # family = FCM.add_font('system://myapp', 'LibertinusSerif-Regular.otf') + # family = FCM.add_font('system://myapp', 'FreeSerif.ttf') + # family = FCM.add_font('system://myapp', 'NotoColorEmoji.ttf') + USING_PANGO = True + print("Successfully loaded font context!") +except: + os.environ.pop('KIVY_TEXT') # = ORG_KIVY_TEXT + print("Failed to load font context, pity. Reloading kivy.") + import importlib + importlib.reload(kivy) + + +if __name__ == '__main__': + from kivy.app import App + from kivy.uix.label import Label + + class MyApp(App): + def build(self): + return Label( + text='''Hello there! +⏷▼⮟⯆🞃🚀😊 +Русский +Tiếng Việt +العربية +中文 +日本語 +বাংলা + ''', + font_context='system://myapp', + ) + MyApp().run() diff --git a/src/endra_app/chat_page.kv b/src/endra_app/chat_page.kv index 89ce4d3..2d843e2 100644 --- a/src/endra_app/chat_page.kv +++ b/src/endra_app/chat_page.kv @@ -17,6 +17,7 @@ font_size: 16 color: 0.9, 0.9, 0.9, 1 size_hint: 0.6, 1 + font_context: 'system://myapp' orientation: 'vertical' TextInput: @@ -24,6 +25,7 @@ background_color: 0.1, 0.1, 0.1, 1 # Dark background foreground_color: 0.9, 0.9, 0.9, 1 # Light text color hint_text: 'message text' # Placeholder text + font_context: 'system://myapp' orientation: 'vertical' size_hint_x: 0.7 @@ -39,7 +41,7 @@ BoxLayout: id: top_bar_lyt orientation: 'horizontal' - size_hint_y: 0.15 + size_hint_y: None Button: id: invite_btn @@ -61,7 +63,7 @@ BoxLayout: id: add_message_lyt orientation: 'horizontal' - size_hint_y: 0.15 + size_hint_y: None BoxLayout: id: add_message_btn_lyt size_hint_x: 3 diff --git a/src/endra_app/main.py b/src/endra_app/main.py index 594e094..01b564c 100644 --- a/src/endra_app/main.py +++ b/src/endra_app/main.py @@ -1,4 +1,4 @@ -# main.py +from . import _load_kivy # IMPORTANT: import this before importing kivy from kivy.app import App from kivy.uix.boxlayout import BoxLayout from .side_bar import SideBar @@ -56,7 +56,8 @@ class MainApp(App): ) profiles.update({profile.did: profile}) return profiles - + def get_profile_ids(self)->set[str]: + return set(self.profiles.keys()) def create_profile(self) -> Profile: tempdir = tempfile.mkdtemp() tempdir @@ -79,4 +80,5 @@ def main(): if __name__ == '__main__': + print(f"USING_PANGO: {_load_kivy.USING_PANGO}") main() diff --git a/src/endra_app/profiles.kv b/src/endra_app/profiles.kv new file mode 100644 index 0000000..4821386 --- /dev/null +++ b/src/endra_app/profiles.kv @@ -0,0 +1,50 @@ +: + + BoxLayout: + + orientation: 'vertical' + size_hint: 1, None # Important! Tell DropDown the height is explicit + height: self.minimum_height # So it fits content dynamically + padding: 10 + canvas.before: + Color: + rgba: 0.15, 0.15, 0.15, 1 # background colour + Rectangle: + size: self.size + pos: self.pos + ScrollView: + id: scroll_view + size_hint_y: None + + GridLayout: + id: scroll_layout + cols: 1 + spacing: 1 + size_hint_y: None + + Button: + id: add_profile_btn + text: "Add Profile" + size_hint_y: None + height: 50 + background_color: 0.8, 0.3, 0.3, 1 # Light red button + +: + orientation: 'horizontal' + size_hint_y: 1 + height: 50 + spacing: 5 + padding: 5 + canvas.before: + Color: + rgba: 0.1, 0.1, 0.1, 1 # background colour + Rectangle: + size: self.size + pos: self.pos + + Label: + id: label + font_size: 16 + color: 0.9, 0.9, 0.9, 1 + size_hint: 0.6, 1 + font_context: 'system://myapp' diff --git a/src/endra_app/profiles.py b/src/endra_app/profiles.py new file mode 100644 index 0000000..e4c6270 --- /dev/null +++ b/src/endra_app/profiles.py @@ -0,0 +1,72 @@ +# side_bar.py +from endra import Profile +from .utils import InvitationPopupView +import json +from loguru import logger +from kivy.uix.boxlayout import BoxLayout +from kivy.lang import Builder +import os +from kivy.uix.dropdown import DropDown +# Load the KV file +KV_FILE = os.path.join(os.path.dirname(__file__), "profiles.kv") +Builder.load_file(KV_FILE) + + +class ProfilesView(DropDown): + def __init__(self, **kwargs): + super().__init__(**kwargs) + + # self.layout = self.ids.layout + self.scroll_view = self.ids.scroll_view + self.scroll_layout = self.ids.scroll_layout + self.add_profile_btn = self.ids.add_profile_btn + + def remove_widget_from_scroll(self, index): + if 0 <= index < len(self.scroll_layout.children): + self.scroll_layout.remove_widget( + self.scroll_layout.children[index]) + + def remove_scroll_widgets(self): + while (len(self.scroll_layout.children)): + self.scroll_layout.remove_widget(self.scroll_layout.children[0]) + + +class Profiles(ProfilesView): + def __init__(self, main, profile: Profile, **kwargs): + super().__init__(**kwargs) + self.main = main + self.profile = profile + + self.add_profile_btn.bind(on_press=self.offer_add_profile) + self.reload_profiles() + print("Loading Dropdown!") + + def offer_add_profile(self, *args, **kwargs): + pass + + def reload_profiles(self): + logger.info("Reloading profiles...") + + for profile in self.main.profiles.values(): + print("PROFILE", profile.did) + self.add_profile_wdg(profile) + + def add_profile_wdg(self, profile: Profile): + widget = ProfileItem( + main=self.main, profile=profile + ) + self.scroll_layout.add_widget(widget) + + +class ProfileItemView(BoxLayout): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.label = self.ids.label + + +class ProfileItem(ProfileItemView): + def __init__(self, main, profile: Profile, **kwargs): + super().__init__(**kwargs) + self.main = main + self.profile = profile + self.label.text = profile.did diff --git a/src/endra_app/settings.kv b/src/endra_app/settings.kv index 9146cdf..05da549 100644 --- a/src/endra_app/settings.kv +++ b/src/endra_app/settings.kv @@ -8,7 +8,8 @@ orientation: 'vertical' Label: text: "Devices" - size_hint_y: 0.1 + size_hint_y: None + font_context: 'system://myapp' ScrollView: id: scroll_view size_hint: 1, 1 @@ -25,7 +26,7 @@ size_hint: 1, None height: 50 background_color: 0.8, 0.3, 0.3, 1 # Light red button -: +: orientation: 'horizontal' size_hint_y: None height: 50 @@ -43,3 +44,4 @@ font_size: 16 color: 0.9, 0.9, 0.9, 1 size_hint: 0.6, 1 + font_context: 'system://myapp' diff --git a/src/endra_app/settings.py b/src/endra_app/settings.py index 80fd0ec..1d27b4f 100644 --- a/src/endra_app/settings.py +++ b/src/endra_app/settings.py @@ -63,19 +63,19 @@ class ProfileSettingsPopup(ProfileSettingsPopupView): def add_device_wdg(self, device: Device): print("DEVICE", type(device.id)) print(device.id) - widget = DeviceHeader( + widget = DeviceItem( main=self.main, device=device ) self.scroll_layout.add_widget(widget) -class DeviceHeaderView(BoxLayout): +class DeviceItemView(BoxLayout): def __init__(self, **kwargs): super().__init__(**kwargs) self.label = self.ids.label -class DeviceHeader(DeviceHeaderView): +class DeviceItem(DeviceItemView): def __init__(self, main, device: Device, **kwargs): super().__init__(**kwargs) self.main = main diff --git a/src/endra_app/side_bar.kv b/src/endra_app/side_bar.kv index 41a78d1..6be4e23 100644 --- a/src/endra_app/side_bar.kv +++ b/src/endra_app/side_bar.kv @@ -1,5 +1,5 @@ #:import QRCodeWidget kivy_garden.qrcode -: +: orientation: 'horizontal' size_hint_y: None height: 50 @@ -11,12 +11,13 @@ Rectangle: size: self.size pos: self.pos - Label: id: label font_size: 16 color: 0.9, 0.9, 0.9, 1 size_hint: 0.6, 1 + font_context: 'system://myapp' + orientation: 'vertical' size_hint_x: 0.3 @@ -29,12 +30,30 @@ Rectangle: size: self.size pos: self.pos - Button: - id: my_profile_btn - text: "My Profile" + BoxLayout: + orientation: "horizontal" size_hint: 1, None - height: 50 - background_color: 0.8, 0.3, 0.3, 1 # Light red button + id: profile_controls_lyt + Button: + id: my_profile_btn + text: "My Profile" + size_hint: 0.9, None + height: 50 + background_color: 0.8, 0.3, 0.3, 1 # Light red button + Button: + id: open_profiles_btn + # font_name: "LibertinusSerif-Regular.otf" + # font_name: "NotoColorEmoji.ttf" + # font_name: "NotoSans-Regular.ttf" + # font_name: "DejaVuSans.ttf" + font_name: "FreeSerif.ttf" + + + text: "▼" + size_hint: None, None + height: 50 + background_color: 0.8, 0.3, 0.3, 1 # Light red button + ScrollView: id: scroll_view size_hint: 1, 1 diff --git a/src/endra_app/side_bar.py b/src/endra_app/side_bar.py index 22efadc..fe80b3e 100644 --- a/src/endra_app/side_bar.py +++ b/src/endra_app/side_bar.py @@ -49,13 +49,13 @@ class AddCorrespondencePopupView(Popup): self.dismiss() -class CorrespondenceHeaderView(BoxLayout): +class CorrespondenceItemView(BoxLayout): def __init__(self, **kwargs): super().__init__(**kwargs) self.label = self.ids.label -class CorrespondenceHeader(CorrespondenceHeaderView): +class CorrespondenceItem(CorrespondenceItemView): def __init__(self, main, correspondence: Correspondence, **kwargs): super().__init__(**kwargs) self.main = main @@ -69,15 +69,16 @@ class CorrespondenceHeader(CorrespondenceHeaderView): print(f"Label '{self.label.text}' clicked!") self.main.chat_page.load_correspondence(self.correspondence) - +from .profiles import Profiles class SideBarView(BoxLayout): def __init__(self, **kwargs): super().__init__(**kwargs) self.scroll_view = self.ids.scroll_view - + self.profile_controls_lyt = self.ids.profile_controls_lyt self.scroll_layout = self.ids.scroll_layout self.my_profile_btn = self.ids.my_profile_btn + self.open_profiles_btn = self.ids.open_profiles_btn self.add_corresp_btn = self.ids.add_corresp_btn self.scroll_layout.bind( @@ -103,6 +104,7 @@ class SideBar(SideBarView): self.add_corresp_btn.bind(on_press=self.offer_add_correspondence) self.my_profile_btn.bind(on_press=self.open_profile_settings) + self.open_profiles_btn.bind(on_press=self.open_profiles) self.reload_correspondences() def reload_correspondences(self): @@ -128,9 +130,12 @@ class SideBar(SideBarView): profile=self.profile, ) popup.open() + def open_profiles(self, *args, **kwargs): + dropdown = Profiles(self.main, self.profile) + dropdown.open(self.profile_controls_lyt) def add_correspondence_header(self, correspondence): - widget = CorrespondenceHeader( + widget = CorrespondenceItem( main=self.main, correspondence=correspondence ) self.scroll_layout.add_widget(widget) diff --git a/src/endra_app/utils.kv b/src/endra_app/utils.kv index 9129ecc..147ef16 100644 --- a/src/endra_app/utils.kv +++ b/src/endra_app/utils.kv @@ -10,10 +10,10 @@ text: "Invitation code copied to clipboard!\n(Click to copy again)" text_size: self.size # Enable text wrapping size_hint_y: 1 + font_context: 'system://myapp' : title:'Invitation' - size_hint: None, None size_hint: 0.9,0.9 auto_dismiss: True BoxLayout: @@ -22,6 +22,6 @@ # InvitationView: # id:invitation_view Button: - size_hint_y:0.1 + size_hint_y:None text: 'Close' on_release: root.dismiss()