Add custom selection menu on Android in React Native WebView - react-native

I'm trying to show custom buttons for text selection in React-Native WebView on Android. I've created a custom component as described here. It works fine.
Following this answer, I'm trying to override ActionMode with custom ActionMode.Callback to display my custom menu. However it doesn't seem to work at all.
My code:
CustomWebViewManager.java
protected static class CustomWebView extends RNCWebView {
public Context context;
public CustomWebView(ThemedReactContext reactContext) {
super(reactContext);
this.context=context;
}
// setting custom action bar
private ActionMode mActionMode;
private ActionMode.Callback mSelectActionModeCallback;
private GestureDetector mDetector;
// this will over ride the default action bar on long press
#Override
public ActionMode startActionMode(Callback callback) {
ViewParent parent = getParent();
if (parent == null) {
return null;
}
String name = callback.getClass().toString();
if (name.contains("SelectActionModeCallback")) {
mSelectActionModeCallback = callback;
mDetector = new GestureDetector(context,
new CustomGestureListener());
}
CustomActionModeCallback mActionModeCallback = new CustomActionModeCallback();
return parent.startActionModeForChild(this, mActionModeCallback);
}
private class CustomActionModeCallback implements ActionMode.Callback {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mActionMode = mode;
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
//overriding onPrepareActionMode, onActionItemClicked and onDestroyActionMode as usual
...
}
private class CustomGestureListener extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onSingleTapUp(MotionEvent e) {
if (mActionMode != null) {
mActionMode.finish();
return true;
}
return false;
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(mDetector !=null)
mDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
}
What I'm doing wrong here? Is that a correct approach?
Thanks.

Related

highlight items in recyclerview android

I am trying to select items in recylerview. When I click an item, a checkbox appears on that item and it is highlighted. But the problem is that when I scroll, the item which is highlighted goes to its original color but the checkbox image remains as it should. Why the highlighted color is gone but the image remains after scrolling, I want the items to keep their state after scrolling.
public static List<Model> item = new ArrayList<Model>()
#Override
public void onBindViewHolder(#NonNull MyAdapter.MyViewHolder holder, int
position) {
holder.bind(item.get(position));
//
public class MyViewHolder extends RecyclerView.ViewHolder{
public MyViewHolder(#NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.check);
public void bind(Model model) {
if (model.isChecked()){
imageView.setVisibility(View.VISIBLE);
itemView.setBackgroundColor(Color.GRAY);
model.setChecked(true);
} else {
imageView.setVisibility(View.GONE);
itemView.setBackgroundColor(Color.TRANSPARENT);
model.setChecked(false);
}
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Model s = item.get(getAdapterPosition());
if (!selectList.contains(s)){
selectList.add(s);
model.setChecked(true);
} else {
selectList.remove(s);
model.setChecked(false);
}
notifyItemChanged(getAdapterPosition());
}
});
public class Model {
private boolean isChecked = false;
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean checked) {
isChecked = checked;
}
}
Don't manually change the design in the onclick listener, just update your model (as you are already doing: model.setchecked(...) depending on state)
Then call Adapter.notifyItemChanged(getAdapterPosition())
This will force the adapter to reload the item, calling onBindViewHolder, where the design should be updated properly
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Model s = item.get(getAdapterPosition());
if (!selectList.contains(s)){
selectList.add(s);
model.setChecked(true);
} else {
selectList.remove(s);
model.setChecked(false);
}
adapter.notifyItemChanged(getAdapterPosition())
}
In the above example, replace "adapter" with a reference to your recylerview adapter

Xamarin MVVM push user data to viewmodel

like the title says I want to give through the user information to my viewmodel, but the problem is that the viewmodel is registered as a dependency and I am binding its content to the xaml page itself. How do I send the user information to the viewmodel itself?
Thank you!
Xaml.cs part:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Calendar : ContentPage
{
public Calendar(User user)
{
InitializeComponent();
FileImageSource image = new FileImageSource
{
File = "calendar.png"
};
Icon = image;// push user information to the ICalendarViewModel
BindingContext = AppContainer.Container.Resolve<ICalendarViewModel>();
}
}
Interface:
public interface ICalendarViewModel : INotifyPropertyChanged
{
}
Bootstrap part registering dependencies:
public class Bootstrap
{
public IContainer CreateContainer()
{
var containerBuilder = new ContainerBuilder();
RegisterDependencies(containerBuilder);
return containerBuilder.Build();
}
protected virtual void RegisterDependencies(ContainerBuilder builder)
{
builder.RegisterType<CalendarViewModel>()
.As<ICalendarViewModel>()
.SingleInstance();
}
}
CalendarViewModel: I do not know if this will help
public class CalendarViewModel : ViewModelBase, ICalendarViewModel
{
public event PropertyChangedEventHandler PropertyChanged;
public string ErrorMessage { get; set; }
private CourseInformation _information;
private ICourseInformationRepository _repository;
public CalendarViewModel()
{
_repository = new CourseInformationRepository();
LoadData();
}
private ObservableCollection<CourseInformation> _courses;
public ObservableCollection<CourseInformation> Courses
{
get
{
return _courses;
}
set
{
_courses = value;
RaisePropertyChanged(nameof(Courses));
}
}
private void LoadData()
{
try
{
ObservableCollection<CourseInformation> CourseList = new ObservableCollection<CourseInformation>(_repository.GetAllCourseInformation());
Courses = new ObservableCollection<CourseInformation>();
DateTime date;
foreach (var course in CourseList)
{
string [] cour = course.Date.Split('/');
cour[2] = "20" + cour[2];
date = new DateTime(Convert.ToInt32(cour[2]), Convert.ToInt32(cour[1]), Convert.ToInt32(cour[0]));
if (date == DateTime.Now)//TESTING WITH TEST DATE, datetime.now
{
if (course.FromTime.Length < 4)
{
course.FromTime = "0" + course.FromTime;
}
if (course.UntilTime.Length < 4)
{
course.UntilTime = "0" + course.UntilTime;
}
course.FromTime = course.FromTime.Insert(2, ":");
course.UntilTime = course.UntilTime.Insert(2, ":");
Courses.Add(course);
}
}
}
catch (ServerUnavailableException e)
{
ErrorMessage = "Server is niet beschikbaar, ophalen van kalender is niet mogelijk.";
}
}
private void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Bootstrap binding in app.xaml.cs:
public partial class App : Application
{
public App()
{
InitializeComponent();
AppContainer.Container = new Bootstrap().CreateContainer();
MainPage = new LoginView();
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
I wanted to comment (not enough reputation) on #LeRoy, use a framework. I would recommend FreshMVVM and you can pass objects into the ViewModel and even pass in Services. It makes it all nice and clean, and it just works.
Should not your CalendarViewModel viewModel contain BindableBase ?
public class CalendarViewModel : BindableBase, ViewModelBase, ICalendarViewModel
what framework are you using? prism, freshmvvm.
Your View and Viewmodel is normally automatically handled by the framework, all you need to do is register your page.
Container.RegisterTypeForNavigation<Views.CalendarPage>();

Toggle implementation for custom RadioButton

I need to create a custom RadioButton without circle. Its a very simple class that extends Label and implements Toggle.
I added a mouse clicked handler :
private class MouseClickedHandler implements EventHandler<MouseEvent> {
#Override
public void handle(MouseEvent t) {
final Toggle toggle = (Toggle) t.getSource();
if (!toggle.isSelected()) {
getToggleGroup().selectToggle(toggle);
}
}
}
My problem is to set a default selected radio button.
If on one of the RadioButton I call setSelected(true) after its creation and after adding it to a ToggleGroup, when I launch the application if I click on other radio buttons in the group, the ToggleGroup does its job of deselecting except for that default one. I always end up with 2 radio buttons selected, the one on which I called setSelected(true) directly, and the one currently selected by a click.
I corrected it - Complete code :
public class RadioBtn extends Label implements Toggle {
private ObjectProperty<ToggleGroup> toggleGroup = null;
private BooleanProperty selectedProperty = null;
public RadioBtn {
initHandlers();
}
#Override
public ToggleGroup getToggleGroup() {
return toggleGroupProperty().get();
}
#Override
public void setToggleGroup(ToggleGroup tg) {
if (getToggleGroup() == null) {
toggleGroupProperty().set(tg);
}
getToggleGroup().getToggles().add(this);
}
#Override
public ObjectProperty<ToggleGroup> toggleGroupProperty() {
if (toggleGroup == null) {
toggleGroup = new SimpleObjectProperty<>();
}
return toggleGroup;
}
#Override
public boolean isSelected() {
return selectedProperty().get();
}
#Override
public void setSelected(boolean bln) {
selectedProperty().set(bln);
}
#Override
public BooleanProperty selectedProperty() {
if (selectedProperty == null) {
selectedProperty = new SimpleBooleanProperty();
}
return selectedProperty;
}
protected void initHandlers() {
if (getToggleGroup() != null) {
setOnMouseClicked(new ToggleGroupHandler());
}
}
private class ToggleGroupHandler implements EventHandler<MouseEvent> {
#Override
public void handle(MouseEvent t) {
final Toggle toggle = (Toggle) t.getSource();
if (!toggle.isSelected()) {
/*if(getToggleGroup().getSelectedToggle() != null) {
getToggleGroup().getSelectedToggle().setSelected(false);
}*/
getToggleGroup().selectToggle(toggle);
}
}
}
}

GWT popup is not centered when built within onClickHandler

My aim is to use GWT.runSync to load the popup contents only when required.
If I construct my widget as:
public class CreateButton extends Button {
public CreateButton() {
super("Create");
buildUI();
}
private void buildUI() {
final CreateWidget createWidget = new CreateWidget();
final PopupPanel popupPanel = new PopupPanel(false);
popupPanel.setWidget(createWidget);
popupPanel.setGlassEnabled(true);
popupPanel.setAnimationEnabled(true);
addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
popupPanel.center();
}
});
}
}
Then the popup will be centered correctly.
If I build the popup within the clickHandler:
public class CreateButton extends Button {
public CreateButton() {
super("Create");
buildUI();
}
private void buildUI() {
#Override
public void onClick(ClickEvent event) {
final CreateWidget createWidget = new CreateWidget();
final PopupPanel popupPanel = new PopupPanel(false);
popupPanel.setWidget(createWidget);
popupPanel.setGlassEnabled(true);
popupPanel.setAnimationEnabled(true);
addClickHandler(new ClickHandler() {
popupPanel.center();
}
});
}
}
The popup will not center correctly. I have tried using setPositionAndShow, however the supplied offsets are 12, even though the CreateWidget is actually about 200px for both width and height.
I want to use the second method so I can eventually use GWT.runAsync within the onClick as CreateWidget is very complex.
I am using GWT-2.1.1
Seems to work by delaying the call to center. Perhaps a once off Timer would work as well. Delaying the call also works when wrapping buildUI within GWT.runAsync
public class CreateButton extends Button {
public CreateButton() {
super("Create");
buildUI();
}
private void buildUI() {
#Override
public void onClick(ClickEvent event) {
final CreateWidget createWidget = new CreateWidget();
final PopupPanel popupPanel = new PopupPanel(false);
popupPanel.setWidget(createWidget);
popupPanel.setGlassEnabled(true);
popupPanel.setAnimationEnabled(true);
addClickHandler(new ClickHandler() {
Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
#Override
public boolean execute() {
popupPanel.center();
return false;
}
}, 50); //a value greater than 50 maybe needed here.
});
}
}
}
}

SurfaceView Tutorial problems

I found a tutorial and it looks like this:
package com.djrobotfreak.SVTest;
public class Tutorial2D extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new Panel(this));
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
private TutorialThread _thread;
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
_thread = new TutorialThread(getHolder(), this);
}
#Override
public void onDraw(Canvas canvas) {
Bitmap _scratch = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(_scratch, 10, 10, null);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
_thread.setRunning(true);
_thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// simply copied from sample application LunarLander:
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
}
class TutorialThread extends Thread {
private SurfaceHolder _surfaceHolder;
private Panel _panel;
private boolean _run = false;
public TutorialThread(SurfaceHolder surfaceHolder, Panel panel) {
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
#Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_panel.onDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
and it does not work, no matter what I do. I am trying to convert my code to surfaceview but I cant find any surfaceview programs that even work (besides the android-provided ones). Does anyone know what the error even is saying?
Here is my logcat info: http://shrib.com/oJB5Bxqs
If you get a ClassNotFoundException, you should check the Manifest file.
Click on the Application tab and look on the botton right side under "Attributes for".
If there is a red X mark under your Class Name, then click on the "Name" link and locate the correct class to load.