This commit is contained in:
yumoqing 2022-10-09 13:14:34 +08:00
parent 4700ba32a3
commit ba29b30fe9
9 changed files with 202 additions and 31 deletions

View File

View File

@ -0,0 +1,46 @@
from kivy.app import App
from jnius import autoclass
import kivy
from android.broadcast import BroadcastReceiver
import sys
from kivyblocks.baseWidget import VBox
BluetoothManager = autoclass('android.bluetooth.BluetoothManager')
BluetoothAdapter = autoclass('android.bluetooth.BluetoothAdapter')
BluetoothDevice = autoclass('android.bluetooth.BluetoothDevice')
class BluetoothFinder(VBox):
data = ListProperty([])
def __init__(self, **kw):
super().__init__(**kw)
arg = context.getSystemService(context.BLUETOOTH_SERVICE)
self.bt_manager = BluetoothManager(arg)
self.bt_adapter = self.bt_manager.getAdaper()
self.unpairedBT()
def get_paired_bt(self):
return self.bt_adapter.getBondedDevice()
def __del__(self):
self.adapter.cancelDiscovery()
def unpairedBT(self):
self.adapter = BluetoothAdapter.getDefaultAdapter()
# Search foir unpaired devices
print("Unpaired devices")
self.data=[{"text": "Unpaired Devices"}]
myReceiver = BroadcastReceiver(self.onReceive, actions = [BluetoothDevice.ACTION_FOUND, BluetoothAdapter.ACTION_DISCOVERY_STARTED, BluetoothAdapter.ACTION_DISCOVERY_FINISHED])
myReceiver.start()
self.adapter.startDiscovery()
# Called by Broadcastreceiver
def onReceive(self, context, intent):
print(f"*BT* On receive context{context}", flush = True)
print(f"*BT* On receive intent {intent}", flush = True)
sys.stdout.flush()
self.myData.append({"text": f"Context {context}, intent {intent}"})
self.layout.data = [item for item in self.myData]

View File

@ -67,7 +67,7 @@ from .widgetExt.inputext import FloatInput,IntegerInput, \
StrInput,SelectInput, BoolInput, Password StrInput,SelectInput, BoolInput, Password
from .widgetExt.messager import Messager from .widgetExt.messager import Messager
from .bgcolorbehavior import BGColorBehavior from .bgcolorbehavior import BGColorBehavior
from .utils import NeedLogin, InsufficientPrivilege, HTTPError from .utils import NeedLogin, InsufficientPrivilege, HTTPError, blockImage
from .login import LoginForm from .login import LoginForm
from .tab import TabsPanel from .tab import TabsPanel
from .threadcall import HttpClient from .threadcall import HttpClient
@ -76,6 +76,7 @@ from .widget_css import WidgetCSS
from .ready import WidgetReady from .ready import WidgetReady
from .utils import CSize, SUPER from .utils import CSize, SUPER
from .swipebehavior import SwipeBehavior from .swipebehavior import SwipeBehavior
from .widgetExt.inputext import MyDropDown
if platform == 'android': if platform == 'android':
from .widgetExt.phonebutton import PhoneButton from .widgetExt.phonebutton import PhoneButton
@ -171,7 +172,6 @@ class Text(Label):
SUPER(Text, self, kwargs) SUPER(Text, self, kwargs)
if self._i18n: if self._i18n:
self.i18n = I18n()
self.i18n.addI18nWidget(self) self.i18n.addI18nWidget(self)
if self.wrap: if self.wrap:
self.size_hint_y = None self.size_hint_y = None
@ -220,7 +220,8 @@ class Text(Label):
self.lang = lang self.lang = lang
def on_lang(self,o,lang): def on_lang(self,o,lang):
self.text = self.i18n(self.otext) if self._i18n and self.otext:
self.text = self.i18n(self.otext)
class Title1(Text): class Title1(Text):
def __init__(self, **kw): def __init__(self, **kw):
@ -260,10 +261,11 @@ class Modal(VBox):
position = OptionProperty('cc',options=['tl', 'tc', 'tr', position = OptionProperty('cc',options=['tl', 'tc', 'tr',
'cl', 'cc', 'cr', 'cl', 'cc', 'cr',
'bl', 'bc', 'br']) 'bl', 'bc', 'br'])
def __init__(self, **kw): def __init__(self, **kw):
self._target = None self._target = None
SUPER(Modal, self, kw) super(Modal, self).__init__(**kw)
self.set_size_position()
self._target.bind(size=self.set_size_position)
self.register_event_type('on_open') self.register_event_type('on_open')
self.register_event_type('on_pre_open') self.register_event_type('on_pre_open')
self.register_event_type('on_pre_dismiss') self.register_event_type('on_pre_dismiss')
@ -285,7 +287,16 @@ class Modal(VBox):
return super().on_touch_down(touch) return super().on_touch_down(touch)
def set_modal_position(self): def on_target(self):
w = Window
if self.target is not None:
w = Factory.Blocks.getWidgetById(self.target)
if w is None:
w = Window
if w != self._target:
self._target = w
def set_target(self):
if self._target is None: if self._target is None:
if self.target is None: if self.target is None:
w = Window w = Window
@ -294,42 +305,56 @@ class Modal(VBox):
if w is None: if w is None:
w = Window w = Window
self._target = w self._target = w
def set_size_position(self, *args):
self.set_target()
if self.size_hint_x:
self.width = self.size_hint_x * self._target.width
if self.size_hint_y:
self.height = self.size_hint_y * self._target.height
print(self.width, self.height,
self.size_hint_x, self.size_hint_y,
self._target.size
)
self.set_modal_position()
def set_modal_position(self):
self.set_target()
xn = self.position[1] xn = self.position[1]
yn = self.position[0] yn = self.position[0]
x, y = 0, 0 x, y = 0, 0
if xn == 'c': if xn == 'c':
x = (w.width - self.width) / 2 x = (self._target.width - self.width) / 2
elif xn == 'r': elif xn == 'r':
x = w.width - self.width x = self._target.width - self.width
if x < 0: if x < 0:
x = 0 x = 0
if yn == 'c': if yn == 'c':
y = (w.height - self.height) / 2 y = (self._target.height - self.height) / 2
elif yn == 't': elif yn == 't':
y = w.height - self.height y = self._target.height - self.height
if y < 0: if y < 0:
y = 0 y = 0
if w == Window: if self._target == Window:
self.pos = x, y self.pos = x, y
else: else:
self.pos = w.pos[0] + x, w.pos[1] + y self.pos = self._target.pos[0] + x, self._target.pos[1] + y
def open(self, widget=None): def open(self):
if self.parent: if self.parent:
return self.parent.remove_widget(self)
self.dispatch('on_pre_open') self.dispatch('on_pre_open')
self.set_modal_position()
Window.add_widget(self) Window.add_widget(self)
self.dispatch('on_open') self.dispatch('on_open')
if self._target != Window: if self._target != Window:
self._target.disable() self._target.disabled = True
def dismiss(self, *args): def dismiss(self, *args):
self.dispatch('on_pre_dismiss') self.dispatch('on_pre_dismiss')
self.dispatch('on_dismiss') self.dispatch('on_dismiss')
Window.remove_widget(self) Window.remove_widget(self)
if self._target != Window: if self._target != Window:
self._Target.enable() self._target.enabled = False
def on_open(self, *args): def on_open(self, *args):
pass pass
@ -369,6 +394,32 @@ class TimedModal(Modal):
self.time_task = None self.time_task = None
super().dismiss() super().dismiss()
class Running(AsyncImage):
def __init__(self, widget, **kw):
super().__init__(**kw)
self.host_widget = widget
self.source = blockImage('running.gif')
self.host_widget.bind(size=self.set_size)
self.set_size()
self.open()
def open(self):
if self.parent:
self.parent.remove_widget(self)
Window.add_widget(self)
self.host_widget.disabled = True
def dismiss(self):
if self.parent:
self.parent.remove_widget(self)
self.host_widget.disabled = False
def set_size(self, *args):
self.size_hint = (None, None)
self.width = CSize(2)
self.height = CSize(2)
self.center = self.host_widget.center
class PressableImage(ButtonBehavior,AsyncImage): class PressableImage(ButtonBehavior,AsyncImage):
def on_press(self): def on_press(self):
pass pass
@ -377,6 +428,10 @@ class PressableLabel(ButtonBehavior, Text):
def on_press(self): def on_press(self):
pass pass
class PressableText(ButtonBehavior, Text):
def on_press(self):
pass
class FILEDataHandler(EventDispatcher): class FILEDataHandler(EventDispatcher):
def __init__(self, url, suffixs=[],params={}): def __init__(self, url, suffixs=[],params={}):
self.url = url self.url = url
@ -577,3 +632,28 @@ class Slider(Carousel):
w = bk.widgetBuild(desc) w = bk.widgetBuild(desc)
self.add_widget(w) self.add_widget(w)
i18n = I18n()
class I18nWidget(PressableText):
lang = StringProperty(None)
def __init__(self, **kw):
super().__init__(**kw)
self.lang = i18n.lang
def on_lang(self, *args):
self.otext = self.lang
def on_press(self, *args):
langs = i18n.get_languages()
data = [ {'lang':l} for l in langs ]
mdd = MyDropDown(textField='lang', valueField='lang',
value=self.lang,
data=data)
mdd.bind(on_select=self.selected_lang)
mdd.showme(self)
def selected_lang(self, o, v):
lang = v[0]
self.lang = lang
i18n.changeLang(self.lang)

View File

@ -15,7 +15,6 @@ def get_cmd_desc(cmd_desc):
desc['datamethod'] = v['datamethod'] desc['datamethod'] = v['datamethod']
keys = v.keys() keys = v.keys()
if 'url' in keys: if 'url' in keys:
Logger.info('get_cmd_desc():cmd_desc=%s', cmd_desc)
desc['actiontype'] = 'urlwidget' desc['actiontype'] = 'urlwidget'
desc['mode'] = 'replace' desc['mode'] = 'replace'
options = { options = {
@ -24,18 +23,22 @@ def get_cmd_desc(cmd_desc):
} }
desc['options'] = options desc['options'] = options
return desc return desc
if 'rfname' in keys: if 'rfname' in keys:
desc['actiontype'] = 'registedfunction' desc['actiontype'] = 'registedfunction'
desc['params'] = v.get('params',{}) desc['params'] = v.get('params',{})
return desc return desc
if 'script' in keys: if 'script' in keys:
desc['actiontype'] = 'script' desc['actiontype'] = 'script'
desc['script'] = v.get('script') desc['script'] = v.get('script')
return desc return desc
if 'method' in keys: if 'method' in keys:
desc['actiontype'] = 'method' desc['actiontype'] = 'method'
desc['method'] = v.get('method') desc['method'] = v.get('method')
return desc return desc
if 'actions' in keys: if 'actions' in keys:
desc['actiontype'] = 'multiple' desc['actiontype'] = 'multiple'
desc['actions'] = v.get('actions') desc['actions'] = v.get('actions')
@ -61,6 +64,6 @@ def cmd_action(cmd_desc, widget):
}) })
w.bind(on_conform=partial(blocks.uniaction, widget, desc)) w.bind(on_conform=partial(blocks.uniaction, widget, desc))
w.open() w.open()
Logger.info('cmd_action():desc=%s, conform and action', desc) print('cmd_action():desc=', desc, ' conform and action', desc)

View File

@ -25,7 +25,7 @@ from appPublic.uniqueID import getID
from appPublic.myTE import string_template_render from appPublic.myTE import string_template_render
from .utils import * from .utils import *
from .baseWidget import Text, HBox, VBox from .baseWidget import Text, HBox, VBox, Running
from .scrollpanel import ScrollPanel from .scrollpanel import ScrollPanel
from .paging import Paging, RelatedLoader from .paging import Paging, RelatedLoader
from .ready import WidgetReady from .ready import WidgetReady
@ -64,7 +64,7 @@ class Cell(ButtonBehavior, WidgetCSS, BoxLayout):
if self.row.header: if self.row.header:
self.csscls=self.row.part.datagrid.header_css self.csscls=self.row.part.datagrid.header_css
if desc['header']: if desc['header']:
bl = Text(i18n=True, text=str(desc['value']), bl = Text(i18n=True, otext=str(desc['value']),
font_size=CSize(1),wrap=True, font_size=CSize(1),wrap=True,
halign='left', valign='middle' halign='left', valign='middle'
) )
@ -432,7 +432,7 @@ class DataGrid(VBox):
desc = { desc = {
"widgettype":"Text", "widgettype":"Text",
"options":{ "options":{
"text":n, "otext":n,
"i18n":True, "i18n":True,
} }
} }

View File

@ -14,6 +14,9 @@ class I18n:
def __init__(self): def __init__(self):
self.kvlang={} self.kvlang={}
self.lang = locale.getdefaultlocale()[0] self.lang = locale.getdefaultlocale()[0]
if self.lang is None:
self.lang = 'en_US'
self.languages = None
self.loadI18n(self.lang) self.loadI18n(self.lang)
self.i18nWidgets = [] self.i18nWidgets = []
@ -21,8 +24,9 @@ class I18n:
self.i18nWidgets.append(ref(w)) self.i18nWidgets.append(ref(w))
def loadI18nFromI18nFolder(self, lang): def loadI18nFromI18nFolder(self, lang):
config = gtConfig() config = getConfig()
fpath = os.path.join(config.i18n_folder,lang,'msg.txt') fpath = os.path.join(config.i18n_folder,lang,'msg.txt')
print('fpath=', fpath, type(fpath))
with codecs.open(fpath,'r','utf-8') as f: with codecs.open(fpath,'r','utf-8') as f:
line = f.readline() line = f.readline()
d = {} d = {}
@ -32,15 +36,39 @@ class I18n:
continue continue
k,v = line.split(':',1) k,v = line.split(':',1)
d.update({k:v}) d.update({k:v})
line = readline() line = f.readline()
return d return d
def get_languages(self):
if self.languages:
return self.languages
self.languages = self.getLanguages()
return self.languages
def getLanguages(self):
config = getConfig()
if config.i18n_folder:
langs = []
for f in os.listdir(config.i18n_folder):
p = os.path.join(config.i18n_folder, f)
if os.path.isdir(p):
langs.append(os.path.basename(f))
return langs
if config.i18n_url:
url = '%s%s' % (config.uihome, config.i18n_url)
hc = HttpClient()
d = hc.get(url)
if isinstance(d, list):
return d
return []
def loadI18n(self,lang): def loadI18n(self,lang):
app = App.get_running_app() app = App.get_running_app()
config = getConfig() config = getConfig()
self.kvlang[lang] = {} self.kvlang[lang] = {}
if config.i18n_folder: if config.i18n_folder:
self.kvlang[lang] = self.loadI18nFromFolder(lang) self.kvlang[lang] = self.loadI18nFromI18nFolder(lang)
return return
if config.i18n_url: if config.i18n_url:
@ -63,8 +91,8 @@ class I18n:
if not d: if not d:
self.loadI18n(lang) self.loadI18n(lang)
self.lang = lang self.lang = lang
ws = [ w for w in self.i18nWidgets if w is not None ] ws = [ w for w in self.i18nWidgets if w() is not None ]
for w in ws:
w().changeLang(lang)
self.i18nWidgets = ws self.i18nWidgets = ws
for w in self.i18nWidgets:
w.changeLang(lang)

View File

@ -5,7 +5,7 @@ from kivy.app import App
from kivy.clock import Clock from kivy.clock import Clock
from kivy.factory import Factory from kivy.factory import Factory
from kivy.utils import platform from kivy.utils import platform
from .baseWidget import VBox, HBox from .baseWidget import VBox, HBox, I18nWidget
from .toggleitems import PressableBox from .toggleitems import PressableBox
from .utils import * from .utils import *
from .swipebehavior import SwipeBehavior from .swipebehavior import SwipeBehavior
@ -61,6 +61,7 @@ PagePanel description file format
"bar_autohide": true when page is idle "bar_autohide": true when page is idle
"bar_size": bar size in CSize unit "bar_size": bar size in CSize unit
"bar_at": "top" or "bottom" "bar_at": "top" or "bottom"
"i18n": true of false
"bar_css": "bar_css":
"panel_css": "panel_css":
"left_menu": if defined, it must be a widget instance or a dict "left_menu": if defined, it must be a widget instance or a dict
@ -136,6 +137,7 @@ sub-widget's description file format
""" """
def __init__(self, bar_size=2, def __init__(self, bar_size=2,
bar_css='default', bar_css='default',
i18n=False,
csscls='default', csscls='default',
singlepage=False, singlepage=False,
fixed_before=None, fixed_before=None,
@ -147,6 +149,7 @@ sub-widget's description file format
self.bar_size = bar_size self.bar_size = bar_size
self.bar_autohide = bar_autohide self.bar_autohide = bar_autohide
self.bar_at = bar_at self.bar_at = bar_at
self.i18n = i18n
self.singlepage = singlepage self.singlepage = singlepage
self.idle_status = False self.idle_status = False
self.idle_threshold = 10 self.idle_threshold = 10
@ -218,6 +221,10 @@ sub-widget's description file format
}) })
self.bar.add_widget(self.bar_left_menu) self.bar.add_widget(self.bar_left_menu)
self.bar_left_menu.bind(on_press=self.show_left_menu) self.bar_left_menu.bind(on_press=self.show_left_menu)
if self.i18n:
self.i18n_w = I18nWidget(size_hint_x=None, width=CSize(5))
self.bar.add_widget(self.i18n_w)
self.bar_title = HBox(csscls=bar_css) self.bar_title = HBox(csscls=bar_css)
self.bar.add_widget(self.bar_title) self.bar.add_widget(self.bar_title)
self.bar_right_menu = VBox(size_hint=(None,None),size=CSize(bcsize,bcsize)) self.bar_right_menu = VBox(size_hint=(None,None),size=CSize(bcsize,bcsize))

View File

@ -7,6 +7,7 @@ from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button from kivy.uix.button import Button
from kivy.clock import Clock from kivy.clock import Clock
from kivy.app import App from kivy.app import App
from kivy.properties import BooleanProperty
from functools import partial from functools import partial
from appPublic.dictObject import DictObject from appPublic.dictObject import DictObject
from appPublic.jsonConfig import getConfig from appPublic.jsonConfig import getConfig
@ -40,8 +41,8 @@ it fires two type of event
""" """
class PageLoader(EventDispatcher): class PageLoader(EventDispatcher):
loading = BooleanProperty(False)
def __init__(self,target=None, **options): def __init__(self,target=None, **options):
self.loading = False
self.target = target self.target = target
self.options = options self.options = options
self.filter = None self.filter = None
@ -72,6 +73,12 @@ class PageLoader(EventDispatcher):
self.loader.bind(on_success=self.show_page) self.loader.bind(on_success=self.show_page)
self.loader.bind(on_error=self.onerror) self.loader.bind(on_error=self.onerror)
def on_loading(self, *args):
if self.loading:
self.running = Running(self.target)
else:
self.running.dismiss()
def on_newbegin(self): def on_newbegin(self):
pass pass

View File

@ -1 +1 @@
__version__ = '0.3.23' __version__ = '0.3.24'