Advertisement
soulseb

tutututu

Jun 11th, 2025
806
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.15 KB | None | 0 0
  1. from kivy.config import Config
  2. Config.set('graphics', 'width', '360')
  3. Config.set('graphics', 'height', '640')
  4. Config.set('graphics', 'resizable', '0')
  5.  
  6. from kivy.app import App
  7. from kivy.lang import Builder
  8. from kivy.animation import Animation
  9. from kivy.core.window import Window
  10. from kivy.metrics import dp
  11. from kivy.uix.boxlayout import BoxLayout
  12. from kivy.uix.button import Button
  13. from kivy.uix.widget import Widget
  14. from kivy.uix.behaviors import ButtonBehavior
  15. from kivy.uix.label import Label
  16. from kivy.uix.modalview import ModalView
  17. from kivy.properties import StringProperty, NumericProperty
  18. from kivy.utils import platform
  19. from kivy.clock import Clock
  20.  
  21. Builder.load_string('''
  22. <ClickableOverlay>:
  23.    canvas:
  24.        Color:
  25.            rgba: 0, 0, 0, 0.3 if self.active else 0
  26.        Rectangle:
  27.            pos: self.pos
  28.            size: self.size
  29.  
  30. <ContentItem>:
  31.    orientation: 'horizontal'
  32.    size_hint_y: None
  33.    height: dp(50)
  34.    spacing: dp(5)
  35.    padding: dp(5)
  36.    canvas.before:
  37.        Color:
  38.            rgba: 0.4, 0.4, 0.6, 1
  39.        Rectangle:
  40.            pos: self.pos
  41.            size: self.size
  42.    
  43.    Label:
  44.        id: title_label
  45.        text: root.item_title
  46.        size_hint_x: 0.8
  47.        halign: 'left'
  48.        valign: 'middle'
  49.        text_size: self.width, None
  50.        color: 1, 1, 1, 1
  51.        font_size: dp(16)
  52.        bold: True
  53.    
  54.    Button:
  55.        id: info_button
  56.        text: 'i'
  57.        size_hint_x: 0.2
  58.        size_hint_y: 1
  59.        background_normal: ''
  60.        background_color: 0.8, 0.8, 0.2, 1
  61.        font_size: dp(14)
  62.        bold: True
  63.        on_press: root.show_info()
  64.  
  65. <InfoDialog>:
  66.    size_hint: (0.8, 0.8)
  67.    auto_dismiss: True
  68.    BoxLayout:
  69.        orientation: 'vertical'
  70.        padding: dp(20)
  71.        spacing: dp(10)
  72.        canvas.before:
  73.            Color:
  74.                rgba: 0.3, 0.3, 0.5, 1
  75.            Rectangle:
  76.                pos: self.pos
  77.                size: self.size
  78.        
  79.        Label:
  80.            text: root.title
  81.            font_size: dp(20)
  82.            bold: True
  83.            color: 1, 1, 1, 1
  84.            size_hint_y: 0.3
  85.        
  86.        Label:
  87.            text: root.description
  88.            font_size: dp(16)
  89.            color: 1, 1, 1, 1
  90.            text_size: self.width, None
  91.            valign: 'top'
  92.            halign: 'left'
  93.            size_hint_y: 0.7
  94.        
  95.        Button:
  96.            text: 'Close'
  97.            size_hint_y: 0.2
  98.            background_normal: ''
  99.            background_color: 0.8, 0.3, 0.3, 1
  100.            on_press: root.dismiss()
  101.  
  102. <SearchApplicationUI>:
  103.    orientation: 'vertical'
  104.    spacing: dp(5)
  105.    padding: [0, 0, 0, root.keyboard_padding]
  106.    
  107.    BoxLayout:
  108.        id: notification_panel
  109.        size_hint_y: None
  110.        height: 0
  111.        opacity: 0
  112.        canvas.before:
  113.            Color:
  114.                rgba: 0.2, 0.8, 0.4, 0.9
  115.            Rectangle:
  116.                pos: self.pos
  117.                size: self.size
  118.        Label:
  119.            id: notification_label
  120.            text: ''
  121.            color: 1, 1, 1, 1
  122.            font_size: dp(18)
  123.            bold: True
  124.            halign: 'center'
  125.            padding: [dp(10), dp(5)]
  126.    
  127.    ScrollView:
  128.        id: content_scroll
  129.        size_hint_y: 1
  130.        do_scroll_y: True
  131.        
  132.        BoxLayout:
  133.            id: items_container
  134.            orientation: 'vertical'
  135.            size_hint_y: None
  136.            height: self.minimum_height
  137.            spacing: dp(5)
  138.            padding: [dp(10), dp(0)]
  139.    
  140.    BoxLayout:
  141.        id: search_controls
  142.        size_hint_y: None
  143.        height: dp(60)
  144.        padding: dp(10)
  145.        spacing: dp(5)
  146.        
  147.        TextInput:
  148.            id: search_field
  149.            hint_text: 'Enter search query...'
  150.            multiline: False
  151.            size_hint_x: 0.8
  152.            padding: [dp(10), (self.height - self.line_height)/2]
  153.            font_size: dp(16)
  154.            on_focus: root.on_search_focus_changed(*args)
  155.            on_text_validate: root.perform_search()
  156.        
  157.        Button:
  158.            id: action_btn
  159.            text: 'Add'
  160.            size_hint_x: 0.2
  161.            font_size: dp(13)
  162.            bold: True
  163.            background_normal: ''
  164.            background_color: (0.4, 0.6, 0.4, 1)
  165.            on_press: root.toggle_notification_panel()
  166.    
  167.    ClickableOverlay:
  168.        id: keyboard_dismiss_area
  169.        size_hint: (1, 1)
  170.        active: False
  171.        on_press:
  172.            root.hide_virtual_keyboard()
  173.            self.active = False
  174. ''')
  175.  
  176. class ClickableOverlay(ButtonBehavior, Widget):
  177.     active = False
  178.  
  179. class InfoDialog(ModalView):
  180.     title = StringProperty('')
  181.     description = StringProperty('')
  182.  
  183. class ContentItem(ButtonBehavior, BoxLayout):
  184.     item_title = StringProperty('')
  185.     item_description = StringProperty('')
  186.    
  187.     def __init__(self, item_title="", item_description="", **kwargs):
  188.         super().__init__(**kwargs)
  189.         self.item_title = item_title
  190.         self.item_description = item_description
  191.    
  192.     def on_press(self):
  193.         app = App.get_running_app()
  194.         app.root.ids.notification_label.text = f"Selected: {self.item_title}"
  195.         if app.root.ids.notification_panel.height == 0:
  196.             app.root.show_notification_panel()
  197.    
  198.     def show_info(self):
  199.         dialog = InfoDialog(title=self.item_title,
  200.                           description=self.item_description)
  201.         dialog.open()
  202.  
  203. class SearchApplicationUI(BoxLayout):
  204.     keyboard_height = NumericProperty(0)
  205.     keyboard_padding = NumericProperty(0)
  206.    
  207.     def __init__(self, **kwargs):
  208.         super().__init__(**kwargs)
  209.         self._keyboard_listener = None
  210.         self._keyboard_measured = False
  211.         Window.bind(on_keyboard=self._on_keyboard)
  212.        
  213.         # Для Android настраиваем слушатель клавиатуры
  214.         if platform == 'android':
  215.             Clock.schedule_once(self._setup_keyboard_listener, 0.5)
  216.        
  217.         self.initialize_content()
  218.         Window.clearcolor = (0.4, 0.4, 0.4, 1)
  219.    
  220.     def _setup_keyboard_listener(self, dt):
  221.         """Установка слушателя клавиатуры для Android"""
  222.         try:
  223.             from android.runnable import run_on_ui_thread
  224.             from jnius import autoclass
  225.            
  226.             @run_on_ui_thread
  227.             def attach_listener():
  228.                 View = autoclass('android.view.View')
  229.                 root_view = Window._get_activity().getWindow().getDecorView()
  230.                 root_view.getViewTreeObserver().addOnGlobalLayoutListener(
  231.                     KeyboardListener(self))
  232.            
  233.             attach_listener()
  234.         except Exception as e:
  235.             print(f"Error setting up keyboard listener: {e}")
  236.    
  237.     def _on_keyboard(self, window, key, *args):
  238.         """Обработка аппаратной клавиатуры"""
  239.         if key == 27:  # ESC key
  240.             self.hide_virtual_keyboard()
  241.             return True
  242.         return False
  243.    
  244.     def on_search_focus_changed(self, instance, has_focus):
  245.         """Измеряем высоту клавиатуры при фокусе"""
  246.         if has_focus:
  247.             if platform == 'android':
  248.                 Clock.schedule_once(self._measure_keyboard_height, 0.3)
  249.             self.ids.keyboard_dismiss_area.active = True
  250.         else:
  251.             self.ids.keyboard_dismiss_area.active = False
  252.    
  253.     def _measure_keyboard_height(self, dt):
  254.         """Точное измерение высоты клавиатуры"""
  255.         try:
  256.             input_field = self.ids.search_field
  257.             pos = input_field.to_window(*input_field.pos)
  258.            
  259.             # Вычисляем видимую высоту над клавиатурой
  260.             visible_height = pos[1] + input_field.height
  261.             self.keyboard_height = max(0, Window.height - visible_height)
  262.            
  263.             # Обновляем отступ и показываем результат
  264.             self.keyboard_padding = self.keyboard_height
  265.             self.ids.notification_label.text = f"Keyboard: {self.keyboard_height:.1f}px"
  266.             self.show_notification_panel()
  267.            
  268.             # Прокручиваем к полю ввода
  269.             Clock.schedule_once(lambda dt: self.ids.content_scroll.scroll_to(input_field), 0.1)
  270.            
  271.         except Exception as e:
  272.             print(f"Keyboard measurement error: {e}")
  273.    
  274.     def hide_virtual_keyboard(self):
  275.         """Скрываем виртуальную клавиатуру"""
  276.         self.ids.search_field.focus = False
  277.         self.keyboard_padding = 0
  278.    
  279.     def initialize_content(self):
  280.         """Заполняем контент"""
  281.         for i in range(1, 21):
  282.             item = ContentItem(
  283.                 item_title=f'Item {i}',
  284.                 item_description=f'Detailed description for item {i}.'
  285.             )
  286.             self.ids.items_container.add_widget(item)
  287.    
  288.     def toggle_notification_panel(self):
  289.         """Переключаем панель уведомлений"""
  290.         if self.ids.notification_panel.height == 0:
  291.             query = self.ids.search_field.text.strip()
  292.             if query:
  293.                 self.ids.notification_label.text = f"Added: {query}"
  294.                 self.show_notification_panel()
  295.         else:
  296.             self.hide_notification_panel()
  297.    
  298.     def show_notification_panel(self):
  299.         """Показываем панель уведомлений"""
  300.         Animation(height=dp(50), opacity=1, duration=0.3).start(self.ids.notification_panel)
  301.         self.ids.action_btn.text = "Remove"
  302.         self.ids.action_btn.background_color = (0.8, 0.3, 0.3, 1)
  303.    
  304.     def hide_notification_panel(self):
  305.         """Скрываем панель уведомлений"""
  306.         Animation(height=0, opacity=0, duration=0.3).start(self.ids.notification_panel)
  307.         self.ids.action_btn.text = "Add"
  308.         self.ids.action_btn.background_color = (0.4, 0.6, 0.4, 1)
  309.    
  310.     def perform_search(self):
  311.         """Выполняем поиск"""
  312.         query = self.ids.search_field.text.strip()
  313.         if query:
  314.             self.ids.notification_label.text = f"Found: {query}"
  315.             if self.ids.notification_panel.height == 0:
  316.                 self.show_notification_panel()
  317.  
  318. # Класс для слушателя клавиатуры Android
  319. if platform == 'android':
  320.     from jnius import PythonJavaClass, java_method
  321.    
  322.     class KeyboardListener(PythonJavaClass):
  323.         __javainterfaces__ = ['android/view/ViewTreeObserver$OnGlobalLayoutListener']
  324.         __javacontext__ = 'app'
  325.        
  326.         def __init__(self, root_widget):
  327.             super().__init__()
  328.             self.root_widget = root_widget
  329.        
  330.         @java_method('()V')
  331.         def onGlobalLayout(self):
  332.             Clock.schedule_once(lambda dt: self.root_widget._measure_keyboard_height(dt), 0)
  333.  
  334. class SearchApplication(App):
  335.     def build(self):
  336.         return SearchApplicationUI()
  337.  
  338. if __name__ == '__main__':
  339.     SearchApplication().run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement