Add on-screen keyboard for feedback dialog
This commit is contained in:
parent
0767b81d0b
commit
78e6704639
153
wuttapos/controls/feedback.py
Normal file
153
wuttapos/controls/feedback.py
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# WuttaPOS -- Pythonic Point of Sale System
|
||||||
|
# Copyright © 2023 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of WuttaPOS.
|
||||||
|
#
|
||||||
|
# WuttaPOS is free software: you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# WuttaPOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# WuttaPOS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
WuttaPOS - feedback control
|
||||||
|
"""
|
||||||
|
|
||||||
|
import flet as ft
|
||||||
|
|
||||||
|
from .base import WuttaControl
|
||||||
|
from .keyboard import WuttaKeyboard
|
||||||
|
|
||||||
|
|
||||||
|
class WuttaFeedback(WuttaControl):
|
||||||
|
|
||||||
|
default_font_size = 20
|
||||||
|
default_button_height = 60
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.on_send = kwargs.pop('on_send', None)
|
||||||
|
self.on_cancel = kwargs.pop('on_cancel', None)
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
|
||||||
|
self.button = ft.Container(content=ft.Text("Feedback", size=self.default_font_size,
|
||||||
|
weight=ft.FontWeight.BOLD),
|
||||||
|
height=self.default_button_height,
|
||||||
|
width=self.default_button_height * 3,
|
||||||
|
on_click=self.initial_click,
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
border=ft.border.all(1, 'black'),
|
||||||
|
border_radius=ft.border_radius.all(5),
|
||||||
|
bgcolor='blue')
|
||||||
|
|
||||||
|
return self.button
|
||||||
|
|
||||||
|
def initial_click(self, e):
|
||||||
|
|
||||||
|
self.message = ft.TextField(label="Message",
|
||||||
|
multiline=True, min_lines=5,
|
||||||
|
autofocus=True)
|
||||||
|
|
||||||
|
self.dlg = ft.AlertDialog(
|
||||||
|
modal=True,
|
||||||
|
title=ft.Text("User Feedback"),
|
||||||
|
content=ft.Container(
|
||||||
|
content=ft.Column(
|
||||||
|
[
|
||||||
|
ft.Text("Questions, suggestions, comments, complaints, etc. "
|
||||||
|
"are welcome and may be submitted below. "),
|
||||||
|
ft.Divider(),
|
||||||
|
self.message,
|
||||||
|
ft.Divider(),
|
||||||
|
WuttaKeyboard(self.config, on_keypress=self.keypress),
|
||||||
|
],
|
||||||
|
expand=True,
|
||||||
|
),
|
||||||
|
height=800,
|
||||||
|
),
|
||||||
|
actions=[
|
||||||
|
ft.Row(
|
||||||
|
[
|
||||||
|
ft.Container(content=ft.Text("Send Message",
|
||||||
|
size=self.default_font_size,
|
||||||
|
color='black',
|
||||||
|
weight=ft.FontWeight.BOLD),
|
||||||
|
height=self.default_button_height,
|
||||||
|
width=self.default_button_height * 3,
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
bgcolor='blue',
|
||||||
|
border=ft.border.all(1, 'black'),
|
||||||
|
border_radius=ft.border_radius.all(5),
|
||||||
|
on_click=self.send_feedback),
|
||||||
|
ft.Container(content=ft.Text("Cancel",
|
||||||
|
size=self.default_font_size,
|
||||||
|
weight=ft.FontWeight.BOLD),
|
||||||
|
height=self.default_button_height,
|
||||||
|
width=self.default_button_height * 2.5,
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
border=ft.border.all(1, 'black'),
|
||||||
|
border_radius=ft.border_radius.all(5),
|
||||||
|
on_click=self.cancel),
|
||||||
|
],
|
||||||
|
alignment=ft.MainAxisAlignment.CENTER,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
self.page.dialog = self.dlg
|
||||||
|
self.dlg.open = True
|
||||||
|
self.page.update()
|
||||||
|
|
||||||
|
def keypress(self, key):
|
||||||
|
if key == '⏎':
|
||||||
|
self.message.value += '\n'
|
||||||
|
elif key == '⌫':
|
||||||
|
self.message.value = self.message.value[:-1]
|
||||||
|
else:
|
||||||
|
self.message.value += key
|
||||||
|
|
||||||
|
self.message.focus()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def cancel(self, e):
|
||||||
|
self.dlg.open = False
|
||||||
|
self.page.update()
|
||||||
|
|
||||||
|
if self.on_cancel:
|
||||||
|
self.on_cancel(e)
|
||||||
|
|
||||||
|
def send_feedback(self, e):
|
||||||
|
if self.message.value:
|
||||||
|
|
||||||
|
self.app.send_email('pos_feedback', data={
|
||||||
|
'user_name': self.page.session.get('user_display'),
|
||||||
|
'message': self.message.value,
|
||||||
|
})
|
||||||
|
|
||||||
|
self.dlg.open = False
|
||||||
|
self.page.snack_bar = ft.SnackBar(ft.Text(f"MESSAGE WAS SENT",
|
||||||
|
color='black',
|
||||||
|
weight=ft.FontWeight.BOLD),
|
||||||
|
bgcolor='green',
|
||||||
|
duration=1500)
|
||||||
|
self.page.snack_bar.open = True
|
||||||
|
self.page.update()
|
||||||
|
|
||||||
|
if self.on_send:
|
||||||
|
self.on_send()
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.message.focus()
|
||||||
|
self.page.update()
|
|
@ -32,6 +32,7 @@ import flet as ft
|
||||||
|
|
||||||
from .base import WuttaView
|
from .base import WuttaView
|
||||||
from wuttapos.controls.custlookup import WuttaCustomerLookup
|
from wuttapos.controls.custlookup import WuttaCustomerLookup
|
||||||
|
from wuttapos.controls.feedback import WuttaFeedback
|
||||||
from wuttapos.util import get_pos_batch_handler
|
from wuttapos.util import get_pos_batch_handler
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,6 +67,22 @@ class POSView(WuttaView):
|
||||||
def get_batch_handler(self):
|
def get_batch_handler(self):
|
||||||
return get_pos_batch_handler(self.config)
|
return get_pos_batch_handler(self.config)
|
||||||
|
|
||||||
|
def reset(self, e=None, update=True):
|
||||||
|
"""
|
||||||
|
This is a convenience method, meant only to clear the main
|
||||||
|
input and set focus to it. Will also update() the page
|
||||||
|
by default.
|
||||||
|
|
||||||
|
The ``e`` arg is ignored and accepted only so this method may
|
||||||
|
be registered as an event handler, e.g. ``on_cancel``.
|
||||||
|
"""
|
||||||
|
self.set_quantity.data = None
|
||||||
|
self.set_quantity.value = None
|
||||||
|
self.main_input.value = ''
|
||||||
|
self.main_input.focus()
|
||||||
|
if update:
|
||||||
|
self.page.update()
|
||||||
|
|
||||||
def set_customer(self, customer, batch=None):
|
def set_customer(self, customer, batch=None):
|
||||||
session = self.app.get_session(customer)
|
session = self.app.get_session(customer)
|
||||||
if not batch:
|
if not batch:
|
||||||
|
@ -96,13 +113,11 @@ class POSView(WuttaView):
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
dlg.open = False
|
dlg.open = False
|
||||||
self.main_input.focus()
|
self.reset()
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
def cancel(e):
|
def cancel(e):
|
||||||
dlg.open = False
|
dlg.open = False
|
||||||
self.main_input.focus()
|
self.reset()
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
dlg = ft.AlertDialog(
|
dlg = ft.AlertDialog(
|
||||||
modal=True,
|
modal=True,
|
||||||
|
@ -144,9 +159,7 @@ class POSView(WuttaView):
|
||||||
|
|
||||||
def close(e):
|
def close(e):
|
||||||
dlg.open = False
|
dlg.open = False
|
||||||
self.main_input.value = ''
|
self.reset()
|
||||||
self.main_input.focus()
|
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
font_size = self.default_font_size * 0.8
|
font_size = self.default_font_size * 0.8
|
||||||
dlg = ft.AlertDialog(
|
dlg = ft.AlertDialog(
|
||||||
|
@ -219,9 +232,7 @@ class POSView(WuttaView):
|
||||||
|
|
||||||
def cancel(e):
|
def cancel(e):
|
||||||
dlg.open = False
|
dlg.open = False
|
||||||
self.main_input.value = ''
|
self.reset()
|
||||||
self.main_input.focus()
|
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
font_size = self.default_font_size * 0.8
|
font_size = self.default_font_size * 0.8
|
||||||
dlg = ft.AlertDialog(
|
dlg = ft.AlertDialog(
|
||||||
|
@ -291,21 +302,17 @@ class POSView(WuttaView):
|
||||||
self.informed_refresh()
|
self.informed_refresh()
|
||||||
|
|
||||||
dlg.open = False
|
dlg.open = False
|
||||||
self.main_input.value = ''
|
|
||||||
self.main_input.focus()
|
|
||||||
self.page.snack_bar = ft.SnackBar(ft.Text("CUSTOMER REMOVED",
|
self.page.snack_bar = ft.SnackBar(ft.Text("CUSTOMER REMOVED",
|
||||||
color='black',
|
color='black',
|
||||||
weight=ft.FontWeight.BOLD),
|
weight=ft.FontWeight.BOLD),
|
||||||
bgcolor='yellow',
|
bgcolor='yellow',
|
||||||
duration=1500)
|
duration=1500)
|
||||||
self.page.snack_bar.open = True
|
self.page.snack_bar.open = True
|
||||||
self.page.update()
|
self.reset()
|
||||||
|
|
||||||
def cancel(e):
|
def cancel(e):
|
||||||
dlg.open = False
|
dlg.open = False
|
||||||
self.main_input.value = ''
|
self.reset()
|
||||||
self.main_input.focus()
|
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
font_size = self.default_font_size * 0.8
|
font_size = self.default_font_size * 0.8
|
||||||
dlg = ft.AlertDialog(
|
dlg = ft.AlertDialog(
|
||||||
|
@ -344,9 +351,7 @@ class POSView(WuttaView):
|
||||||
if customer:
|
if customer:
|
||||||
|
|
||||||
self.set_customer(customer)
|
self.set_customer(customer)
|
||||||
self.main_input.value = ''
|
self.reset()
|
||||||
self.main_input.focus()
|
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
else: # customer not found
|
else: # customer not found
|
||||||
self.page.snack_bar = ft.SnackBar(ft.Text(f"CUSTOMER NOT FOUND: {entry}",
|
self.page.snack_bar = ft.SnackBar(ft.Text(f"CUSTOMER NOT FOUND: {entry}",
|
||||||
|
@ -355,6 +360,7 @@ class POSView(WuttaView):
|
||||||
bgcolor='yellow',
|
bgcolor='yellow',
|
||||||
duration=1500)
|
duration=1500)
|
||||||
self.page.snack_bar.open = True
|
self.page.snack_bar.open = True
|
||||||
|
# TODO: should use reset() here?
|
||||||
self.main_input.focus()
|
self.main_input.focus()
|
||||||
self.page.update()
|
self.page.update()
|
||||||
|
|
||||||
|
@ -403,91 +409,6 @@ class POSView(WuttaView):
|
||||||
expand=1,
|
expand=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
def feedback_click(e):
|
|
||||||
|
|
||||||
message = ft.TextField(label="Message",
|
|
||||||
multiline=True, min_lines=5,
|
|
||||||
autofocus=True)
|
|
||||||
|
|
||||||
def send_feedback(e):
|
|
||||||
|
|
||||||
if message.value:
|
|
||||||
|
|
||||||
self.app.send_email('pos_feedback', data={
|
|
||||||
'user_name': self.page.session.get('user_display'),
|
|
||||||
'message': message.value,
|
|
||||||
})
|
|
||||||
|
|
||||||
dlg.open = False
|
|
||||||
|
|
||||||
self.page.snack_bar = ft.SnackBar(ft.Text(f"MESSAGE WAS SENT",
|
|
||||||
color='black',
|
|
||||||
weight=ft.FontWeight.BOLD),
|
|
||||||
bgcolor='green',
|
|
||||||
duration=1500)
|
|
||||||
self.page.snack_bar.open = True
|
|
||||||
|
|
||||||
self.main_input.focus()
|
|
||||||
|
|
||||||
else:
|
|
||||||
message.focus()
|
|
||||||
|
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
def cancel(e):
|
|
||||||
dlg.open = False
|
|
||||||
self.main_input.focus()
|
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
button_height = self.default_button_size * 0.8
|
|
||||||
dlg = ft.AlertDialog(
|
|
||||||
modal=True,
|
|
||||||
title=ft.Text("User Feedback"),
|
|
||||||
content=ft.Container(
|
|
||||||
content=ft.Column(
|
|
||||||
[
|
|
||||||
ft.Text("Questions, suggestions, comments, complaints, etc. "
|
|
||||||
"are welcome and may be submitted below. "),
|
|
||||||
ft.Divider(),
|
|
||||||
message,
|
|
||||||
],
|
|
||||||
expand=True,
|
|
||||||
),
|
|
||||||
height=500,
|
|
||||||
),
|
|
||||||
actions=[
|
|
||||||
ft.Row(
|
|
||||||
[
|
|
||||||
ft.Container(content=ft.Text("Send Message",
|
|
||||||
size=self.default_font_size,
|
|
||||||
color='black',
|
|
||||||
weight=ft.FontWeight.BOLD),
|
|
||||||
height=button_height,
|
|
||||||
width=self.default_button_size * 3,
|
|
||||||
alignment=ft.alignment.center,
|
|
||||||
bgcolor='blue',
|
|
||||||
border=ft.border.all(1, 'black'),
|
|
||||||
border_radius=ft.border_radius.all(5),
|
|
||||||
on_click=send_feedback),
|
|
||||||
ft.Container(content=ft.Text("Cancel",
|
|
||||||
size=self.default_font_size,
|
|
||||||
weight=ft.FontWeight.BOLD),
|
|
||||||
height=button_height,
|
|
||||||
width=self.default_button_size * 2.5,
|
|
||||||
alignment=ft.alignment.center,
|
|
||||||
border=ft.border.all(1, 'black'),
|
|
||||||
border_radius=ft.border_radius.all(5),
|
|
||||||
on_click=cancel),
|
|
||||||
],
|
|
||||||
alignment=ft.MainAxisAlignment.CENTER,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.page.dialog = dlg
|
|
||||||
dlg.open = True
|
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
def tenkey_click(e):
|
def tenkey_click(e):
|
||||||
value = e.control.content.value
|
value = e.control.content.value
|
||||||
|
|
||||||
|
@ -720,8 +641,7 @@ class POSView(WuttaView):
|
||||||
|
|
||||||
ft.Row(
|
ft.Row(
|
||||||
[
|
[
|
||||||
tenkey_button("Feedback", height=70, width=200,
|
WuttaFeedback(self.config, on_send=self.reset, on_cancel=self.reset),
|
||||||
bgcolor='blue', on_click=feedback_click),
|
|
||||||
ft.Row(
|
ft.Row(
|
||||||
[
|
[
|
||||||
self.set_quantity,
|
self.set_quantity,
|
||||||
|
@ -848,14 +768,11 @@ class POSView(WuttaView):
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
self.clear_all()
|
self.clear_all()
|
||||||
self.main_input.value = ''
|
self.reset()
|
||||||
self.main_input.focus()
|
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
def cancel(e):
|
def cancel(e):
|
||||||
dlg.open = False
|
dlg.open = False
|
||||||
self.main_input.focus()
|
self.reset()
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
session = self.app.make_session()
|
session = self.app.make_session()
|
||||||
batch = self.get_current_batch(session, create=False)
|
batch = self.get_current_batch(session, create=False)
|
||||||
|
@ -924,8 +841,7 @@ class POSView(WuttaView):
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
self.clear_all()
|
self.clear_all()
|
||||||
self.main_input.focus()
|
self.reset()
|
||||||
self.page.update()
|
|
||||||
|
|
||||||
def clear_all(self):
|
def clear_all(self):
|
||||||
self.items.controls.clear()
|
self.items.controls.clear()
|
||||||
|
@ -972,9 +888,4 @@ class POSView(WuttaView):
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
session.close()
|
session.close()
|
||||||
|
self.reset()
|
||||||
self.main_input.value = ""
|
|
||||||
self.main_input.focus()
|
|
||||||
self.set_quantity.data = None
|
|
||||||
self.set_quantity.value = None
|
|
||||||
self.page.update()
|
|
||||||
|
|
Loading…
Reference in a new issue