WICKET: Updating a self-made Panel - refresh

ive got the following Problem:
my self-made video-class (extending Panel) doesnt get updated, if its model changes.
Thats the current state:
I got a Class "A" with a ListChoice. This Class creates the Panel "descrPanel", which gets a Model, containing the current selected Item of the ListChoice. It is updated, when the User selects something in the ListChoice (The ListChoice got an AjaxBehaviour, updating the descrPanel via target.add(descrPanel)):
Class A:
PropertyModel<Exercise> currExerciseModel = new PropertyModel<Exercise>(this,"selectedExercise");
final ExerciseDescriptionPanel descrPanel = new ExerciseDescriptionPanel("descrPanelTag", currExerciseModel);
descrPanel.setOutputMarkupId(true);
In Class ExerciseDescriptionPanel, i inserted my self-made Video-Class (extending Panel). Also i inserted a MultiLineLabel:
Class ExerciseDescriptionPanel
public class ExerciseDescriptionPanel extends Panel {
private IModel<Exercise> model;
private Exercise exercise;
public ExerciseDescriptionPanel(String id, IModel<Exercise> model) {
super(id, model);
this.model = model;
MultiLineLabel mll = new MultiLineLabel("mll", new Model() {
#Override
public String getObject() {
if (ExerciseDescriptionPanel.this.getModel().getObject() != null){
return ExerciseDescriptionPanel.this.getModel().getObject().getDescription();
}
else return "";
}
});
add(mll);
Video video = new Video("myVideo", new Model<Exercise>(){
#Override
public Exercise getObject() {
if (ExerciseDescriptionPanel.this.getModel().getObject() != null){
return ExerciseDescriptionPanel.this.getModel().getObject();
}
else return new Exercise();
}
});
add(video);
}
Well, what i dont understand is: While the Description is updated based on the current selection of the ListChoice, the Video-Class just ignores it and keeps returning the "new Exercise()", which schould only be returned at the first load of the ListChoice, when no selection is made.
I also provide you the Video-Class:
Class Video
public class Video extends Panel{
private IModel<Exercise> model;
public Video(String id, IModel<Exercise> model) {
super(id, model);
String src = ((Exercise)model.getObject()).getVideo();
String startPicDest = ((Exercise)model.getObject()).getPicture();
WebMarkupContainer flashSrc = new WebMarkupContainer("flashSrcTag");
flashSrc.add(new AttributeModifier("value", "config={'playlist':['" +
startPicDest +"',{'url':'"+ src +"','autoPlay':false}]}"));
this.add(flashSrc);
setOutputMarkupId(true);
}
}
Ive been searching through the internet for hours now, without finding anything helpful.
Hope you guys are able to give me some solution to this problem. Thanks in regard.
Greetings

You're pulling the exercise out of the model once only:
public Video(String id, IModel<Exercise> model) {
super(id, model);
String src = ((Exercise)model.getObject()).getVideo();
...
}
How is this supposed to be up-to-date when the exercise changes later on?
You have to get the actual value for each render:
WebMarkupContainer flashSrc = new WebMarkupContainer("flashSrcTag") {
public void onComponentTag(ComponentTag tag) {
Exercise temp = (Exercise)model.getObject();
String src = temp.getVideo();
String startPicDest = temp.getPicture();
tag.put("value", String.format("config={'playlist':['%s',{'url':'%s','autoPlay':false}]}", startPicDest, src));
}
};

NOTE: Please ignore this humble try to help you, svenmeier's answer is way better than mine.
I'm not 100% sure if this is true, but could it be related to the difference between your Video being a MarkupContainer and the MultiLineLabel being a WebComponent?
Both the Video and the MultiLineLabel are added to the ExerciseDescriptionPanel in its constructor. If I understand the Wicket documentation correctly, as long as the surrounding Page and thus the ExerciseDescriptionPanel stay the same instance, the markup of the Video will not be regenerated. It says:
A Page renders itself by rendering its associated markup (the html file that sits next to the Page). As MarkupContainer (the superclass for Page) iterates through the markup stream for the associated markup, it looks up components attached to the tags in the markup by id. Since the MarkupContainer (in this case a Page) is already constructed and initialized by onBeginRequest(), the child for each tag should be available in the container. Once the Component is retrieved, it's render() method is called.
Maybe you calling modelChanged() on your Video once you change the Model of your ExerciseDescriptionPanel could indicate that the markup has to be refreshed.

Related

Flutter - how to store lists of Strings: (GetStorage or Shared Preferences). using android

So, I have come across a solution for this problem using Get_storage thanks to a couple of great explanations about the topic. I managed to work with getx and the Provider package to save data when adding new stuff and reading it when starting the application (thats the behavior i'm going for here). Said that, i'm having a hard time trying to remove data from memory.
Context
The project is a to-do list app, the front end is working perfectly, but when it comes to storage it gets more complicated. The thing is that i'm very new to flutter and mobile development, i recieved some help but this kind of stuff is still foggy in my brain, i could not remove data using the same logic. When i called box.Remove('key') like the docs say, my ENTIRE list got removed. I don't have a single clue why that happaned.
And so i wonder if i could understand it more by reading through some more explanations, i know Shared Preferences is a great deal do work with this kind of situation, but i would also be confortable with a solution using get_storage since i'm more familiar with it.
the code:\
I'm calling these lists inside a listView on a different file with the help of Provider - -
List<Task> _tasks = [
Task(
name: "Title",
description: "Description",
),
];
Adding tasks to my ListView - -
void add(String newTitle, newDesc) {
final task = Task(name: newTitle, description: newDesc);
_tasks.add(task);
notifyListeners();
}
Here is the removal of a task from the ListView - -
void removeTasks(Task task) {
_tasks.remove(task);
notifyListeners();
}
I tried to implement a logic to write and read data, it worked. But i also tried to use this removeTasks method to remove from storage as well by calling box.Remove('tasks'); ('tasks' was the key passed to the writing and reading methods). It removed everything from memory since my listview got empty.
Since i'm not that experienced, i went through the documentation and could understand some of the SharedPreferences Explanation (same with got_storage) but i'm having a hard time when trying to apply it to my code.
I would appreciate any help using get_storage OR shared preferences to this problem.
Where i'm calling the deletion:
// bool variables that control the state of the screen
// since i can change it to show done tasks or on goind tasks
// dont mind that, i think its irrelevant to the problem.
//
bool isActiveDoing = true;
bool isActiveDone = false;
List finalArray = []; //it will store the tasks
class TaskList extends StatefulWidget {
#override
_TaskListState createState() => _TaskListState();
}
class _TaskListState extends State<TaskList> {
#override
Widget build(BuildContext context) {
//dont mind the if else as well, its not part of the problem
//just using it to handle the state of the screen
if (isActiveDoing) {
finalArray = Provider.of<TasksFunctions>(context).tasks;
}
//TasksFunctions is a class with methods on regards to the storage
//it contains add tasks, remove, etc... i'm using provider to
//link those to the screens with the notifyListeners
if (isActiveDone) {
finalArray = Provider.of<TasksFunctions>(context).doneTasks;
}
//now here is where i call the class tha has the deletion method
return Consumer<TasksFunctions>(
builder: (context, tasksFunctions, child) {
return ListView.builder(
//list view tha has all the tasks
itemCount: finalArray.length,
itemBuilder: (context, index) {
final task = finalArray[index];
//using the slidableWidget to wrap the deletion method
return SlidableWidget(
onDismissed: (action) {
if (isActiveDoing) {
Provider.of<TasksFunctions>(context, listen: false)
.removeTask(task);
//so here is where i'm deleting those tasks, calling that method
//listed up on this post
}
if (isActiveDone {
Provider.of<TasksFunctions>(context, listen: false)
.removeDone(task);
}
},
);
},
);
},
);
}
}
So i spent some time translating the code, but i think that it does not match any of flutter's good practices principles.
I also tried calling storageList.remove(task); and then rewriting it with the box.write('tasks', storageList); but nothing was removed from the memory (maybe because i didn't loop through the whole storageLists searching for the right index i guess)
Sounds like your code is based on my answer to your original question about this.
If that's the case, then the key tasks is the key to the entire list of maps, not a single map or Task. So it's behaving as expected when it wipes all of your tasks.
In order to persist any changes, you'd have to remove that particular map (Task) from storageList then overwrite the box again with box.write('tasks', storageList); It will save over the same list of maps and persist any deletions you made.
If you share your code where you're trying to delete the task and whats going on around it I can give you a more specific example.
EDIT: Answering question in comments.
If you wanted to go the UniqueKey route you wouldn't need the index at all. You could do something like this.
class Task {
final String name;
final String description;
final String key; // not an actual Key but will take the String value of a UniqueKey
Task({this.key, this.name, this.description});
}
When you add a new Task it would look like this.
final task = Task(
description: 'test description',
name: 'test name',
key: UniqueKey().toString());
Then you could use a Map of maps instead of a list of maps and use the key for both.
Map storageList = {};
void addAndStoreTask(Task task) {
_tasks.add(task);
final Map storageMap = {}; // temporary map that gets added to storage
storageMap['name'] = task.name;
storageMap['description'] = task.description;
storageMap['key'] = task.key;
storageList[task.key] = storageMap; // adding temp map to storageList
box.write('tasks', storageList); // adding map of maps to storage
}
Then your restore function would look like this:
void restoreTasks() {
storageList = box.read('tasks'); // initializing list from storage
storageList.forEach((key, value) { // value here is each individual map that was stored
final task =
Task(name: value['name'], description: value['description'], key: key);
_tasks.add(task);
});
}
Then when you go to delete, you iterate through the list and find the matching key.

wicket I'm using three panels, but only one is displayed at a time, when the third panel is added to the code the second never appears

I have a Modal class, when this modal is opened, it shows a panel asking the user if the user wants to proceed with the operation. If the user selects Yes the request is sent to the DB, which takes some time, during this time the first panel should be replaced by the second (which displays a spinner). This indeed happens if we do not use the third panel. Although I want to replace the second panel by the third panel in order to inform the user if the operation was successful or not (which depends of the message object,if it is null or have an error message).
So when I use addNewPanel(panel3, target) I never see panel2. I put a thread.sleep(5000) instruction after addNewPanel(panel2, target) and even so, this panel didn't appeared, I only get the initial and panel3 in the end.
If I do not use panel3 I see panel2.
Does anyone have an idea why is this happening?
Below I have the code of the Modal class
public class DetailsModal2 extends Modal<IModel<UserDomain>>{
#SpringBean
private IService service;
private BootstrapAjaxLink<String> noButton;
private ResponseMessage message;
private ProcessingPanel panel2;
private AlertPanel panel3;
private Panel replacedPanel;
public DetailsModal2(String id, IModel<UserDomain> model){
super(id);
replacedPanel = new AreYouSure("replacedPanel");
replacedPanel.setOutputMarkupId(true);
add(replacedPanel);
panel2 = new ProcessingPanel("replacedPanel");
panel3 = new AlertPanel("replacedPanel");
addButton(new BootstrapAjaxLink<String>("button", null, Buttons.Type.Warning, new ResourceModel("details")){
private static final long serialVersionUID = 1L;
#Override
public void onClick(AjaxRequestTarget target) {
// TODO Auto-generated method stub
//I was expecting to see this panel
addNewPanel(panel2,target);
// this puts this button invisible
this.setVisible(false);
target.add(this);
//this changes the label of the No button to Close
noButton.setLabel(Model.of("Close"));
target.add(noButton);
if(!service.retrieveData())
{
message = service.addUser("X");
if(message == null){
panel3.updateClassAndText(true);
addNewPanel(panel3,target);
}
else {
panel3.updateClassAndText(false);
addNewPanel(panel3,target);
System.out.println(""+ message.getError());
}
}//close if
else if(service.retrieveData())
{
message = service.removeUser("X");
if(message == null){
panel3.updateClassAndText(true);
addNewPanel(panel3,target);
}
else{
panel3.updateClassAndText(false);
addNewPanel(panel3,target);
System.out.println(""+ message.getError());
}
}
else{
System.out.println("It was not possible to access the db");
}
}
}
});
noButton = new BootstrapAjaxLink<String>("button", null, Buttons.Type.Primary){
private static final long serialVersionUID = 1L;
#Override
public void onClick(AjaxRequestTarget target) {
close(target);
}
}.setLabel(Model.of("No"));
addButton(noButton);
}
public void addNewPanel(Panel addpanel, AjaxRequestTarget target ){
Panel newPanel = null;
newPanel = addpanel;
newPanel.setOutputMarkupId(true);
replacedPanel.replaceWith(newPanel);
target.add(newPanel);
}
}//close class
HTML
<wicket:extend>
<div><span wicket:id="replacedPanel"> </span></div>
</wicket:extend>
Wicket atmosphere is deprecated from wicket 8 and will not be supported anymore, so do not use it ..

Sitecore dictionary items Editable via page editor

I am trying to implement Sitecore Dictionary items to be edited via PageEditor.
This is my approach.. Just need your thoughts and suggestions.
To make it simple and not to mess up with the pipelines, here is a simple way of what I am doing.
Normally you do a sitecore translate for example,
#Sitecore.Globalization.Translate.Text("SomeKey")
You can encapsulate the Translate to a custom class which might look like
public static class CustomTranslate
{
public static string Text(string key)
{
if (Sitecore.Context.PageMode.IsPageEditorEditing)
{
string val = String.Empty;
Item currentItem = Context.Database.GetItem(ResourcesController.ItemLookUp()[key]);
if (currentItem != null)
{
val = FieldRenderer.Render(currentItem, "Phrase");
}
return val;
}
else
return Sitecore.Globalization.Translate.Text(key);
}
}
The CustomTranslate.Text returns a FieldRenderer in PageEdit mode else returns the Sitecore.Globalization.Translate.Text
Then in your code you can refer the translations as
#CustomTranslate.Text("SomeKey")
The Lookup can be a dictionary of Key and Item ID as shown in below code,
public static class ResourceController
{
public static Dictionary ItemLookUp()
{
///get dictionary path..etc.. code not included
//read all sitecore dictionary Items
Sitecore.Data.Items.Item[] items =
Sitecore.Context.Database.SelectItems("fast:" + dictionaryPath +
"//*[##templateid='{6D1CD897-1936-4A3A-A511-289A94C2A7B1}']");
//build a Dictionary<string,string> using sitecore item key and Guid.
items.All(y => { resourceDictionary.Add(y["Key"], y.ID.Guid.ToString()); return true;}
// Key,Guid dictionary
return resourceDictionary;
}
}
A Simpler and much easier approach ! Thoughts, Comments ?

Card not showing; goes straight to home card

I am trying to show a card so I know everything up to that point works. However, when I try to display the card, it just goes straight to the home card. The card I was trying to show was just going to display what was said in the voice recognizer before but that didn't work so I just put plain text and that didn't work either. Application goes - voice trigger --> voice recognizer --> this service:
public class MedMinderService extends Service {
public String MedName;
public String voiceResults;
private static final String TAG = "ShowData";
private static final String LIVE_CARD_ID = "showdata";
public static final String PREFS_NAME = "MyPreferencesFile";
private TimelineManager mTimelineManager;
private LiveCard mLiveCard;
#Override
public void onCreate() {
super.onCreate();
mTimelineManager = TimelineManager.from(this);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
public int onStartCommand(Intent intent, int flags, int startId) {
String voiceResults = intent.getExtras()
.getString(RecognizerIntent.EXTRA_RESULTS);
String MedName = voiceResults; //MedName declared
SharedPreferences MedInfo = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = MedInfo.edit();
editor.putString("MedName", MedName.toString());
editor.commit();
mLiveCard = mTimelineManager.getLiveCard(LIVE_CARD_ID);
Intent i = new Intent(this, ShowDataActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
return START_STICKY;
}
}
The intent at the bottom goes to this activity:
public class ShowDataActivity extends Activity {
private LiveCard mLiveCard;
public static final String PREFS_NAME = "MyPreferencesFile";
private GestureDetector mGestureDetector;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences MedInfo = getSharedPreferences(PREFS_NAME, 0);
Card ShowDataCard = new Card(this);
ShowDataCard.setText("IT WORKS!");
//ShowDataCard.setText(MedInfo.getString("MedName", "your medication"));
View ShowDataCardView = ShowDataCard.toView();
setContentView(ShowDataCardView);
}
The "ShowDataCard" that has been commented out is what I was origonally trying to do with the voice recognition but it wouldn't even work with the text "IT WORKS!"
Again: I am just trying to show a card with the text "IT WORKS"
thanks
The easiest way to get a live card to appear with just text is using widgets that are compatible with RemoteViews. You can find a list of them in the GDK documentation here:
https://developers.google.com/glass/develop/gdk/ui/live-cards
under the Creating low-frequency live cards section.
Here is some sample code (based on your code above) that can get that working quickly:
final String LIVE_CARD_ID = "showdata";
mLiveCard = mTimelineManager.getLiveCard(LIVE_CARD_ID);
RemoteViews remoteViews =
new RemoteViews(getPackageName(), R.layout.layout_helloglass);
mLiveCard.setViews(remoteViews);
// Make sure Glass navigates to LiveCard immediately
mLiveCard.setNonSilent(true);
mLiveCard.publish();
The layout file can look like this for layout_helloglass.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Hello, Glass!" />
</FrameLayout>
If you still want to navigate to another Activity from your LiveCard, you need to associate the Activity with a PendingIntent and then associate that PendingIntent with the LiveCard's action. This would happen immediately before the LiveCard.publish() method:
Intent i = new Intent(this, ShowCardActivity.class);
mLiveCard.setAction(PendingIntent.getActivity(this, 0, i, 0));
That should get you up and running! Hopefully this will help.
There was a bug in the GDK Sneak Peek that prevented voice prompts from creating Services. If one inserted a Log.d() call in a Service's onStartCommand() override, they would discover that it were never called.
This bug has been fixed in the GDK Preview. This behavior should not appear again.
This question was rewritten after the GDK Preview launch to remove this outdated answer. Thanks to user Falcon for notifying me.

LWUIT List works terribly slow

I've faced with the well-known problem in LWUIT. My list component with the checkbox renderer scrolls very slow. If to test my application on emulator it runs quite smoothly (nevertheless I see CPU utilization splashes up to 60% during scroll action), but if to run it on mobile phone it takes a couple of seconds between focus movements.
There's a code of renderer:
public class CheckBoxMultiselectRenderer extends CheckBox implements ListCellRenderer {
public CheckBoxMultiselectRenderer() {
super("");
}
//override
public void repaint() {
}
public Component getListCellRendererComponent(List list, Object value,
int index,boolean isSelected) {
Location loc = (Location)value;
setText(loc.getLocationName());
setFocus(isSelected);
setSelected(loc.isSelected());
return this;
}
public Component getListFocusComponent(List list) {
setText("");
setFocus(true);
getStyle().setBgTransparency(Consts.BG_TRANSPARENCY);
return this;
}
}
that's the code of my form containing the list:
protected void createMarkup() {
Form form = getForm();
form.setLayout(new BorderLayout());
form.setScrollable(false);
Label title = new Label("Choose location zone:");
title.getStyle().setMargin(5, 5, 0, 0);
title.getStyle().setBgTransparency(Consts.BG_TRANSPARENCY);
title.setAlignment(Component.CENTER);
form.addComponent(BorderLayout.NORTH, title);
list = new List(StateKeeper.getLocationsAsList());
list.setFixedSelection(List.FIXED_NONE_CYCLIC);
// list.setSmoothScrolling(true);
list.getStyle().setBgTransparency(0);
list.setListCellRenderer(new CheckBoxMultiselectRenderer());
list.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
// List l = (List)ae.getSource();
// l.requestFocus();
// l.setHandlesInput(true);
Location selItem = (Location)list.getSelectedItem();
selItem.setSelected(!selItem.isSelected());
}
});
form.addComponent(BorderLayout.CENTER, list);
}
I would be very thankful for any help!
We must be so carefull building lwuit List. If we have made something wrong they can work worse than expected. I recommend you to take a look on this
LWUIT Blog ListRender
You can also rewrite your paint method. You list's speed will be increased.