Passing data to Flutter based on Android event - android-studio

Really struggling with the correct way to achieve the following. If I want to make a native call to Android FROM my Flutter app, there are plenty of examples that I can follow. eg: create an EventChannel and then listen for events and respond to requests from within my Android/Kotlin onMessage listener.
However, what I cannot figure out is how to go the other way! I have a native event that is triggering in the background within native Android. When the event occurs, everything works fine and I can print / debug the data, but I cannot figure out the correct way to package this data up and send back up to Flutter to display in the app:
class MainActivity: FlutterActivity() {
....
....
....
fun somethingHappened(firstName: String, lastName: String, eMail: String) {
Log.d("MyApp","An event has occurred...");
// Log message is printing out correctly, but need to
// create Object / Hashmap / data structure and send to Flutter
}
....
....
}
Can anyone tell me the correct pattern / approach to use and ideally a link to a simple example that I can reference?
Thanks,
Jab

In MainActivity:
class MainActivity: FlutterActivity() {
private val CHANNEL = "CHANNEL"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
val channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL);
channel.invokeMethod("nameOfMethod", "dataToPass")
}
}
and on flutter side:
MethodChannel channel = MethodChannel('CHANNEL');
#override
void initState() {
channel.setMethodCallHandler((call){
if(call.method == 'nameOfMethod'){
print(call.arguments);
}
return null;
});
super.initState();
}

Related

Shopware How to get SalesChannelContext in OrderWrittenEvent in order to send Mail?

I have a situation where I want to send emails from the order written event whenever an order has been updated according to some set of conditions that I will implement (for example an API response error) But unfortunately I have been unable to do so.
I first created a controller and an email service which uses the abstract email service of shopware And from my controller I'm able to send an email But when I tried to do the same in the event,I quickly realized that it wasn't doing exactly what I was expecting it to do. After some research on it, I saw that the event actually don't have access to the sales channel context so I tried multiple different ways to solve this issue but I'm still stuck. Can somebody please guide me on how I can implement that? thank you very much.
an example of what I tried is to call the store API in order to get the context of the saleschannel to use it in my sendMail function But it was giving errors such as:
request.CRITICAL: Uncaught PHP Exception TypeError: "Argument 5 passed to Swag\BasicExample\Service\EmailService::sendMail() must be an instance of Shopware\Core\System\SalesChannel\SalesChannelContext, instance of stdClass given.
I obviously understand that I have to give it a Shopware\Core\System\SalesChannel\SalesChannelContext not an STD class but how can I do that? since it doesn't really see the channel context.
If you do have an instance of OrderEntity you can rebuild the SalesChannelContext from the existing order using the OrderConverter service.
<service id="Foo\MyPlugin\Subscriber\MySubscriber">
<argument type="service" id="Shopware\Core\Checkout\Cart\Order\OrderConverter"/>
<argument type="service" id="order.repository"/>
<tag name="kernel.event_subscriber"/>
</service>
class MySubscriber implements EventSubscriberInterface
{
private OrderConverter $orderConverter;
private EntityRepository $repository;
public function __construct(
OrderConverter $orderConverter,
EntityRepository $repository
) {
$this->orderConverter = $orderConverter;
$this->repository = $repository;
}
public static function getSubscribedEvents(): array
{
return [
OrderEvents::ORDER_WRITTEN_EVENT => 'onOrderWritten',
];
}
public function onOrderWritten(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $writeResult) {
$orderId = $writeResult->getPrimaryKey();
$criteria = new Criteria([$orderId]);
$criteria->addAssociation('transactions');
$criteria->addAssociation('orderCustomer');
$order = $this->repository
->search($criteria, $event->getContext())->first();
if (!$order instanceof OrderEntity) {
continue;
}
$salesChannelContext = $this->orderConverter
->assembleSalesChannelContext($order, $event->getContext());
// ...
}
}
}

How to connect two different ViewModels in Kotlin AndroidStudio

I have two different View Models with their own fragments, and I want my arrayListB in ViewModelB have the same value of my arrayListA in ViewModelA.
I am sure this may help you to do that!
Architecture Components provides ViewModel helper class for the UI controller that is responsible for preparing data for the UI. ViewModel objects are automatically retained during configuration changes so that data they hold is immediately available to the next activity or fragment instance. For example, if you need to display a list of users in your app, make sure to assign responsibility to acquire and keep the list of users to a ViewModel, instead of an activity or fragment, as illustrated by the following sample code:
class MyViewModel : ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData<List<User>>().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
for more information see this :
(https://developer.android.com/topic/libraries/architecture/viewmodel?msclkid=bf393d12ce9011eca291710e2d69c5af)

the right way to return a Single from a CompletionStage

I'm playing around with reactive flows using RxJava2, Micronaut and Cassandra. I'm new to rxjava and not sure what is the correct way to return a of List Person in the best async manner?
data is coming from a Cassandra Dao interface
public interface PersonDAO {
#Query("SELECT * FROM cass_drop.person;")
CompletionStage<MappedAsyncPagingIterable<Person>> getAll();
}
that gets injected into a micronaut controller
return Single.just(personDAO.getAll().toCompletableFuture().get().currentPage())
.subscribeOn(Schedulers.io())
.map(people -> HttpResponse.ok(people));
OR
return Single.just(HttpResponse.ok())
.subscribeOn(Schedulers.io())
.map(it -> it.body(personDAO.getAll().toCompletableFuture().get().currentPage()));
OR switch to RxJava3
return Single.fromCompletionStage(personDAO.getAll())
.map(page -> HttpResponse.ok(page.currentPage()))
.onErrorReturn(throwable -> HttpResponse.ok(Collections.emptyList()));
Not a pro of RxJava nor Cassandra :
In your first and second example, you are blocking the thread executing the CompletionStage with get, even if you are doing it in the IO thread, I would not recommand doing so.
You are also using a Single wich can emit, only one value, or an error. Since you want to return a List, I would sugest to go for at least an Observable.
Third point, the result from Cassandra is paginated, I don't know if it's intentionnaly but you list only the first page, and miss the others.
I would try a solution like the one below, I kept using the IO thread (the operation may be costly in IO) and I iterate over the pages Cassandra fetch :
/* the main method of your controller */
#Get()
public Observable<Person> listPersons() {
return next(personDAO.getAll()).subscribeOn(Schedulers.io());
}
private Observable<Person> next(CompletionStage<MappedAsyncPagingIterable<Person>> pageStage) {
return Single.fromFuture(pageStage.toCompletableFuture())
.flatMapObservable(personsPage -> {
var o = Observable.fromIterable(personsPage.currentPage());
if (!personsPage.hasMorePages()) {
return o;
}
return o.concatWith(next(personsPage.fetchNextPage()));
});
}
If you ever plan to use reactor instead of RxJava, then you can give cassandra-java-driver-reactive-mapper a try.
The syntax is fairly simple and works in compile-time only.

Black-hole error when route pointed to a class that extends plugin and uses extended class

In routes I have
Router::connect('/opauth-complete/*', array('controller' => 'app_users', 'action' => 'opauth_complete'));
If I change pointer to controller app_users with anything else and create controller everything works with no error. But I need it to work with AppUsersController.
AppUsersController looks like this
App::uses('UsersController', 'Users.Controller');
class AppUsersController extends UsersController {
public function beforeFilter() {
parent::beforeFilter();
$this->User = ClassRegistry::init('AppUser');
}
// ...
// ...
public function opauth_complete() {
die(1);
}
// ...
// ...
}
So, plugin is CakeDC Users and another plugin that goes to /example/callback after /example/auth/facebook is Opauth plugin.
Error message looks like this
The request has been black-holed
Error: The requested address '/example/opauth-complete' was not found on this server.
This is perfectly possible to make these two plugins work together; when browser points to /example/auth/facebook, it redirects to /example/auth/callback and somehow it needs opauth-complete route to link to specific method.
All works if not pointed to app_users that extends plugin, uses plugin. Does not work only with this case. How can users of these two plugins get around such situation.
I solved it by disabling Security component on Opauth action in my AppUsersController. Thing is that Opauth transfers data using POST and you should either change a method of it (ie: use Sessions, GET) or disable Security component.
For a method change use this in your bootstrap.php or core.php
Configure::write('Opauth.callback_transport', 'session'); // you can try 'get' too
To follow my approach add this to a controller where error occurs and where you place your opauth_complete method
public function beforeFilter() {
// ...
if (isset($this->Security) && $this->action == 'opauth_complete') {
$this->Security->validatePost = false;
$this->Security->csrfCheck = false;
}
// ...
}
P.S. Changing method to Sessions has its drawbacks, you can take a look at comments here at Github Opauth issue #16

GWT-GXT FileUploadField

I tried making a form in GXT to upload files, but I see more examples on the net, I failed to make it work a simple FileUploadField to save the file locally.
Cde fragment:
formPanel = new FormPanel();
formPanel.setBodyBorder(false);
formPanel.setHeaderVisible(false);
formPanel.setAction(GWT.getModuleBaseURL() + "fileUpload");
formPanel.setEncoding(Encoding.MULTIPART);
formPanel.setMethod(Method.POST);
formPanel.setButtonAlign(HorizontalAlignment.CENTER);
formPanel.setHeaderVisible(true);
fileUploadField = new FileUploadField();
fileUploadField.setName("fileName");
fileUploadField.setAllowBlank(false);
fileUploadField.setFieldLabel("Archivo");
fileUploadField.addListener(Events.OnChange, new Listener<BaseEvent>() {
public void handleEvent(BaseEvent BaseEvent) {
aSubmitButton.setEnabled(true);
}
});
aSubmitButton = new Button("OK");
aSubmitButton.setEnabled(false);
aSubmitButton.setId("submit_button");
aSubmitButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
#Override
public void componentSelected(ButtonEvent inButtonEvent) {
formPanel.submit();
}
});
The above code is the declaration of FormPanel and FileUploadField.
We use gwtupload-0.6.3-compat.jar library to do the job.
Basically, the idea is that on the server side you need to create a servlet, which is going to be accepting your uploaded files. The mentioned library provides UploadAction servlet extension facilitating that.
On the client side you can use one of gwtupload components. We use MultiUploader for instance. That's literally a few lines of code there. Main code is in the listener:
private IUploader.OnFinishUploaderHandler onFinishUploaderHandler = new IUploader.OnFinishUploaderHandler() {
public void onFinish(IUploader uploader) {
if (uploader.getStatus() == Status.SUCCESS) {
// What you want to do when file is uploaded.
}
}
};
The rest is taken care of by the component. Since the library is for GWT, it comes with source code, so you can see what it's doing behind the scene and read extensive comments in the code.
Free to use of course.

Resources