I have a Xamarin Forms App. Which I created a FBShareButton : Button to handle the sharing via custom renderers. This is the code in my renderer:
public class FacebookShareRenderer : ButtonRenderer
{
ShareButton sb;
protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged (e);
sb = new ShareButton(Context);
this.Control.Click += (sender, eargs) => sb.PerformClick();
sb.Click += (sender, eargs) => {
ShareLinkContent.Builder shareLinkContentBuilder = new ShareLinkContent.Builder().
SetContentDescription("Hello").
SetContentTitle("Desc");
shareLinkContentBuilder.SetImageUrl("url");
ShareLinkContent shareLinkContent = shareLinkContentBuilder.Build();
sb.ShareContent = shareLinkContent;
}
};
}
}
The share dialog opens and asks me to right something as I supposed to. However, the content does not appear and when I share they do not show. Any ideas?
I fugired this out; first the SetImageUrl should be a valid url with an Image and second I needed to SetContentUrl also, otherwise it would empty the content.
Related
I need to create a workflow in AEM that for a page (specified as payload) finds all the assets used on the page and uploads a list of them to an external service. So far I have most of the code ready, but business process requires me to use a special code for each of the pages (different for each run of the workflow), so that the list is uploaded to correct place.
That is when I have a question - Can you somehow add more input values for an AEM workflow? Maybe by extending the starting dialog, or adding some special step that takes user input? I need to be able to somehow specify the code when launching the workflow or during its runtime.
I have read a lot of documentation but as this is my first time using workflows, I might be missing something really obvious. I will be grateful for any piece of advice, including a link to a relevant piece of docs.
Yes, that is possible. You need to implement a dialog step in your workflow: https://docs.adobe.com/content/help/en/experience-manager-64/developing/extending-aem/extending-workflows/workflows-step-ref.html#dialog-participant-step
You could:
Create a custom menu entry somewhere in AEM (e.g. Page Editor, /apps/wcm/core/content/editor/_jcr_content/content/items/content/header/items/headerbar/items/pageinfopopover/items/list/items/<my-action>, see under libs for examples)
Create a client-library with the categories="[cq.authoring.editor]". So it is loaded as part of the page editor (and not inside the iframe with your page)
Create a JS-Listener, that opens a dialog if the menu-entry was clicked (see code). You can either use plain Coral UI dialogs, or my example misused a Granite page dialog (Granite reads the data-structure in cq:dialog, and creates a Coral UI component edit-dialog out of it - while Coral is the plain JS UI-framework)
Create a Java-Servlet, that catches your request, and creates the workflow. You could theoretically use the AEM servlet. But I often have to write my own, because it lacks some features.
Here is the JS Listener:
/*global Granite,jQuery,document,window */
(function ($, ns, channel, window) {
"use strict";
var START_WORKFLOW_ACTIVATOR_SELECTOR = ".js-editor-myexample-activator";
function onSuccess() {
ns.ui.helpers.notify({
heading: "Example Workflow",
content: "successfully started",
type: ns.ui.helpers.NOTIFICATION_TYPES.SUCCESS
});
}
function onSubmitFail(event, jqXHR) {
var errorMsg = Granite.I18n.getVar($(jqXHR.responseText).find("#Message").html());
ns.ui.helpers.notify({
heading: "Example Workflow",
content: errorMsg,
type: ns.ui.helpers.NOTIFICATION_TYPES.ERROR
});
}
function onReady() {
// add selector for special servlet to form action-url
var $form = ns.DialogFrame.currentFloatingDialog.find("form");
var action = $form.attr("action");
if (action) {
$form.attr("action", action + ".myexample-selector.html");
}
// register dialog-fail event, to show a relevant error message
$(document).on("dialog-fail", onSubmitFail);
// init your dialog here ...
}
function onClose() {
$(document).off("dialog-fail", onSubmitFail);
}
// Listen for the tap on the 'myexample' activator
channel.on("click", START_WORKFLOW_ACTIVATOR_SELECTOR, function () {
var activator = $(this);
// this is a dirty trick, to use a Granite dialog directly (point to data-structure like in cq:dialog)
var dialogUrl = Granite.HTTP.externalize("/apps/...." + Granite.author.ContentFrame.getContentPath());
var dlg = new ns.ui.Dialog({
getConfig: function () {
return {
src: dialogUrl,
loadingMode: "auto",
layout: "auto"
}
},
getRequestData: function () {
return {};
},
"onSuccess": onSuccess,
"onReady": onReady,
"onClose": onClose
});
ns.DialogFrame.openDialog(dlg);
});
}(jQuery, Granite.author, jQuery(document), window));
And here is the servlet
#Component(service = Servlet.class,
property = {
SLING_SERVLET_RESOURCE_TYPES + "=cq:Page",
SLING_SERVLET_SELECTORS + "=myexample-selector",
SLING_SERVLET_METHODS + "=POST",
SLING_SERVLET_EXTENSIONS + "=html"
})
public class RequestExampleWorkflowServlet extends SlingAllMethodsServlet {
#Override
protected void doPost(#Nonnull SlingHttpServletRequest request, #Nonnull SlingHttpServletResponse response) throws IOException {
final Page page = request.getResource().adaptTo(Page.class);
if (page != null) {
Map<String, Object> wfMetaData = new HashMap<>();
wfMetaData.put("workflowTitle", "Request Translation for " + page.getTitle());
wfMetaData.put("something", "Hello World");
try {
WorkflowSession wfSession = request.getResourceResolver().adaptTo(WorkflowSession.class);
if (wfSession != null) {
WorkflowModel wfModel = wfSession.getModel("/var/workflow/models/example-workflow");
WorkflowData wfData = wfSession.newWorkflowData(PayloadInfo.PAYLOAD_TYPE.JCR_PATH.name(), page.getPath());
wfSession.startWorkflow(wfModel, wfData, wfMetaData);
MyServletUtil.respondSlingStyleHtml(response, HttpServletResponse.SC_OK, "Triggered Example Workflow");
} else {
throw new WorkflowException("Cannot retrieve WorkflowSession");
}
} catch (WorkflowException e) {
MyServletUtil.respondSlingStyleHtml(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
}
} else {
MyServletUtil.respondSlingStyleHtml(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal error - cannot get page");
}
}
}
I am using GWTUpload , the library is in here https://code.google.com/p/gwtupload/
The Example code at client side found on that website has this structure:
// Attach an image to the pictures viewer
private OnLoadPreloadedImageHandler showImage = new OnLoadPreloadedImageHandler() {
public void onLoad(PreloadedImage image) {
//showImageFlowPanel code solution 1
image.setWidth("75px");
showImageFlowPanel.add(image);
}
};
private IUploader.OnFinishUploaderHandler onFinishUploaderHandler = new IUploader.OnFinishUploaderHandler() {
public void onFinish(IUploader uploader) {
if (uploader.getStatus() == Status.SUCCESS) {
new PreloadedImage(uploader.fileUrl(), showImage);
UploadedInfo info = uploader.getServerInfo();
String headShotImageUrl="http://"+Window.Location.getHost()+"/" +"images/uploaded/"+info.message;
//headShotImage code solution 2
if(!"".equals(headShotImageUrl) && UriUtils.isSafeUri(headShotImageUrl)){
headShotImage.setUrl(UriUtils.fromString(headShotImageUrl));
}
}
}
};
The example uses showImageFlowPanel (solution 1) to store the image but I want to store the image inside headShotImage which take the url after user uploaded image successfully, see the headShotImage (solution 2) code above.
Ok, the headShotImage code work fine but I dont know how to remove it when users remove the image. If I use showImageFlowPanel as in the solution 1 then the program remove the image automatically for me and I do not need to do anything.
So my question is "Where to call an Action when user removes an uploaded image in GWTUpload?"
You have to use setOnCancelUploaderHandler. Take a look to this code took from the demo.
// When the user clicks a cancel button we get an event
uploader.addOnCancelUploadHandler (
new IUploader.OnCancelUploaderHandler() {
public void onCancel(IUploader uploader) {
for (String iname : uploader.getServerMessage().getUploadedFieldNames()) {
// loadedImages is an temporary table where we are adding all uploaded files
// indexed by field name
Widget w = loadedImages.get(iname);
if (w != null) {
w.removeFromParent();
loadedImages.remove(uploader.getInputName());
}
}
}
});
I just trying to add add the Facebook integration with my app in Xamarin.Android. For that I found that there is a Component named as Xamarin.Social then I am trying that. Here is my attempt.
Attempt :-
void btnShare_Click(object sender, EventArgs e)
{
try
{
var facebook = new Xamarin.Social.Services.FacebookService()
{
ClientId = AppId,
RedirectUrl = new System.Uri("http://www.facebook.com/connect/login_success.html")
};
// 2. Create an item to share
var item = new Item { Text = "Xamarin.Social is the bomb.com." };
var shareController = facebook.GetShareUI(this, item, result =>
{
if (result.HasFlag(Xamarin.Social.ShareResult.Done))
{
Toast.MakeText(this, "Posted", ToastLength.Long).Show();
}
if (result.HasFlag(Xamarin.Social.ShareResult.Cancelled))
{
Toast.MakeText(this, "Cancelled", ToastLength.Long).Show();
}
});
StartActivity(shareController);
}
catch (Exception exp)
{
}
}
Note :- Facebook login page is opening successfully.
Error :- But I am getting this Forbidded(403) error. the point is this error is not reaching to catch block , but it is shown in a toast notification. so no further details are available.
Does anybody explored this component successfully ?
Any help is appreciated :)
As I mentioned in the comments, I had to many issues using the social plugin, I just used the android share intent, see example below
var shareIntent = new Intent();
shareIntent.SetAction(Intent.ActionSend);
shareIntent.PutExtra(Intent.ExtraText, message); //message is the text you want to share
shareIntent.SetType("text/plain");
StartActivity(shareIntent);
WP8 how to share data from my app to Facebook
or twitter
i want to take screen-shoot of my list-box and then share it on Facebook
i try this code
ShareLinkTask shareLinkTask = new ShareLinkTask();
shareLinkTask.Title = "Code Samples";
shareLinkTask.LinkUri = new Uri("https://www.facebook.com/", UriKind.Absolute);
shareLinkTask.Message = "Here are some great code samples for Windows Phone.";
shareLinkTask.Show();
but it doesnot work
You should not use ShareLinkTask for sharing photos. You should use ShareMediaTask. You can more information and how to implement ShareMediaTask by clicking link I provided herewith.
Here's the code:
CameraCaptureTask cameraCaptureTask = new CameraCaptureTask();
//declare it globally
cameraCaptureTask.Completed += cameraCaptureTask_Completed;
//declare it in Constructor
cameraCaptureTask.Show();
//declare it in any method.
For example, button click event. By using this method, you can capture the list box.
//declare this method anywhere in the cs page
void cameraCaptureTask_Completed(object sender, PhotoResult e)
{
if(e.TaskResult == TaskResult.OK)
{
ShowShareMediaTask(e.OriginalFileName);
}
}
void ShowShareMediaTask(string path)
{
ShareMediaTask shareMediaTask = new ShareMediaTask();
shareMediaTask.FilePath = path;
shareMediaTask.Show();
}
Now, You can easily take screenshot of app's listbox and share it with any of the social networks where user installed on their phone. Cheers.!
I'm running into a problem with my app (ASP.NET MVC 2) where I can't upload files (images in my case). I've changed the web.config to accept up to 20MB, and I'm trying to upload a file that's only 3MB.
The app itself has two ways to upload. The initial upload which starts a Gallery and then an additional upload to append to a Gallery.
The initial works like a charm, but the appending one fails with no explanation. Even if I re-upload the initial image as an append it still fails.
I'm a little stuck on this so I would appreciate any help you guys can offer.
Thanks in advance!
EDIT
If I "hack" the form with Firebug and direct it to the initial upload Url it works, but when it's directing to the Url it should be posting to it fails...
EDIT 2
Per Rob's request, here's the code handling the initial gallery and appending image:
[HttpPost, ValidateAntiForgeryToken]
public RedirectToRouteResult PutGallery( // Move to Ajax
[Bind(Prefix = "Gallery", Include = "ClubId,EventId,RHAccountId,RHCategoryId,Year")] Gallery Gallery,
HttpPostedFileBase File) {
if (ModelState.IsValid && (File.ContentLength > 0)) {
if (Gallery.RHAccountId > 0) {
Gallery.RHUser = this.fdc.RHAccounts.Single(
a =>
(a.RHAccountId == Gallery.RHAccountId)).RHUser;
} else {
if (!this.fdc.RHUsers.Any(
u =>
(u.User.Name == Gallery.Username))) {
if (!this.fdc.Users.Any(
u =>
(u.Name == Gallery.Username))) {
Gallery.RHUser = new RHUser() {
User = new User() {
Name = Gallery.Username
}
};
} else {
Gallery.RHUser = new RHUser() {
User = this.fdc.Users.Single(
u =>
(u.Name == Gallery.Username))
};
};
} else {
Gallery.RHUser = this.fdc.RHUsers.Single(
u =>
(u.User.Name == Gallery.Username));
};
};
Image Image = new Image() {
Gallery = Gallery
};
this.fdc.Galleries.InsertOnSubmit(Gallery);
this.fdc.Images.InsertOnSubmit(Image);
this.fdc.SubmitChanges();
Files.Save(Image.ImageId, File);
return RedirectToAction("Default", "Site");
} else {
return RedirectToAction("Default", "Site");
};
}
[HttpPost, ValidateAntiForgeryToken]
public RedirectToRouteResult PutImage(
[Bind(Prefix = "Image", Include = "GalleryId")] Image Image,
HttpPostedFileBase File) {
Gallery Gallery = this.fdc.Galleries.Single(
g =>
(g.GalleryId == Image.GalleryId));
if (File.ContentLength > 0) {
this.fdc.Images.InsertOnSubmit(Image);
this.fdc.SubmitChanges();
Files.Save(Image.ImageId, File);
};
return RedirectToAction("Gallery", "Site", new {
Category = Gallery.RHCategory.Category.EncodedName,
GalleryId = Gallery.GalleryId
});
}
SIDENOTE:
Could Cassini, VS 2010's built in web server, be the cause?
Ok, so I figured it out, it only took a lengthy install of IIS locally on my machine + the configuration, to have it tell me that I miss-spelled controller as controlls in the routes.
Really annoying that it took all of that to get the real error, so Cassini was partially at fault...
So, the moral of the story is, make sure you spell everything correctly.