Deze presentatie is gegeven tijdens de KScope conferentie 2012
Spreker: Luc Bors
Titel: How to Bring Common UI Patterns to ADF
Onderwerp: Fusion Middleware - Subonderwerp: ADF
Eindgebruikers van bedrijfsapplicaties eisen dezelfde gebruikerservaring die ze kennen van bijvoorbeeld office applicaties en applicaties op het internet. Functies zoals bookmarking, favorieten en het werken met tabs wordt graag gezien in de dagelijkse werk. Het zoekmechanisme van Google, dat suggesties toont op basis van de ingevoerde tekst, is zo ´gewoon´ dat mensen dit in elke applicatie terug willen zien. Twitter en Facebook geven automatisch aan dat je nieuwe berichten hebt zonder dat je daar zelf eerst om moet vragen, dat gebruikers de normaalste zaak van de wereld vinden. Er zijn nog veel meer van deze UI patterns. In deze sessie leer je hoe een aantal van deze UI patterns in je ADF applicatie kunt inbouwen waardoor de eindgebruiker beschikking krijgt over bekende en vanzelfsprekende features. Dit zal leiden tot een snellere acceptatie van de applicatie en prettigere gebruikerservaring.
You may be hearing a lot of buzz around functional programming. For example, Java 8 recently introduced new features (lambda expressions and method references) and APIs (Streams, Optional and CompletableFutures) inspired from functional ideas such as first-class functions, composition and immutability.
However, what does this mean for my existing codebase?
In this talk we show how you can refactor your traditional object-oriented Java to using FP features and APIs from Java 8 in a beneficial manner.
We will discuss:
- How to adapt to requirement changes using first-class functions
- How you can enhance code reusability using currying
- How you can make your code more robust by favouring immutability over mutability
- How you can design better APIs and reduce unintended null pointer exceptions using an optional data type"
All you need to know about JS functions. talk was given by Oluwaleke Fakorede in JavaScript Ife Meetup.
Contains ways to declare javascript functions
methods in JavaScript.
When working with enterprise applications, you want to have the same user experience that you know from for instance office applications and browsers. People know how to use the features that can be found in browsers such as bookmarking, favorites, and working with tabs. The search mechanism provided by Google, that uses suggestions based on the text typed by the user, is so common that people expect this in every application. And there are more of these UI patterns. In this session, you will learn how to implement some of the common UI patterns in your ADF application.
From object oriented to functional domain modelingCodemotion
"From object oriented to functional domain modeling" by Mario Fusco
Malgrado l'introduzione delle lambda, la gran parte degli sviluppatori Java non è ancora abituata agli idiomi della programmazione funzionale e quindi non è pronta a sfruttare a pieno le potenzialità di Java 8. In particolare non è ancora comune vedere dati e funzioni usate insieme quando si modella un dominio di business. Lo scopo del talk è mostrare come alcuni principi di programmazione funzionale quali l'impiego di oggetti e strutture dati immutabili, l'uso di funzioni senza side-effect e il loro reuso mediante composizione, possono anche essere validi strumenti di domain modelling.
Deze presentatie is gegeven tijdens de KScope conferentie 2012
Spreker: Luc Bors
Titel: How to Bring Common UI Patterns to ADF
Onderwerp: Fusion Middleware - Subonderwerp: ADF
Eindgebruikers van bedrijfsapplicaties eisen dezelfde gebruikerservaring die ze kennen van bijvoorbeeld office applicaties en applicaties op het internet. Functies zoals bookmarking, favorieten en het werken met tabs wordt graag gezien in de dagelijkse werk. Het zoekmechanisme van Google, dat suggesties toont op basis van de ingevoerde tekst, is zo ´gewoon´ dat mensen dit in elke applicatie terug willen zien. Twitter en Facebook geven automatisch aan dat je nieuwe berichten hebt zonder dat je daar zelf eerst om moet vragen, dat gebruikers de normaalste zaak van de wereld vinden. Er zijn nog veel meer van deze UI patterns. In deze sessie leer je hoe een aantal van deze UI patterns in je ADF applicatie kunt inbouwen waardoor de eindgebruiker beschikking krijgt over bekende en vanzelfsprekende features. Dit zal leiden tot een snellere acceptatie van de applicatie en prettigere gebruikerservaring.
You may be hearing a lot of buzz around functional programming. For example, Java 8 recently introduced new features (lambda expressions and method references) and APIs (Streams, Optional and CompletableFutures) inspired from functional ideas such as first-class functions, composition and immutability.
However, what does this mean for my existing codebase?
In this talk we show how you can refactor your traditional object-oriented Java to using FP features and APIs from Java 8 in a beneficial manner.
We will discuss:
- How to adapt to requirement changes using first-class functions
- How you can enhance code reusability using currying
- How you can make your code more robust by favouring immutability over mutability
- How you can design better APIs and reduce unintended null pointer exceptions using an optional data type"
All you need to know about JS functions. talk was given by Oluwaleke Fakorede in JavaScript Ife Meetup.
Contains ways to declare javascript functions
methods in JavaScript.
When working with enterprise applications, you want to have the same user experience that you know from for instance office applications and browsers. People know how to use the features that can be found in browsers such as bookmarking, favorites, and working with tabs. The search mechanism provided by Google, that uses suggestions based on the text typed by the user, is so common that people expect this in every application. And there are more of these UI patterns. In this session, you will learn how to implement some of the common UI patterns in your ADF application.
From object oriented to functional domain modelingCodemotion
"From object oriented to functional domain modeling" by Mario Fusco
Malgrado l'introduzione delle lambda, la gran parte degli sviluppatori Java non è ancora abituata agli idiomi della programmazione funzionale e quindi non è pronta a sfruttare a pieno le potenzialità di Java 8. In particolare non è ancora comune vedere dati e funzioni usate insieme quando si modella un dominio di business. Lo scopo del talk è mostrare come alcuni principi di programmazione funzionale quali l'impiego di oggetti e strutture dati immutabili, l'uso di funzioni senza side-effect e il loro reuso mediante composizione, possono anche essere validi strumenti di domain modelling.
Similar to Creating a Facebook Clone - Part XXXIII - Transcript.pdf (20)
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualityInflectra
In this insightful webinar, Inflectra explores how artificial intelligence (AI) is transforming software development and testing. Discover how AI-powered tools are revolutionizing every stage of the software development lifecycle (SDLC), from design and prototyping to testing, deployment, and monitoring.
Learn about:
• The Future of Testing: How AI is shifting testing towards verification, analysis, and higher-level skills, while reducing repetitive tasks.
• Test Automation: How AI-powered test case generation, optimization, and self-healing tests are making testing more efficient and effective.
• Visual Testing: Explore the emerging capabilities of AI in visual testing and how it's set to revolutionize UI verification.
• Inflectra's AI Solutions: See demonstrations of Inflectra's cutting-edge AI tools like the ChatGPT plugin and Azure Open AI platform, designed to streamline your testing process.
Whether you're a developer, tester, or QA professional, this webinar will give you valuable insights into how AI is shaping the future of software delivery.
Securing your Kubernetes cluster_ a step-by-step guide to success !KatiaHIMEUR1
Today, after several years of existence, an extremely active community and an ultra-dynamic ecosystem, Kubernetes has established itself as the de facto standard in container orchestration. Thanks to a wide range of managed services, it has never been so easy to set up a ready-to-use Kubernetes cluster.
However, this ease of use means that the subject of security in Kubernetes is often left for later, or even neglected. This exposes companies to significant risks.
In this talk, I'll show you step-by-step how to secure your Kubernetes cluster for greater peace of mind and reliability.
Elevating Tactical DDD Patterns Through Object CalisthenicsDorra BARTAGUIZ
After immersing yourself in the blue book and its red counterpart, attending DDD-focused conferences, and applying tactical patterns, you're left with a crucial question: How do I ensure my design is effective? Tactical patterns within Domain-Driven Design (DDD) serve as guiding principles for creating clear and manageable domain models. However, achieving success with these patterns requires additional guidance. Interestingly, we've observed that a set of constraints initially designed for training purposes remarkably aligns with effective pattern implementation, offering a more ‘mechanical’ approach. Let's explore together how Object Calisthenics can elevate the design of your tactical DDD patterns, offering concrete help for those venturing into DDD for the first time!
Epistemic Interaction - tuning interfaces to provide information for AI supportAlan Dix
Paper presented at SYNERGY workshop at AVI 2024, Genoa, Italy. 3rd June 2024
https://alandix.com/academic/papers/synergy2024-epistemic/
As machine learning integrates deeper into human-computer interactions, the concept of epistemic interaction emerges, aiming to refine these interactions to enhance system adaptability. This approach encourages minor, intentional adjustments in user behaviour to enrich the data available for system learning. This paper introduces epistemic interaction within the context of human-system communication, illustrating how deliberate interaction design can improve system understanding and adaptation. Through concrete examples, we demonstrate the potential of epistemic interaction to significantly advance human-computer interaction by leveraging intuitive human communication strategies to inform system design and functionality, offering a novel pathway for enriching user-system engagements.
Neuro-symbolic is not enough, we need neuro-*semantic*Frank van Harmelen
Neuro-symbolic (NeSy) AI is on the rise. However, simply machine learning on just any symbolic structure is not sufficient to really harvest the gains of NeSy. These will only be gained when the symbolic structures have an actual semantics. I give an operational definition of semantics as “predictable inference”.
All of this illustrated with link prediction over knowledge graphs, but the argument is general.
DevOps and Testing slides at DASA ConnectKari Kakkonen
My and Rik Marselis slides at 30.5.2024 DASA Connect conference. We discuss about what is testing, then what is agile testing and finally what is Testing in DevOps. Finally we had lovely workshop with the participants trying to find out different ways to think about quality and testing in different parts of the DevOps infinity loop.
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Albert Hoitingh
In this session I delve into the encryption technology used in Microsoft 365 and Microsoft Purview. Including the concepts of Customer Key and Double Key Encryption.
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...UiPathCommunity
💥 Speed, accuracy, and scaling – discover the superpowers of GenAI in action with UiPath Document Understanding and Communications Mining™:
See how to accelerate model training and optimize model performance with active learning
Learn about the latest enhancements to out-of-the-box document processing – with little to no training required
Get an exclusive demo of the new family of UiPath LLMs – GenAI models specialized for processing different types of documents and messages
This is a hands-on session specifically designed for automation developers and AI enthusiasts seeking to enhance their knowledge in leveraging the latest intelligent document processing capabilities offered by UiPath.
Speakers:
👨🏫 Andras Palfi, Senior Product Manager, UiPath
👩🏫 Lenka Dulovicova, Product Program Manager, UiPath
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf91mobiles
91mobiles recently conducted a Smart TV Buyer Insights Survey in which we asked over 3,000 respondents about the TV they own, aspects they look at on a new TV, and their TV buying preferences.
3. public class SearchForm extends Form {
private boolean searchPeople;
private String lastSearchValue;
private UITimer pendingTimer;
private long lastSearchTime;
private TextField searchField = new TextField();
private InfiniteContainer ic = new InfiniteContainer() {
@Override
public Component[] fetchComponents(int index, int amount) {
if(searchField.getText().length() < 2) {
return null;
}
int page = index / amount;
if(index % amount > 0) {
page++;
}
List<Component> response = new ArrayList<>();
if(searchPeople) {
List<User> results = ServerAPI.searchPeople(
searchField.getText(), page, amount);
if(results == null) {
return null;
SearchForm
Lets dive into the code starting with the fields and general types…
This is set to true when we are in people search mode
4. public class SearchForm extends Form {
private boolean searchPeople;
private String lastSearchValue;
private UITimer pendingTimer;
private long lastSearchTime;
private TextField searchField = new TextField();
private InfiniteContainer ic = new InfiniteContainer() {
@Override
public Component[] fetchComponents(int index, int amount) {
if(searchField.getText().length() < 2) {
return null;
}
int page = index / amount;
if(index % amount > 0) {
page++;
}
List<Component> response = new ArrayList<>();
if(searchPeople) {
List<User> results = ServerAPI.searchPeople(
searchField.getText(), page, amount);
if(results == null) {
return null;
SearchForm
We use this flag to detect if the search text actually changed
5. public class SearchForm extends Form {
private boolean searchPeople;
private String lastSearchValue;
private UITimer pendingTimer;
private long lastSearchTime;
private TextField searchField = new TextField();
private InfiniteContainer ic = new InfiniteContainer() {
@Override
public Component[] fetchComponents(int index, int amount) {
if(searchField.getText().length() < 2) {
return null;
}
int page = index / amount;
if(index % amount > 0) {
page++;
}
List<Component> response = new ArrayList<>();
if(searchPeople) {
List<User> results = ServerAPI.searchPeople(
searchField.getText(), page, amount);
if(results == null) {
return null;
SearchForm
This timer waits to make sure the user isn't still typing, so we won't send too many search queries at once
6. public class SearchForm extends Form {
private boolean searchPeople;
private String lastSearchValue;
private UITimer pendingTimer;
private long lastSearchTime;
private TextField searchField = new TextField();
private InfiniteContainer ic = new InfiniteContainer() {
@Override
public Component[] fetchComponents(int index, int amount) {
if(searchField.getText().length() < 2) {
return null;
}
int page = index / amount;
if(index % amount > 0) {
page++;
}
List<Component> response = new ArrayList<>();
if(searchPeople) {
List<User> results = ServerAPI.searchPeople(
searchField.getText(), page, amount);
if(results == null) {
return null;
SearchForm
The time of the last search helps us decide how long we should wait for the upcoming search query so we don't send too many queries
7. public class SearchForm extends Form {
private boolean searchPeople;
private String lastSearchValue;
private UITimer pendingTimer;
private long lastSearchTime;
private TextField searchField = new TextField();
private InfiniteContainer ic = new InfiniteContainer() {
@Override
public Component[] fetchComponents(int index, int amount) {
if(searchField.getText().length() < 2) {
return null;
}
int page = index / amount;
if(index % amount > 0) {
page++;
}
List<Component> response = new ArrayList<>();
if(searchPeople) {
List<User> results = ServerAPI.searchPeople(
searchField.getText(), page, amount);
if(results == null) {
return null;
SearchForm
This is the search text field where the user can type
8. public class SearchForm extends Form {
private boolean searchPeople;
private String lastSearchValue;
private UITimer pendingTimer;
private long lastSearchTime;
private TextField searchField = new TextField();
private InfiniteContainer ic = new InfiniteContainer() {
@Override
public Component[] fetchComponents(int index, int amount) {
if(searchField.getText().length() < 2) {
return null;
}
int page = index / amount;
if(index % amount > 0) {
page++;
}
List<Component> response = new ArrayList<>();
if(searchPeople) {
List<User> results = ServerAPI.searchPeople(
searchField.getText(), page, amount);
if(results == null) {
return null;
SearchForm
Search results add up into the InfiniteContainer for paging/refresh capabilities
9. public class SearchForm extends Form {
private boolean searchPeople;
private String lastSearchValue;
private UITimer pendingTimer;
private long lastSearchTime;
private TextField searchField = new TextField();
private InfiniteContainer ic = new InfiniteContainer() {
@Override
public Component[] fetchComponents(int index, int amount) {
if(searchField.getText().length() < 2) {
return null;
}
int page = index / amount;
if(index % amount > 0) {
page++;
}
List<Component> response = new ArrayList<>();
if(searchPeople) {
List<User> results = ServerAPI.searchPeople(
searchField.getText(), page, amount);
if(results == null) {
return null;
SearchForm
If search text is less than 2 characters we shouldn't start searching
10. public class SearchForm extends Form {
private boolean searchPeople;
private String lastSearchValue;
private UITimer pendingTimer;
private long lastSearchTime;
private TextField searchField = new TextField();
private InfiniteContainer ic = new InfiniteContainer() {
@Override
public Component[] fetchComponents(int index, int amount) {
if(searchField.getText().length() < 2) {
return null;
}
int page = index / amount;
if(index % amount > 0) {
page++;
}
List<Component> response = new ArrayList<>();
if(searchPeople) {
List<User> results = ServerAPI.searchPeople(
searchField.getText(), page, amount);
if(results == null) {
return null;
SearchForm
This is the standard page calculation logic that we have in other InfiniteContainer classes
11. }
int page = index / amount;
if(index % amount > 0) {
page++;
}
List<Component> response = new ArrayList<>();
if(searchPeople) {
List<User> results = ServerAPI.searchPeople(
searchField.getText(), page, amount);
if(results == null) {
return null;
}
for(User u : results) {
response.add(createEntry(u));
}
} else {
List<Post> results = ServerAPI.searchPosts(
searchField.getText(), page, amount);
if(results == null) {
return null;
}
for(Post u : results) {
response.add(createEntry(u));
}
}
SearchForm
We build results for people or posts in the same way, there are 2 createEntry methods that cover the logic for both cases
12. List<User> results = ServerAPI.searchPeople(
searchField.getText(), page, amount);
if(results == null) {
return null;
}
for(User u : results) {
response.add(createEntry(u));
}
} else {
List<Post> results = ServerAPI.searchPosts(
searchField.getText(), page, amount);
if(results == null) {
return null;
}
for(Post u : results) {
response.add(createEntry(u));
}
}
if(response.isEmpty()) {
return null;
}
return UIUtils.toArray(response);
}
};
SearchForm
The resulting components are returned on null in the case of an empty set. This is pretty direct and should be relatively obvious, the two big pieces that are obviously
missing from this code are the createEntry methods so lets get to them…
13. });
return;
}
}
lastSearchTime = System.currentTimeMillis();
ic.refresh();
}
}
private Component createEntry(User u) {
MultiButton mb = new MultiButton(u.fullName());
mb.setIcon(u.getAvatar(8));
mb.addActionListener(e -> new UserForm(u).show());
return mb;
}
private Component createEntry(Post p) {
MultiButton mb = new MultiButton(p.title.get());
mb.setTextLine2(p.content.get());
mb.setIcon(p.user.get().getAvatar(8));
mb.addActionListener(e -> new PostForm(p).show());
return mb;
}
}
SearchForm
The version that accepts the User object just creates a MultiButton for that. The same is true for the post entry
14. });
return;
}
}
lastSearchTime = System.currentTimeMillis();
ic.refresh();
}
}
private Component createEntry(User u) {
MultiButton mb = new MultiButton(u.fullName());
mb.setIcon(u.getAvatar(8));
mb.addActionListener(e -> new UserForm(u).show());
return mb;
}
private Component createEntry(Post p) {
MultiButton mb = new MultiButton(p.title.get());
mb.setTextLine2(p.content.get());
mb.setIcon(p.user.get().getAvatar(8));
mb.addActionListener(e -> new PostForm(p).show());
return mb;
}
}
SearchForm
I’ll get to the event handling code later, the UserForm & PostForm mentioned here don’t exist yet so I’ll discuss them after finishing the search class.
This is pretty trivial the next step isn't as simple…
15. return UIUtils.toArray(response);
}
};
public SearchForm() {
super(new BorderLayout());
searchField.setUIID("Title");
searchField.getAllStyles().setAlignment(LEFT);
searchField.addDataChangedListener((i, ii) -> updateSearch());
Toolbar tb = getToolbar();
tb.setTitleComponent(searchField);
Form previous = getCurrentForm();
tb.addMaterialCommandToLeftBar("", MATERIAL_CLOSE, e ->
previous.showBack());
tb.addMaterialCommandToRightBar("", MATERIAL_PERSON, e -> {
searchPeople = true;
ic.refresh();
});
tb.addMaterialCommandToRightBar("", MATERIAL_PAGES, e -> {
searchPeople = false;
ic.refresh();
});
add(CENTER, ic);
setEditOnShow(searchField);
}
SearchForm
We use BorderLayout so the InfiniteContainer can fit in the center, there is no other reason
16. return UIUtils.toArray(response);
}
};
public SearchForm() {
super(new BorderLayout());
searchField.setUIID("Title");
searchField.getAllStyles().setAlignment(LEFT);
searchField.addDataChangedListener((i, ii) -> updateSearch());
Toolbar tb = getToolbar();
tb.setTitleComponent(searchField);
Form previous = getCurrentForm();
tb.addMaterialCommandToLeftBar("", MATERIAL_CLOSE, e ->
previous.showBack());
tb.addMaterialCommandToRightBar("", MATERIAL_PERSON, e -> {
searchPeople = true;
ic.refresh();
});
tb.addMaterialCommandToRightBar("", MATERIAL_PAGES, e -> {
searchPeople = false;
ic.refresh();
});
add(CENTER, ic);
setEditOnShow(searchField);
}
SearchForm
The Title UIID makes the search field fit into the title area
17. return UIUtils.toArray(response);
}
};
public SearchForm() {
super(new BorderLayout());
searchField.setUIID("Title");
searchField.getAllStyles().setAlignment(LEFT);
searchField.addDataChangedListener((i, ii) -> updateSearch());
Toolbar tb = getToolbar();
tb.setTitleComponent(searchField);
Form previous = getCurrentForm();
tb.addMaterialCommandToLeftBar("", MATERIAL_CLOSE, e ->
previous.showBack());
tb.addMaterialCommandToRightBar("", MATERIAL_PERSON, e -> {
searchPeople = true;
ic.refresh();
});
tb.addMaterialCommandToRightBar("", MATERIAL_PAGES, e -> {
searchPeople = false;
ic.refresh();
});
add(CENTER, ic);
setEditOnShow(searchField);
}
SearchForm
In iOS the title is centered by default and that doesn't look good while editing so we left align explicitly for this case
18. return UIUtils.toArray(response);
}
};
public SearchForm() {
super(new BorderLayout());
searchField.setUIID("Title");
searchField.getAllStyles().setAlignment(LEFT);
searchField.addDataChangedListener((i, ii) -> updateSearch());
Toolbar tb = getToolbar();
tb.setTitleComponent(searchField);
Form previous = getCurrentForm();
tb.addMaterialCommandToLeftBar("", MATERIAL_CLOSE, e ->
previous.showBack());
tb.addMaterialCommandToRightBar("", MATERIAL_PERSON, e -> {
searchPeople = true;
ic.refresh();
});
tb.addMaterialCommandToRightBar("", MATERIAL_PAGES, e -> {
searchPeople = false;
ic.refresh();
});
add(CENTER, ic);
setEditOnShow(searchField);
}
SearchForm
This is the search operation, with every change to the text field we call the updateSearch method which performs the actual search
19. return UIUtils.toArray(response);
}
};
public SearchForm() {
super(new BorderLayout());
searchField.setUIID("Title");
searchField.getAllStyles().setAlignment(LEFT);
searchField.addDataChangedListener((i, ii) -> updateSearch());
Toolbar tb = getToolbar();
tb.setTitleComponent(searchField);
Form previous = getCurrentForm();
tb.addMaterialCommandToLeftBar("", MATERIAL_CLOSE, e ->
previous.showBack());
tb.addMaterialCommandToRightBar("", MATERIAL_PERSON, e -> {
searchPeople = true;
ic.refresh();
});
tb.addMaterialCommandToRightBar("", MATERIAL_PAGES, e -> {
searchPeople = false;
ic.refresh();
});
add(CENTER, ic);
setEditOnShow(searchField);
}
SearchForm
setTitleComponent places the component in the title area instead of the label that's there by default
20. return UIUtils.toArray(response);
}
};
public SearchForm() {
super(new BorderLayout());
searchField.setUIID("Title");
searchField.getAllStyles().setAlignment(LEFT);
searchField.addDataChangedListener((i, ii) -> updateSearch());
Toolbar tb = getToolbar();
tb.setTitleComponent(searchField);
Form previous = getCurrentForm();
tb.addMaterialCommandToLeftBar("", MATERIAL_CLOSE, e ->
previous.showBack());
tb.addMaterialCommandToRightBar("", MATERIAL_PERSON, e -> {
searchPeople = true;
ic.refresh();
});
tb.addMaterialCommandToRightBar("", MATERIAL_PAGES, e -> {
searchPeople = false;
ic.refresh();
});
add(CENTER, ic);
setEditOnShow(searchField);
}
SearchForm
This closes the search form by going to the previous form
21. return UIUtils.toArray(response);
}
};
public SearchForm() {
super(new BorderLayout());
searchField.setUIID("Title");
searchField.getAllStyles().setAlignment(LEFT);
searchField.addDataChangedListener((i, ii) -> updateSearch());
Toolbar tb = getToolbar();
tb.setTitleComponent(searchField);
Form previous = getCurrentForm();
tb.addMaterialCommandToLeftBar("", MATERIAL_CLOSE, e ->
previous.showBack());
tb.addMaterialCommandToRightBar("", MATERIAL_PERSON, e -> {
searchPeople = true;
ic.refresh();
});
tb.addMaterialCommandToRightBar("", MATERIAL_PAGES, e -> {
searchPeople = false;
ic.refresh();
});
add(CENTER, ic);
setEditOnShow(searchField);
}
SearchForm
These are the two buttons in the title area that let us toggle people & post search modes. We invoke refresh when there is a change which triggers a call to
fetchComponents in the InfiniteContainer for the first page
22. return UIUtils.toArray(response);
}
};
public SearchForm() {
super(new BorderLayout());
searchField.setUIID("Title");
searchField.getAllStyles().setAlignment(LEFT);
searchField.addDataChangedListener((i, ii) -> updateSearch());
Toolbar tb = getToolbar();
tb.setTitleComponent(searchField);
Form previous = getCurrentForm();
tb.addMaterialCommandToLeftBar("", MATERIAL_CLOSE, e ->
previous.showBack());
tb.addMaterialCommandToRightBar("", MATERIAL_PERSON, e -> {
searchPeople = true;
ic.refresh();
});
tb.addMaterialCommandToRightBar("", MATERIAL_PAGES, e -> {
searchPeople = false;
ic.refresh();
});
add(CENTER, ic);
setEditOnShow(searchField);
}
SearchForm
When we show the form the search field will instantly launch into editing mode, this is important with a virtual keyboard so it won't just have focus it will actually be in edit
mode
23. add(CENTER, ic);
setEditOnShow(searchField);
}
private void updateSearch() {
String text = searchField.getText();
if(text.length() > 2) {
if(lastSearchValue != null) {
if(lastSearchValue.equalsIgnoreCase(text)) {
return;
}
if(pendingTimer != null) {
pendingTimer.cancel();
}
long t = System.currentTimeMillis();
if(t - lastSearchTime < 800) {
pendingTimer = UITimer.timer((int)(t - lastSearchTime),
false, this, () -> {
lastSearchTime = System.currentTimeMillis();
ic.refresh();
});
return;
}
}
lastSearchTime = System.currentTimeMillis();
ic.refresh();
SearchForm
This leads us to the updateSearch() method which performs the actual search logic
24. add(CENTER, ic);
setEditOnShow(searchField);
}
private void updateSearch() {
String text = searchField.getText();
if(text.length() > 2) {
if(lastSearchValue != null) {
if(lastSearchValue.equalsIgnoreCase(text)) {
return;
}
if(pendingTimer != null) {
pendingTimer.cancel();
}
long t = System.currentTimeMillis();
if(t - lastSearchTime < 800) {
pendingTimer = UITimer.timer((int)(t - lastSearchTime),
false, this, () -> {
lastSearchTime = System.currentTimeMillis();
ic.refresh();
});
return;
}
}
lastSearchTime = System.currentTimeMillis();
ic.refresh();
SearchForm
If the text didn't change we don't do anything
25. add(CENTER, ic);
setEditOnShow(searchField);
}
private void updateSearch() {
String text = searchField.getText();
if(text.length() > 2) {
if(lastSearchValue != null) {
if(lastSearchValue.equalsIgnoreCase(text)) {
return;
}
if(pendingTimer != null) {
pendingTimer.cancel();
}
long t = System.currentTimeMillis();
if(t - lastSearchTime < 800) {
pendingTimer = UITimer.timer((int)(t - lastSearchTime),
false, this, () -> {
lastSearchTime = System.currentTimeMillis();
ic.refresh();
});
return;
}
}
lastSearchTime = System.currentTimeMillis();
ic.refresh();
SearchForm
If we have a search pending we kill that search request, since this all runs on the EDT this is a search that didn't start yet
26. add(CENTER, ic);
setEditOnShow(searchField);
}
private void updateSearch() {
String text = searchField.getText();
if(text.length() > 2) {
if(lastSearchValue != null) {
if(lastSearchValue.equalsIgnoreCase(text)) {
return;
}
if(pendingTimer != null) {
pendingTimer.cancel();
}
long t = System.currentTimeMillis();
if(t - lastSearchTime < 800) {
pendingTimer = UITimer.timer((int)(t - lastSearchTime),
false, this, () -> {
lastSearchTime = System.currentTimeMillis();
ic.refresh();
});
return;
}
}
lastSearchTime = System.currentTimeMillis();
ic.refresh();
SearchForm
If we already started a search we make sure it wasn't too soon, otherwise we'll postpone this search for later
27. add(CENTER, ic);
setEditOnShow(searchField);
}
private void updateSearch() {
String text = searchField.getText();
if(text.length() > 2) {
if(lastSearchValue != null) {
if(lastSearchValue.equalsIgnoreCase(text)) {
return;
}
if(pendingTimer != null) {
pendingTimer.cancel();
}
long t = System.currentTimeMillis();
if(t - lastSearchTime < 800) {
pendingTimer = UITimer.timer((int)(t - lastSearchTime),
false, this, () -> {
lastSearchTime = System.currentTimeMillis();
ic.refresh();
});
return;
}
}
lastSearchTime = System.currentTimeMillis();
ic.refresh();
SearchForm
When the timer elapses we update the search time and refresh, notice that since this is a UITimer the elapsing happens on the EDT
28. String text = searchField.getText();
if(text.length() > 2) {
if(lastSearchValue != null) {
if(lastSearchValue.equalsIgnoreCase(text)) {
return;
}
if(pendingTimer != null) {
pendingTimer.cancel();
}
long t = System.currentTimeMillis();
if(t - lastSearchTime < 800) {
pendingTimer = UITimer.timer((int)(t - lastSearchTime),
false, this, () -> {
lastSearchTime = System.currentTimeMillis();
ic.refresh();
});
return;
}
}
lastSearchTime = System.currentTimeMillis();
ic.refresh();
}
}
private Component createEntry(User u) {
MultiButton mb = new MultiButton(u.fullName());
SearchForm
If there is nothing pending we just do the search right now and refresh the InfiniteContainer. With this the search form should work and show search results instantly!
29. mainUI.addTab("", MATERIAL_WEB, 5f, new NewsfeedContainer());
FloatingActionButton fab =
FloatingActionButton.createFAB(MATERIAL_IMPORT_CONTACTS);
Container friends = fab.bindFabToContainer(new FriendsContainer());
fab.addActionListener(e -> uploadContacts());
mainUI.addTab("", MATERIAL_PEOPLE_OUTLINE, 5f,
friends);
mainUI.addTab("", MATERIAL_NOTIFICATIONS_NONE,
5f, new NotificationsContainer());
mainUI.addTab("", MATERIAL_MENU, 5f,
new MoreContainer());
add(CENTER, mainUI);
getToolbar().addMaterialCommandToLeftBar("",
MATERIAL_CAMERA_ALT, 4, e -> {});
getToolbar().addMaterialCommandToRightBar("",
MATERIAL_CHAT, 4, e -> {});
Button searchButton = new Button("Search", "TitleSearch");
setMaterialIcon(searchButton, MATERIAL_SEARCH);
getToolbar().setTitleComponent(searchButton);
searchButton.addActionListener(e -> new SearchForm().show());
}
private void uploadContacts() {
MainForm
The one last piece of the puzzle is plugging it into the UI which is actually trivial... We add this line to the MainForm constructor. With that you can now click the search
button and it will actually work with the data from the database.