How to edit Inline keyboard after click? - telegram-bot

I use botman
Need to change the keyboard after clicking.
An example of implementation is in #shopbot (Telegram) after entering the command /invoice
How I tried to do:
$keyboard = Keyboard::create()->type( Keyboard::TYPE_INLINE )
->oneTimeKeyboard(false)
->addRow( KeyboardButton::create("My inline button")->callbackData('first_inline'),
KeyboardButton::create("My inline button2")->callbackData('second_inline'))
->toArray();
$changedKb = Keyboard::create()->type( Keyboard::TYPE_INLINE )
->oneTimeKeyboard(false)
->addRow( KeyboardButton::create("Changed")->callbackData('first_inline'),
KeyboardButton::create("Changed2")->callbackData('second_inline'))
->toArray();
return $this->ask('Test to inline', function (Answer $answer) use ($changedKb) {
$this->bot->sendRequest('editMessageReplyMarkup',
[
'message_id' => $answer->getMessage()->getPayload()['message_id']
] + $changedKb, $answer->getMessage());
}, $keyboard);
Using editMessageReplyMarkup, I did not succeed, after clicking on the button, the text changes, but the button disappears immediately
Maybe someone has a solution, not necessarily made through a botman

There is a method on TelegramDriver class, that removes the keyboard, you can change it
/**
* This hide the inline keyboard, if is an interactive message.
*/
public function messagesHandled()
{
$callback = $this->payload->get('callback_query');
$hideInlineKeyboard = $this->config->get('hideInlineKeyboard', true);
if ($callback !== null) {
$callback['message']['chat']['id'];
$this->removeInlineKeyboard($callback['message']['chat']['id'],
$callback['message']['message_id']);
}
}

Related

Optimise Kotlin code for button clicked state

I want to change the button background when the button clicked, the function is work by using this code
bank1.setOnClickListener {
bank1.setBackgroundResource(R.drawable.selected_btn_border_blue_bg);
bank2.setBackgroundResource(R.drawable.default_option_border_bg);
bank3.setBackgroundResource(R.drawable.default_option_border_bg);
bank4.setBackgroundResource(R.drawable.default_option_border_bg);
}
bank2.setOnClickListener {
bank2.setBackgroundResource(R.drawable.selected_btn_border_blue_bg);
bank1.setBackgroundResource(R.drawable.default_option_border_bg);
bank3.setBackgroundResource(R.drawable.default_option_border_bg);
bank4.setBackgroundResource(R.drawable.default_option_border_bg);
}
bank3.setOnClickListener {
bank3.setBackgroundResource(R.drawable.selected_btn_border_blue_bg);
bank2.setBackgroundResource(R.drawable.default_option_border_bg);
bank1.setBackgroundResource(R.drawable.default_option_border_bg);
bank4.setBackgroundResource(R.drawable.default_option_border_bg);
}
bank4.setOnClickListener {
bank4.setBackgroundResource(R.drawable.selected_btn_border_blue_bg);
bank2.setBackgroundResource(R.drawable.default_option_border_bg);
bank3.setBackgroundResource(R.drawable.default_option_border_bg);
bank1.setBackgroundResource(R.drawable.default_option_border_bg);
}
But it kinda hardcoded, and make it to so many lines, any way to make the code shorter?
I would keep a variable that keeps track of the selected one like
private var selectedBank: View? = null
And then do
arrayOf(bank1, bank2, bank3, bank4).forEach {
it.setOnClickListener {
selectedBank?.setBackgroundResource(R.drawable.default_option_border_bg)
selectedBank = it
it.setBackgroundResource(R.drawable.selected_btn_border_blue_bg)
}
}
you only need to deselected the previous selected one

How to trigger PC Keyboard inputs in Kotlin Desktop Compose

I am going to develop a POS system using Kotlin Jetpack Compose and I wanna know how to trigger keyboard input events inside my project.
In Compose Desktop You can listen for key events using onKeyEvent Window parameter:
Window(
onCloseRequest = ::exitApplication,
visible = visible,
onKeyEvent = {
if (it.isCtrlPressed && it.key == Key.A) {
println("Ctrl + A is pressed")
true
} else {
// let other handlers receive this event
false
}
}
) {
App()
}
An other options, which will also work for Compose in Android, is using Modifier.onKeyEvent. As documentation says:
will allow it to intercept hardware key events when it (or one of its children) is focused.
So you need to make an item or one of its children focusable and focused. Check out more about focus in compose in this article
To do this you need a FocusRequester, in my example I'm asking focus when view renders using LaunchedEffect.
For the future note, that if user taps on a text field, or an other focusable element will gain focus, your view will loose it. If this focused view is inside your view with onKeyEvent handler, it still gonna work.
An empty box cannot become focused, so you need to add some size with a modifier. It still will be invisible:
val requester = remember { FocusRequester() }
Box(
Modifier
.onKeyEvent {
if (it.isCtrlPressed && it.key == Key.A) {
println("Ctrl + A is pressed")
true
} else {
// let other handlers receive this event
false
}
}
.focusRequester(requester)
.focusable()
.size(10.dp)
)
LaunchedEffect(Unit) {
requester.requestFocus()
}
Alternatively just add content to Box so it will stretch and .size modifier won't be needed anymore
Following the second option of the Philip answer is possible to get a strange behavior when you set the focus and, for some reason, click inside application window. Doing this, is possible "lost" the focus and the key events are not propper handled.
In order to avoid this the suggestion is manually handle this problem by adding a click/tap modifier, which just specifies that when detect a click/tap the requester requests the focus again. See below:
val requester = FocusRequester()
Box(
Modifier
//pointer input handles [onPress] to force focus to the [requester]
.pointerInput(key1 = true) {
detectTapGestures(onPress = {
requester.requestFocus()
})
}
.onKeyEvent {
if (it.isCtrlPressed && it.key == Key.A) {
println("Ctrl + A is pressed")
true
} else {
// let other handlers receive this event
false
}
}
.focusRequester(requester)
.focusable()
.fillMaxSize()
.background(Color.Cyan)
)
LaunchedEffect(Unit) {
requester.requestFocus()
}

How to prevent closing of cell edit mode on validation errors with custom vue components in ag-grid

I have succesfully rendered my own component as the cellEditor and would like and on-leave I would like it to try to validate the value and prevent the closing if it fails.
If I look at this then https://www.ag-grid.com/javascript-grid-cell-editing/#editing-api there's cancelable callback functions for editing. But in this callback function is there a way to access the current instantiated component? I would think that would be the easiest way to handle this.
I'm using vee-validate so the validation function is async, just to keep in mind.
Use Full row editing.
Create a global variable like
var problemRow = -1;
Then Subscribe to this events:
onRowEditingStarted: function (event) {
if (problemRow!=-1 && event.rowIndex!=problemRow) {
gridOptions.api.stopEditing();
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
},
onRowEditingStopped: function (event) {
if (problemRow==-1) {
if (event.data.firstName != "your validation") {
problemRow = event.rowIndex
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
}
if (problemRow == event.rowIndex) {
if (event.data.firstName != "your validation") {
problemRow = event.rowIndex
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
else{
problemRow=-1;
}
}
},
I had a similar issue - albeit in AngularJS and the non-Angular mode for ag-grid - I needed to prevent the navigation when the cell editor didn't pass validation.
The documentation is not very detailed, so in the end I added a custom cell editor with a form wrapped around the input field (to handle the niceties such as red highlighting etc), and then used Angular JS validation. That got me so far, but the crucial part was trying to prevent the user tabbing out or away when the value was invalid so the user could at least fix the issue.
I did this by adding a value parser when adding the cell, and then within that if the value was invalid according to various rules, throw an exception. Not ideal, I know - but it does prevent ag-grid from trying to move away from the cell.
I tried loads of approaches to solving this - using the tabToNextCell events, suppressKeyboardEvent, navigateToNextCell, onCellEditingStopped - to name a few - this was the only thing that got it working correctly.
Here's my value parser, for what it's worth:
var codeParser = function (args) {
var cellEditor = _controller.currentCellEditor.children['codeValue'];
var paycodeId = +args.colDef.field;
var paycodeInfo = _controller.paycodes.filter(function (f) { return f.id === paycodeId; })[0];
// Check against any mask
if (paycodeInfo && paycodeInfo.mask) {
var reg = new RegExp("^" + paycodeInfo.mask + '$');
var match = args.newValue.match(reg);
if (!match) {
$mdToast.show($mdToast.simple().textContent('Invalid value - does not match paycode format.').position('top right').toastClass('errorToast'))
.then(function(r) {
_controller.currentCellEditor.children['codeValue'].focus();
});
throw 'Invalid value - does not match paycode format.';
}
}
return true;
};
The _controller.currentCellEditor value is set during the init of the cell editor component. I do this so I can then refocus the control after the error has been shown in the toast:
CodeValueEditor.prototype.init = function (params) {
var form = document.createElement('form');
form.setAttribute('id', 'mainForm');
form.setAttribute('name', 'mainForm');
var input = document.createElement('input');
input.classList.add('ag-cell-edit-input');
input.classList.add('paycode-editor');
input.setAttribute('name', 'codeValue');
input.setAttribute('id', 'codeValue');
input.tabIndex = "0";
input.value = params.value;
if (params.mask) {
input.setAttribute('data-mask', params.mask);
input.setAttribute('ng-pattern','/^' + params.mask + '$/');
input.setAttribute('ng-class',"{'pattern-error': mainForm.codeValue.$error.pattern}");
input.setAttribute('ng-model', 'ctl.currentValue');
}
form.appendChild(input);
this.container = form;
$compile(this.container)($scope);
_controller.currentValue = null;
// This is crucial - we can then reference the container in
// the parser later on to refocus the control
_controller.currentCellEditor = this.container;
$scope.$digest();
};
And then cleared in the grid options onCellEditingStopped event:
onCellEditingStopped: function (event) {
$scope.$apply(function() {
_controller.currentCellEditor = null;
});
},
I realise it's not specifically for your components (Vue.js) but hopefully it'll help someone else. If anyone has done it a better way, I'm all ears as I don't like throwing the unnecessary exception!

Disable the escape key in dojo

I have a requirement to disable the escape key when the dialog is open.currently when i click the escape button the dialog closes and the transaction is submitting.I tried the following code snippet but its not working chrome.
dojo.connect(dialog, "onKeyPress", function(e){
var key = e.keyCode || e.charCode;
var k = dojo.keys;
if (key == k.ESCAPE) {
event.preventDefault();
d.stopEvent(event);
}
});
Could you please help on this..i have searched a lot and havent found a suitable solution for my problem.
Thanks inadvance..
Dojo uses the _onKey event for accessibility. You can override it by using:
dialog._onKey = function() { }
I wrote an example JSFiddle, hitting the Escape key should not work anymore.
In the event you want to override the escape key in all dialogs (rather than a particular instance), you can use dojo/aspect:
require(['dojo/aspect', 'dijit/Dialog'], function (Aspect, Dialog) {
Aspect.around(Dialog.prototype, '_onKey', function (original) {
return function () { }; // no-op
});
});
You can create an extension for the Dialog widget like this in a new file:
define(["dojo/_base/declare", "dijit/Dialog"],
function(declare, Dialog){
return declare(Dialog, {
//Prevents the 'ESC' Button of Closing the dialog
_onKey: function() { }
});
});
save the file into dojo Directory (say: dojo/my/my_dialog.js),
and instead of calling: 'dijit/Dialog', just call: 'my/my_dialog'.
this will save you the hard work of editing each Dialog call,
And the same thing to the "dojox/widget/DialogSimple" Widget.

making Ext.Action's text property dependent on another field's value

I have a grid within a window. The grid has 3 Actions: Edit, Delete and Disable.I was wondering if it is possible to make the text of the Disable Action (which is currently 'Disable/Enable') to be dependent on the Current Status of the record selected. So say the user selects a record whose Current Status is Enabled, then the action's text should be 'Disable'. If, however, the user selects a record whose status is Disabled, then the action's text should be 'Enable'. Is it possible to do this when using Action? Or do I need to use a button instead of Action?
I am assuming your action button is in a toolbar that is docked to the top of your grid panel. The only tricky thing is getting a reference to the grid (without hardcoding it). The grid's 'select' event only gives you a reference to the rowmodel used.
/* Set a action attribute on the Ext.Action so we can find it */
var action = new Ext.Action({
text: 'Do something',
handler: function(){
Ext.Msg.alert('Click', 'You did something.');
},
iconCls: 'do-something',
itemId: 'myAction',
action: 'myAction' // I don't like itemId's personally :)
});
/* In the Controller */
init: function() {
this.control({
'mygrid': {
select: this.onRecordSelect
}
});
},
onRecordSelect: function(rowModel, record) {
var grid = rowModel.views[0].ownerCt);
var action = grid.getDockedItems('toolbar[dock="top"]')[0].down('button[action="myAction"]');
var enabled = (record.get('CurrentStatus') == "Enabled");
action.setText(enabled ? 'Disable' : 'Enable');
action.setIconCls(enabled ? 'myDisableCls' : 'myEnableCls');
}
/* in SASS */
.myDisableCls{
background-image:url(#{$icon_path}/checkbox.png) !important;
}
.myEnableCls {
background-image:url(#{$icon_path}/checkbox_ticked.png) !important;
}
Good luck!
I solved the problem in another way. This is my code:
grid.getSelectionModel().on({
selectionchange: function(sm, selections) {
if (selections.length > 0) {
Edit.enable();
Delete.enable();
if(selections[0].data.CurrentStatus == "Disabled"){
Disable.setText("Enable");
Disable.enable();
}else{
Disable.setText("Disable");
Disable.enable();
}
} else {
Edit.disable();
Delete.disable();
Disable.disable();
}
}
});