I am creating a Twitter client using Fabric but I can not create a custom onClick.
I created this custom adapter and tried to create a OnClickListener but not working. Always open in browser tweet.
public class TweetAdapter extends TweetTimelineListAdapter {
public ArrayList<Long> tweetIds=new ArrayList<Long>();
public TweetAdapter(Context context, Timeline<Tweet> timeline) {
super(context, timeline);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Object rowView = convertView;
final Tweet tweet = (Tweet)this.getItem(position);
if(convertView == null) {
rowView = new CompactTweetView(this.context, tweet);
} else {
((BaseTweetView)convertView).setTweet(tweet);
((View)rowView).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
tweetIds.add(tweet.getId());
}
});
}
return (View)rowView;
}
}
In BaseTweetView class it is the function type OnClickListener but in this case I can't think of any idea to overwrite.
private void setPermalinkLauncher() {
BaseTweetView.PermalinkClickListener listener = new BaseTweetView.PermalinkClickListener();
this.setOnClickListener(listener);
this.contentView.setOnClickListener(listener);
}
class PermalinkClickListener implements OnClickListener {
PermalinkClickListener() {
}
public void onClick(View v) {
if(BaseTweetView.this.getPermalinkUri() != null) {
BaseTweetView.this.scribePermalinkClick();
BaseTweetView.this.launchPermalink();
}
}
}
Any ideas? Thanks
Finally I made this works using a custom Adapter (very similar that the one you use in the question). This adapter obtains the resulting view from super implementation and adds an onClickListener to overrides the fabric defaults one:
class CustomTweetTimelineListAdapter extends TweetTimelineListAdapter {
public CustomTweetTimelineListAdapter(Context context, Timeline<Tweet> timeline) {
super(context, timeline);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
//disable subviews to avoid links are clickable
if(view instanceof ViewGroup){
disableViewAndSubViews((ViewGroup) view);
}
//enable root view and attach custom listener
view.setEnabled(true);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String tweetId = "click tweetId:"+getItemId(position);
Toast.makeText(context, tweetId, Toast.LENGTH_SHORT).show();
}
});
return view;
}
//helper method to disable subviews
private void disableViewAndSubViews(ViewGroup layout) {
layout.setEnabled(false);
for (int i = 0; i < layout.getChildCount(); i++) {
View child = layout.getChildAt(i);
if (child instanceof ViewGroup) {
disableViewAndSubViews((ViewGroup) child);
} else {
child.setEnabled(false);
child.setClickable(false);
child.setLongClickable(false);
}
}
}
}
Full code example here.
Hope it helps.
Related
My search view is working properly but I am trying to do a search such that all the "visible" search letters should be highlighted. I used the filter interface in my adapter for filtering data.
here is my adapter Class
public class myAdapter extends RecyclerView.Adapter<myAdapter.viewHolder> implements Filterable {
private List<Model> model;
// for search filtering
private ArrayList<Model> modelFull;
Context context;
public myAdapter(ArrayList<Model> model, Context context) {
this.model = model;
modelFull =new ArrayList<>(model);
this.context = context;
}
#NonNull
#Override
public viewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.template, parent, false);
return new viewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull viewHolder holder, int position) {
Model forPosition = model.get(position);
holder.image.setImageResource(forPosition.getImage());
holder.intro.setText(forPosition.getIntro());
}
#Override
public int getItemCount() {
return model.size();
}
public class viewHolder extends RecyclerView.ViewHolder {
TextView intro;
ImageView image;
public viewHolder(#NonNull View itemView) {
super(itemView);
intro= itemView.findViewById(R.id.introTxt);
image = itemView.findViewById(R.id.image);
}
}
#Override
public Filter getFilter() {
return generalFilter;
}
private Filter generalFilter =new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
List<Model> filteredModel =new ArrayList<>();
if(constraint ==null || constraint.length()==0) {
filteredModel.addAll(modelFull);
}
else {
String searchQuery= constraint.toString().toLowerCase().trim();
for(blogBigModel item : modelFull){
if(item.getBlogIntro().toLowerCase().contains(searchQuery)){
filteredModel.add(item);
}
}
}
FilterResults results =new FilterResults();
results.values = filteredModel;
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
model.clear();
model.addAll((List)results.values);
notifyDataSetChanged();
}
};
}
that's my class / Fragment where i used the above adapter
[what should i add to get the desired highlighted query when i search in the search bar like Whatsapp][1]
[1]: https://i.stack.imgur.com/Fdu2r.jpg
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.ic_home_search:enter code here
SearchView searchView = (SearchView) item.getActionView();
searchView.setQueryHint("Search....");
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setBackground(getResources().getDrawable(R.drawable.searchview_bg));
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
});
}
}
return true;
});
I want to filter Listview by Searchview
I use the following Adapter for the filter and it works if I haven't made any new additions to the adapter
When I add a new item to Listview, the search stops completely until I restart the program after adding, modifying or deleting it
full code
adapter class
Do you want to achieve the result like following GIF?
If you want to add the item to the listview, based on your adapter, you should item in the adapter like following code.
public class TableItemAdapter : BaseAdapter<TableItem>, IFilterable
{
public List<TableItem> _originalData;
public List<TableItem> _items;
private readonly Activity _context;
public TableItemAdapter(Activity activity, IEnumerable<TableItem> tableitems)
{
_items = tableitems.ToList();
_context = activity;
Filter = new TableItemFilter(this);
}
//Add data to the `_items`, listview will be updated, if add data in the activity,
//there are two different lists, so listview will not update.
public void AddData(TableItem tableItem)
{
_items.Add(tableItem);
NotifyDataSetChanged();
}
public override TableItem this[int position]
{
get { return _items[position]; }
}
public Filter Filter { get; private set; }
public override int Count
{
get { return _items.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = _items[position];
View view = convertView;
if (view == null) // no view to re-use, create new
view = convertView ?? _context.LayoutInflater.Inflate(Resource.Layout.TableItem, null);
//view = _context.LayoutInflater.Inflate(Resource.Layout.TableItem, null);
view.FindViewById<TextView>(Resource.Id.Text1).Text = item.Heading;
view.FindViewById<TextView>(Resource.Id.Text2).Text = item.SubHeading;
return view;
}
public override void NotifyDataSetChanged()
{
// this.NotifyDataSetChanged();
base.NotifyDataSetChanged();
}
}
public class TableItemFilter :Filter
{
private readonly TableItemAdapter _adapter;
public TableItemFilter(TableItemAdapter adapter)
{
_adapter = adapter;
}
protected override FilterResults PerformFiltering(ICharSequence constraint)
{
var returnObj = new FilterResults();
var results = new List<TableItem>();
if (_adapter._originalData == null)
_adapter._originalData = _adapter._items;
if (constraint == null) return returnObj;
if (_adapter._originalData != null && _adapter._originalData.Any())
{
results.AddRange(
_adapter._originalData.Where(
item => item.SubHeading.ToLower().Contains(constraint.ToString()) | item.Heading.ToLower().Contains(constraint.ToString())));
}
returnObj.Values = FromArray(results.Select(r => r.ToJavaObject()).ToArray());
returnObj.Count = results.Count;
constraint.Dispose();
return returnObj;
}
protected override void PublishResults(ICharSequence constraint, FilterResults results)
{
using (var values = results.Values)
_adapter._items = values.ToArray<Java.Lang.Object>().Select(r => r.ToNetObject<TableItem>()).ToList();
_adapter.NotifyDataSetChanged();
// Don't do this and see GREF counts rising
constraint.Dispose();
results.Dispose();
}
}
public class JavaHolder : Java.Lang.Object
{
public readonly object Instance;
public JavaHolder(object instance)
{
Instance = instance;
}
}
public static class ObjectExtensions
{
public static TObject ToNetObject<TObject>(this Java.Lang.Object value)
{
if (value == null)
return default(TObject);
if (!(value is JavaHolder))
throw new InvalidOperationException("Unable to convert to .NET object. Only Java.Lang.Object created with .ToJavaObject() can be converted.");
TObject returnVal;
try { returnVal = (TObject)((JavaHolder)value).Instance; }
finally { value.Dispose(); }
return returnVal;
}
public static Java.Lang.Object ToJavaObject<TObject>(this TObject value)
{
if (Equals(value, default(TObject)) && !typeof(TObject).IsValueType)
return null;
var holder = new JavaHolder(value);
return holder;
}
}
}
Then in the activity, you add the data by adapter.
private void Button1_Click(object sender, System.EventArgs e)
{
tableItemAdapter.AddData(new TableItem() { Heading = "test1222", SubHeading = "sub Test" });
}
Here is my demo, you can download it.
https://github.com/851265601/Xamarin.Android_ListviewSelect/blob/master/XAListViewSearchDemo.zip
I've created a JavaFX application with JDK8, that contains a window and multiples objects.
I'm trying now to put useless used object available for GarbageCollector.(Testing with JVisualVM).
But I'm stuck with one problem: Clean a Popover that contains handler and listener on window element.
Original code of the popover:
public class CustomPopOver extends PopOver {
/**
* Constructor with the Content of the PopOver.
* #param content the Node.
*/
public CustomPopOver (Node content) {
super(content);
addHandler();
}
/**
* Empty Constructor.
*/
public CustomPopOver () {
super();
addHandler();
}
private void addHandler() {
this.ownerWindowProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
EventHandler<WindowEvent> preExistingHandler = newValue.getOnCloseRequest();
newValue.setOnCloseRequest(event -> {
if (this.isShowing()) {
this.hide(Duration.millis(0));
}
if (preExistingHandler != null) {
preExistingHandler.handle(event);
}
});
}
});
}
}
I tried lots of thing to go to this, but it's not working properly:
public class CustomPopOver extends PopOver implements DisposableBean {
private MyListener listener = new MyListener();
public CustomPopOver (Node content) {
super(content);
addHandler();
}
/**
* Empty Constructor.
*/
public CustomPopOver () {
super();
addHandler();
}
private void addHandler() {
this.ownerWindowProperty().addListener(listener);
}
#Override
public void destroy() {
if (this.getOwnerWindow() != null){
this.getOwnerWindow()
.removeEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, listener.windowCloseEventHandler);
this.getOwnerWindow()
.removeEventHandler(WindowEvent.WINDOW_HIDING, listener.windowHidingEventHandler);
}
this.ownerWindowProperty().removeListener(listener);
listener = null;
}
/**
* ChangeListener that removes itself when needed.
*/
private class MyListener implements ChangeListener<Window> {
EventHandler<WindowEvent> windowCloseEventHandler;
EventHandler<WindowEvent> windowHidingEventHandler;
#Override
public void changed(ObservableValue<? extends Window> observable, Window oldValue, Window newValue) {
if (oldValue != null) {
oldValue.removeEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, windowCloseEventHandler);
oldValue.removeEventHandler(WindowEvent.WINDOW_HIDING, windowHidingEventHandler);
}
if (newValue != null) {
EventHandler<WindowEvent> preExistingHandler = newValue.getOnCloseRequest();
windowCloseEventHandler = new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
if (isShowing()) {
hide(Duration.millis(0));
ownerWindowProperty().removeListener(MyListener.this);
}
if (preExistingHandler != null) {
preExistingHandler.handle(event);
}
newValue.removeEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, this);
}
};
newValue.setOnCloseRequest(windowCloseEventHandler);
windowHidingEventHandler = new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
ownerWindowProperty().removeListener(MyListener.this);
newValue.removeEventHandler(WindowEvent.WINDOW_HIDING, this);
}
};
newValue.setOnHiding(windowHidingEventHandler);
}
}
}
}
and we call the destroy method to clean the popover from jvm cache.
Code to test class CustomPopOver:
public class PopOverViewer extends Application {
private BorderPane pane;
public PopOverViewer() {
pane = new BorderPane();
pane.setCenter(button());
}
private Node button() {
HBox hBox = new HBox();
List<CustomPopOver > lists = new ArrayList<>();
Button show = new Button("click");
show.setOnAction(event -> {
CustomPopOver popOver = new CustomPopOver ();
lists.add(popOver);
popOver.show(show);
});
Button clean = new Button("clean");
clean.setOnAction(event -> {
lists.forEach(CustomPopOver::destroy);
lists.clear();
});
hBox.getChildren().addAll(show, clean);
return hBox;
}
#Override
public void start(Stage primaryStage) {
PopOverViewer app = new PopOverViewer();
primaryStage.setScene(new Scene(app.getPane()));
primaryStage.show();
}
private Parent getPane() {
return pane;
}
}
I would like that the class CustomPopover is clean from GC.
Thanks #fabian, placing WeakEventHandler on Handler inside of a strong referenced Listener, helped to clean it.
Code that worked:
public class CustomPopOver extends PopOver implements DisposableBean {
private MyListener listener = new MyListener();
/**
* Constructor with the Content of the PopOver.
* #param content the Node.
*/
public CustomPopOver(Node content) {
super(content);
addHandler();
}
/**
* Empty Constructor.
*/
public CustomPopOver() {
super();
addHandler();
}
private void addHandler() {
this.ownerWindowProperty().addListener(listener);
}
#Override
public void destroy() {
this.ownerWindowProperty().removeListener(listener);
listener = null;
}
/**
* ChangeListener that removes itself when needed.
*/
private class MyListener implements ChangeListener<Window> {
#Override
public void changed(ObservableValue<? extends Window> observable, Window oldValue, Window newValue) {
if (newValue != null) {
EventHandler<WindowEvent> preExistingHandler = newValue.getOnCloseRequest();
EventHandler<WindowEvent> windowCloseEventHandler = new WeakEventHandler<>(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
if (isShowing()) {
hide(Duration.millis(0));
ownerWindowProperty().removeListener(CustomPopOver.MyListener.this);
}
if (preExistingHandler != null) {
preExistingHandler.handle(event);
}
newValue.removeEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, this);
}
});
newValue.setOnCloseRequest(windowCloseEventHandler);
EventHandler<WindowEvent> windowHidingEventHandler = new WeakEventHandler<>(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
ownerWindowProperty().removeListener(CustomPopOver.MyListener.this);
newValue.removeEventHandler(WindowEvent.WINDOW_HIDING, this);
}
});
newValue.setOnHiding(windowHidingEventHandler);
}
}
}
}
I am using MvvmCross in my Xamarin.Android application. I want to make my own custom MvxRecyclerAdapter so that I can have multiple buttons in each row of the MvxRecyclerView. Here is my custom MvxRecyclerView:
public class TwoPieceMvxRecyclerView : MvxRecyclerView
{
private bool _initialized;
public TwoPieceMvxRecyclerView(Context context, IAttributeSet attr) : base(context, attr)
{
}
public override Android.Support.V7.Widget.RecyclerView.Adapter GetAdapter()
{
if(!_initialized)
{
SetAdapter(new TwoPieceMvxRecyclerAdapter());
_initialized = true;
}
return base.GetAdapter();
}
}
And here is my custom MvxRecyclerAdapter:
public class TwoPieceMvxRecyclerAdapter : MvxRecyclerAdapter, IOnClickListener
{
private ICommand _itemClickPiece1;
private ICommand _itemClickPiece2;
private View _clickablePiece1;
private View _clickablePiece2;
public TwoPieceMvxRecyclerAdapter()
{
}
public ICommand ItemClickPiece1
{
get { return _itemClickPiece1; }
set
{
if (ReferenceEquals(_itemClickPiece1, value))
{
return;
}
_itemClickPiece1 = value;
}
}
public ICommand ItemClickPiece2
{
get { return _itemClickPiece2; }
set
{
if (ReferenceEquals(_itemClickPiece2, value))
{
return;
}
_itemClickPiece2 = value;
}
}
protected override Android.Views.View InflateViewForHolder(Android.Views.ViewGroup parent, int viewType, MvvmCross.Binding.Droid.BindingContext.IMvxAndroidBindingContext bindingContext)
{
var view = base.InflateViewForHolder(parent, viewType, bindingContext);
_clickablePiece1 = view.FindViewById<View>(Resource.Id.clickable_piece1);
_clickablePiece2 = view.FindViewById<View>(Resource.Id.clickable_piece2);
_clickablePiece1.SetOnClickListener(this);
_clickablePiece2.SetOnClickListener(this);
return view;
}
public void OnClick(View v)
{
if (v == _clickablePiece1)
{
ItemClickPiece1.Execute(null);
}
else if (v == _clickablePiece2)
{
ItemClickPiece2.Execute(null);
}
}
}
When I run the application I get this error:
Could not activate JNI Handle 0xbfd00978 (key_handle 0x6e44919) of
Java type
'md5bd77c484e80df14e69d8c5ab04394fe0/TwoPieceMvxRecyclerView' as
managed type
'AzzimovMobile.Droid.Components.TwoPieceMvxRecycler.TwoPieceMvxRecyclerView'.
System.InvalidOperationException: If you wan't to use single
item-template RecyclerView Adapter you can't change
it'sIMvxTemplateSelector to anything other than
MvxDefaultTemplateSelector
You are missing a constructor on your RecyclerView:
public TwoPieceMvxRecyclerView(IntPtr javaReference, JniHandleOwnership transfer): base(javaReference, transfer)
{
}
Also be aware you don't need to use a custom RecyclerView to change its Adapter. You can just grab the RecyclerView instance on your .cs view and set the adapter from there. Something like this should work:
public class MyView: MvxFragment<MyViewModel>
{
//...
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = base.OnCreateView(inflater, container, savedInstanceState);
// ...
var recycler = view.FindViewById<MvxRecyclerView>(Resource.Id.recycler);
recycler.Adapter = new TwoPieceMvxRecyclerAdapter(((IMvxAndroidBindingContext)BindingContext);
// you can even set a TemplateSelector here!
recycler.ItemTemplateSelector = new MyTemplateSelector();
// ...
return view;
}
}
I want to write a Vaadin 7 application (see MyVaadinUI below), which asks the user to enter user name and password.
If they are correct, another view (see MainUI below) should appear and take the entire area (replace the login view).
I tried to implement this transition in the method MyVaadinUI.goToMainWindow, but I get the error
java.lang.RuntimeException: Component must be attached to a session when getConnectorId() is called for the first time
at com.vaadin.server.AbstractClientConnector.getConnectorId(AbstractClientConnector.java:417)
at com.vaadin.server.communication.ConnectorHierarchyWriter.write(ConnectorHierarchyWriter.java:67)
at com.vaadin.server.communication.UidlWriter.write(UidlWriter.java:143)
at com.vaadin.server.communication.UidlRequestHandler.writeUidl(UidlRequestHandler.java:149)
at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:97)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:37)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1371)
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:238)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
when I run the application and press the button.
How can I fix it?
#Theme("mytheme")
#SuppressWarnings("serial")
public class MyVaadinUI extends UI
{
private TextField userNameTextField;
private PasswordField passwordTextField;
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = MyVaadinUI.class, widgetset = "ru.mycompany.vaadin.demo.AppWidgetSet")
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
addUserNameTextField(layout);
addPasswordTextField(layout);
addButton(layout, request);
}
private void addPasswordTextField(Layout aLayout) {
passwordTextField = new PasswordField("Пароль:");
aLayout.addComponent(passwordTextField);
}
private void addUserNameTextField(final Layout aLayout) {
userNameTextField = new TextField("Пользователь:");
aLayout.addComponent(userNameTextField);
}
private void addButton(final Layout aParent, final VaadinRequest request) {
final Button button = new Button("Войти");
button.addClickListener(new Button.ClickListener() {
public void buttonClick(Button.ClickEvent event) {
final boolean credentialsCorrect = checkCredentials();
if (credentialsCorrect) {
goToMainWindow(request);
} else {
[...]
}
}
});
aParent.addComponent(button);
}
private void goToMainWindow(final VaadinRequest aRequest) {
final MainUI mainUI = new MainUI();
mainUI.init(aRequest);
setContent(mainUI);
}
}
#Theme("mytheme")
#SuppressWarnings("serial")
public class MainUI extends UI {
#Override
protected void init(final VaadinRequest vaadinRequest) {
final HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
setContent(splitPanel);
splitPanel.setSizeFull();
splitPanel.setSplitPosition(200, Unit.PIXELS);
final String[] tabLabels = new String[] {
"Tree item 1",
"Tree item 2"};
final Tree tree = new Tree();
for (int i=0; i < tabLabels.length; i++)
{
addTreeItem(tree, tabLabels[i]);
}
splitPanel.setFirstComponent(tree);
splitPanel.setSecondComponent(new Label("Test"));
}
private void addTreeItem(final Tree aTree, final String aLabel) {
aTree.addItem(aLabel);
}
}
On the Vaadin forum someone suggested to use the navigator, which solved my problem.
I'd rather think that MainUI should extend HorizontalSplitPanel, not UI. It is strange concept to me to insert one UI into another.
You can use #SpringUI for the main class which extends UI:
#SpringUI
#Theme("mytheme")
#Widgetset("com.MyAppWidgetset")
#PreserveOnRefresh
public class MainUI extends UI {
private static final long serialVersionUID = -8247521108438815011L;
private static Locale locale = VaadinSession.getCurrent().getLocale();
#Autowired
private ToolBoxMessageSource messageSource;
#Autowired
private SpringViewProvider springViewProvider;
public MainUI() {
}
//Initializes navigator with SpringViewProvider and add all existing
//and ui specific assigned views to navigator.
#Override
protected void init(VaadinRequest vaadinRequest) {
Navigator navigator = new Navigator(this, this);
// Adding springViewProvider for spring autowiring
navigator.addProvider(springViewProvider);
// Adding all views for navigation
navigator.addView(LoginView.NAME, LoginView.class);
navigator.addView(MainView.NAME, MainView.class);
navigator.addView(MailToolView.NAME, MailToolView.class);
navigator.addView(AdminView.NAME, AdminView.class);
navigator.addView(EditRecipientView.NAME, EditRecipientView.class);
navigator.addView(EditRecipientsView.NAME, EditRecipientsView.class);
navigator.addView(ServerView.NAME, ServerView.class);
navigator.addView(TestJobView.NAME, TestJobView.class);
navigator.addView("", new LoginView());
navigator.navigateTo(LoginView.NAME);
navigator.setErrorView(LoginView.class);
// security: if user changes view check if the user has the required rights
navigator.addViewChangeListener(new ViewChangeListener() {
private static final long serialVersionUID = 7330051193056583546L;
#Override
public boolean beforeViewChange(ViewChangeEvent event) {
Toolbox toolbox = getSession().getAttribute(Toolbox.class);
if (TbRightManagement.checkAccess(event.getNewView().getClass(), toolbox)) {
return true;
} else {
if (toolbox != null) {
TBNotification.show(messageSource.getMessage("access.denied.title", locale),
messageSource.getMessage("access.denied.no_permissions.msg", locale),
Type.ERROR_MESSAGE);
navigator.navigateTo(MainView.NAME);
return false;
} else {
TBNotification.show(messageSource.getMessage("access.denied.title", locale),
messageSource.getMessage("access.denied.not_loggedin.msg", locale),
Type.ERROR_MESSAGE);
navigator.navigateTo(LoginView.NAME);
return false;
}
}
}
#Override
public void afterViewChange(ViewChangeEvent event) {}
});
}
}
And for the other views, as an example EditRecipientsView should be a #SpringView which extends a Vaadin Designer and implements a Vaadin View.
#SpringView(name = EditRecipientsView.NAME)
#Theme("mytheme")
#TbRight(loggedIn = true, mailTool = true)
public class EditRecipientsView extends RecipientsDesign implements View {
private static final long serialVersionUID = 1L;
public static final String NAME = "editRecipients";
private static Locale locale = VaadinSession.getCurrent().getLocale();
private BeanItemContainer<Recipient> recipientContainer;
private Uploader uploader;
#Autowired
private ToolBoxMessageSource messageSource;
public EditRecipientsView() {
super();
}
//Initializes the ui components of the recipient view.
#PostConstruct
public void init() {
btn_addRecipient.addClickListener(e -> { MainUI.getCurrent().getNavigator().navigateTo(EditRecipientView.NAME);});
}
//Handling data when entering this view.
#Override
public void enter(ViewChangeEvent event) {
if (getSession().getAttribute(UIMailing.class) != null) {
List<Recipient> recipientList = getSession().getAttribute(UIMailing.class).getRecipients();
if (recipientList != null) {
recipientContainer.removeAllItems();
} else {
recipientList = new ArrayList<Recipient>();
}
recipientContainer.addAll(recipientList);
recipient_table.sort(new Object[] {"foreName", "lastName"}, new boolean[] {true, true});
}
}
}