How do you update a Glass CardScrollView programatically in XE16 (KitKat)?
I have a CardScrollView of cards that display photos from url's. I download the photos from the url's in a background thread and then I want to "refresh" or update the CardScrolView to make the cards display the new images.
I was calling:
cardScrollView.updateViews(true);
In XE12, but in XE16/KitKat that operation is deprecated. So how do you download an image in the background and then update a displayed "Card" with that image? Just calling card.addImage() seems to add a blank image and doesn't display the image.
I've updated my call from the background thread to be:
cardScrollView.getAdapter().notifyDataSetChanged();
Here is the code for the card scroll adapter with
private class SpecialCardsScrollAdapter extends CardScrollAdapter {
#Override
public int getPosition(Object item) {
return specialCardsList.indexOf(item);
}
#Override
public int getCount() {
return specialCardsList.size();
}
#Override
public Object getItem(int position) {
return specialCardsList.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
return specialCardsList.get(position).getView();
}
}
Should I expect that calling cardScrollView.getAdapter().notifyDataSetChanged(); would cause Cards already put into the scrollview to update the image they have stored?
As mentioned in the release notes, use BaseAdapter#notifyDataSetChanged() from your CardScrollAdapter instead.
Related
currently I am working on a page that generates a print view of a specific item. So this means I dont need all the stuff from my MainLayout like Navigation etc.
For this reason I have created a new Layout that only has a placeholder.
Lets call this PrintLayout.aspx:
<sc:placeholder ID="PlPrint" runat="server" key="phPrintOutput"></sc:placeholder>
In the code behind I have a method that fetches the renderings from the item, but I am stuck at the point where I want to copy them to my phPrintOutput Placeholder on the fly:
public void AddPresentationDetailsToPlaceHolder(Item item)
{
List<RenderingReference> renderings = item.Visualization.GetRenderings(Sitecore.Context.Device, false).ToList();
foreach(RenderingReference r in renderings)
{
// How can I apply the renderings on the fly to my phPrintOutput Placeholder??
}
}
Of course it is very important that every sublayout keeps it current datasource.
Any help would be appreciated, thank you all
You only require to add the control to the placeholder. To do so, please see the code below:
public void AddPresentationDetailsToPlaceHolder(Item item)
{
List<RenderingReference> renderings = item.Visualization.GetRenderings(Sitecore.Context.Device, false).ToList();
foreach(RenderingReference r in renderings)
{
if(r.RenderingID == new ID("Rendering Id you want to be displayed on layout"))
{
this.PlPrint.Controls.Add(r.GetControl());
}
}
}
This will automatically add the rendering to the layout.
I am very new sitecore, working with sitecore 7.
The question is when I am in a page editor, when I delete an item using the floating menu 'delete' function, It just deletes the item.
Customer requirement is to add a confirmation box here. Something like 'are you sure to delete'. and two typical buttons(yes/cancel).
is that even possible? any help would be appreciated.
EDIT:
In the picture below, The red cross, is a delete/remove button. If I click it just deletes. I want to show confirmation upon clicking the button.
EDIT 2:
Ok, I am writing a custom command.
I have added a new button. The target is this new button will ask if the user wants to remove the component or not. And if user says 'yes' it will do the same as the default built in remove button does.
Code:
public class RemoveWithNoti:Sitecore.Shell.Applications.WebEdit.Commands.WebEditCommand
{
public override void Execute(CommandContext context)
{
Context.ClientPage.Start(this, "Run", context.Parameters);
}
protected static void Run(ClientPipelineArgs args)
{
if (args.IsPostBack)
{
if (args.HasResult)
{
//Here I need to call "chrome:rendering:delete" this . I just dont know how to!!
}
}
else
{
SheerResponse.Confirm("Are you certain that you want to remove this component");
args.WaitForPostBack();
}
}
}
How do I call chrome:rendering:delete from code??
The "chrome:rendering:delete" event is handled on the client side by javascript. Here is the exact places:
/sitecore/shell/Applications/Page Modes/ChromeTypes/RenderingChromeType.js file:
handleMessage: function(message, params, sender) {
switch (message) {
...
case "chrome:rendering:delete":
this.deleteControl();
break;
...
},
You can do something like this in the same file:
deleteControl: function() {
if(confirm('Are you sure to remove this component?')){
var placeholder = this.getPlaceholder();
if (placeholder) {
placeholder.type.deleteControl(this.chrome);
}
}
}
Steps, I have used to create my first Google Glass GDK App
New Project > Application name, company domain > Next > Glass (Glass Development Kit Preview (Google Inc.) (API 19)) > Next > Immersion Activity
ImmersionActivity.java:
public class ImmersionActivity extends Activity {
/**
* {#link CardScrollView} to use as the main content view.
*/
private CardScrollView mCardScroller;
private View mView;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
mView = buildView();
mCardScroller = new CardScrollView(this);
mCardScroller.setAdapter(new CardScrollAdapter() {
#Override
public int getCount() {
return 1;
}
#Override
public Object getItem(int position) {
return mView;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
return mView;
}
#Override
public int getPosition(Object item) {
if (mView.equals(item)) {
return 0;
}
return AdapterView.INVALID_POSITION;
}
});
// Handle the TAP event.
mCardScroller.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Plays disallowed sound to indicate that TAP actions are not supported.
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
am.playSoundEffect(Sounds.DISALLOWED);
}
});
setContentView(mCardScroller);
}
#Override
protected void onResume() {
super.onResume();
mCardScroller.activate();
}
#Override
protected void onPause() {
mCardScroller.deactivate();
super.onPause();
}
/**
* Builds a Glass styled "Hello World!" view using the {#link CardBuilder} class.
*/
private View buildView() {
CardBuilder card = new CardBuilder(this, CardBuilder.Layout.TEXT);
card.setText(R.string.hello_world);
return card.getView();
}
}
Manifest.xml:
<activity
android:name=".ImmersionActivity"
android:icon="#drawable/ic_glass_logo"
android:label="#string/title_activity_immersion" >
<intent-filter>
<action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
</intent-filter>
<meta-data
android:name="com.google.android.glass.VoiceTrigger"
android:resource="#xml/voice_trigger" />
</activity>
voice_trigger.xml:
<trigger command="SHOW_ME_A_DEMO" />
Now, what i have understood, we can run this app by trigger voice command "SHOW ME A DEMO", Is that right or wrong ?
And is there any way to run Glass GDK app on Android Emulator using Android Studio ?
Now, what i have understood, we can run this app by trigger voice command "SHOW ME A DEMO", Is that right or wrong ?
It's correct. YOu can even configure this trigger and use other commands.
And is there any way to run Glass GDK app on Android Emulator using Android Studio ?
No you can't. Only Tablet, Phone, Wear (watches) and TV devices are available on the Android Virtual Device Manager.
Now, what i have understood, we can run this app by trigger voice command "SHOW ME A DEMO", Is that right or wrong ?
yes you could run a app with the trigger set as command = "Show_me_a_demo"
But with this you are only able to run it from the speak menu.
I would turn it into
<trigger keyword="#string/app_name"/>
you could use any keyword you want but with this it would show up in the application menu as well as on the speak menu. The name that would show would be whatever you named your app.
It would also be a good idea to add <uses-permission android:name="com.google.android.glass.permission.DEVELOPMENT" />
to your manifest. To make sure the custom commands work
there are no emulators for the glass available as of now.
My Glass app is very simple. I have one static card and I set its text and display it in the overridden "onCreate()" method of my Activity:
myCard.setText("First text");
View cardView = myCard.getView();
// Display the card we just created
setContentView(cardView);
I want to sleep for 5 seconds then display "Second Text" to the user. An earlier question on StackExchange discussed that you get a new view as above, and call setContentView() again.
This is fine so far, but my naive question is, where do I sleep and reset the content view? Obviously I can't sleep in "onCreate()" or "onStart()" of the activity, because the display has not been rendered for the user yet. I have a simple Service. In the service? Do I create a thread somewhere and use that? Thanks!
No need to start a new thread or sleep. You can do this with Android's Handler.postDelayed method, which posts a task to be executed on the UI thread at a later time.
public class MyActivity {
private Handler mHandler = new Handler();
#Override
protected boolean onCreate() {
myCard.setText("First text");
View cardView = myCard.getView();
// Display the card we just created
setContentView(cardView);
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
updateCard();
}
}, 5000 /* 5 sec in millis */);
}
private void updateCard() {
// update the card with "Second text"
}
}
I want to be able to right click on a content item in Sitecore and then select something like "Run My App" in the context menu. Then in the app that runs I need to be able to reference the content item that was right clicked. Is this possible?
Yes you can do this, its not as hard as it sounds.
You want to drop into the Core database and open up the content editor. The right click menu is defined within the sitecore/content/Applications/Content Editor/Context Menus/Default
The items within that folder are what you see when you right-click an item in the tree. So you can add a new item there with a template of Menu Item.
If you look at the existing ones, most of them send a message to the Sitecore Desktop. These messages are the commands defined in /App_Config/Commands.config. I can't see anything in there that would just launch another Sitecore application, so you would need to create a new command to do that. To create one, just inherit from the Sitecore.Shell.Framework.Commands.Command class. That passes in a CommandContext which will holds a collection of Items.
public class DemoCommand: Command
{
#region Overrides of Command
/// <summary>
/// Executes the command in the specified context.
/// </summary>
/// <param name="context">The context.</param>
public override void Execute(CommandContext context)
{
Assert.ArgumentNotNull(context, "context");
var parameters = new NameValueCollection();
if (context.Items != null && context.Items.Length == 1)
{
var item = context.Items[0];
parameters["id"] = item.ID.ToString();
}
Context.ClientPage.Start(this, "Run", parameters);
}
#endregion
public CommandState QueryStat(CommandContext context)
{
Assert.ArgumentNotNull(context, "context");
return CommandState.Enabled;
}
protected static void Run(ClientPipelineArgs args)
{
Assert.ArgumentNotNull(args, "args");
SheerResponse.CheckModified(false);
SheerResponse.Broadcast(
SheerResponse.ShowModalDialog(
"[Path to your application here]"
),
"Shell");
}
}
To get the item passed over, in your message call - just pass the variable $Target.
So the field Message in the Menu Item would be something like:
item:runMyApplication(id=$Target)
Hope that makes sense :)