POST
|
Thanks for this input @TonghuiMing Yes, I'm using a "Vector polygon" to show a hatch fill. And I can confirm your theory, switching it to a Basic shape solved that issue; the symbol does scale in the ExB app. I would prefer to use the hatch fill however as it works very well in this application. Can you keep us posted on a potential fix for this?
... View more
Wednesday
|
1
|
0
|
19
|
POST
|
I am using a List component to display details about features in a layer in a web map. I am showing the legend symbol using an Image component by connecting it to data and having it dynamically auto-populated. That part works great but I'd like to make the symbol bigger. There is a "Symbol scale" property with a slider but it doesn't appear to change the size of the symbol image. Am I missing anything about what the Symbol scale property does or how to use it? Thanks for any input
... View more
3 weeks ago
|
0
|
2
|
162
|
POST
|
I am converting an image from the HEIC format to jpg in order to upload as an attachment. The ImageObject save method does this but it only returns true or false. I'm getting lots of false returns resulting in a selected image not being available to upload for my users. Is there any way to get more information about why the save operation fails? No errors are thrown and nothing is written to the console. I am checking that the folder where the saved file is going exists and that we have access. The photo sharing setting is set correctly. Am I missing anything here? Thanks for any insights. // set our fileinfo to the file url selected by the user
// so we can do some probing of it
fileInfo.url = fileUrl;
// ios includes some parameters to the url using the conventional ?
// remove them from the suffix so they aren't included in our final file name
let lastIndex = fileInfo.suffix.lastIndexOf('?');
let suffix = (lastIndex !== -1 ? fileInfo.suffix.slice(0, lastIndex) : fileInfo.suffix).toLowerCase();
let picName = "";
let picFileName = "";
// use current date and time as milliseconds as default
// guarantees uniqueness and we could parse out the upload date if needed later
let picDate = Date.parse(new Date());
// load our picture into imageObject in prep for save
imageObject.load(fileInfo.filePath);
// build the file name using the date derived above
// and the original file suffix less any parameters
// and tack on the count if we have multiple
picName = picDate + "." + count;
picFileName = picName + "." + suffix;
// increment count for the next time around
count++;
// make a copy of the selected image
// now create the full destination path by getting the path to the new folder along with our new pic file name
let destination = fileFolder.filePath(picFileName);
// if we have a heic format picture swap the .heic suffix for the .jpg suffix
// *note that this is an undocumented hero act that isn't found in readily available Qt\QML libraries
if (fileUrl.toString().toLowerCase().includes("heic")) {
destination = destination.replace(".heic", ".jpg");
}
// we are checking for the folder when the app fires and creating it if it doesn't exist
if (fileFolder.exists) {
// now that the selected image is loaded into imageObject
// and we have created our destination path
// call the save method which converts heic to jpg as necessary
let copied = imageObject.save(destination, "JPG");
if (copied) {
// if copied successfully add it to our model and it will be saved when the workflow is saved
pictureListModel
.append({
// this is the path passed to the function to add attachment
filePath: destination,
// this is the path we use as the source to display before saving, above
// windows needs the file:/// prefix others do not
localFilePath: Qt.platform.os == "windows" ? fileInfo.url.toString() : destination,
contentType: 'image/jpeg',
name: picName
});
} else {
app.toast.show("Unable to upload the picture", "fail");
const details = "The attempt to copy the file failed\n" +
"we were trying to copy this file: \n" +
fileInfo.filePath +
"\nto this location: \n" + destination;
app.toast.show(details, "fail");
console.log("we were trying to copy this file", fileInfo.filePath);
console.log("to this location", destination);
console.log("copy picture failed");
}
} else {
// we have checked for this folder on launch and created it if not there but...
console.log("The destination folder does not exist");
app.toast.show("The destination folder does not exist", "fail");
}
... View more
08-31-2023
12:20 PM
|
0
|
0
|
363
|
POST
|
Maybe a better description is under-documented. The save method converting from heic to jpg is HUGE due to the usage by Apple iOS but isn't mentioned at all in the docs. It's a significant feature that is easily missed, as I did. Thanks again for the direction.
... View more
06-14-2023
08:33 AM
|
0
|
0
|
1574
|
POST
|
Here's the core of the code I'm using. Assuming you have all the properties defined etc. You'll also need an AuthenticationView defined in scope somewhere too. // assuming you have a AuthenticationView defined
// for signing into a portal instance
AuthenticationView {
id: authView
anchors.fill: parent
}
// this goes in your main app component
Component.onCompleted: {
// we are using secure storage to store a refresh token that is attempted to be retrieved
// if the secureStorage.getContent("appRefreshToken") returns an empty string
// i.e. the refresh token has never been stored
// then don't pass it into the credential which will prompt for sign in (using the authView defined above)
// if the refresh token is successfully retrieved from storage pass it into the credential which will use it to generate a fresh token
// create oAuth info specifying that we are requiring a named user sign in and a clientid unique to this app
let oAuthClientInfo = ArcGISRuntimeEnvironment.createObject("OAuthClientInfo", {
oAuthMode: Enums.OAuthModeUser,
clientId: app.clientId
});
let credential = ArcGISRuntimeEnvironment.createObject("Credential", { oAuthClientInfo: oAuthClientInfo });
// attempt to get the refresh token from storage
// so it can be used to generate an access token rather than forcing user to log in again
const refreshToken = secureStorage.getContent("appRefreshToken");
// if we got a refresh token apply it to the credential
// if we did not get one, returns empty string if the key is not found in storage
// don't set the credential refresh token which will prompt for sign in via AuthenticationView
// when loading the portal
if(refreshToken !== "") {
credential.oAuthRefreshToken = refreshToken;
credential.tokenServiceUrl = "%1/sharing/rest/oauth2/token".arg(app.portalUrl);
}
app.portal = ArcGISRuntimeEnvironment.createObject("Portal", {url: app.portalUrl, credential: credential});
app.portal.load();
app.portal.onLoadStatusChanged.connect(()=>{
if (app.portal.loadStatus === Enums.LoadStatusFailedToLoad) {
console.log(app.portal.error.message);
// assume our refresh token was invalidated so set to empty which prompts for log in
app.portal.credential.oAuthRefreshToken = "";
app.portal.retryLoad();
}
else if(app.portal.loadStatus === Enums.LoadStatusLoaded) {
// store the refresh token and token service url for retrieval next time the app is started
// so the user isn't prompted to log in again
secureStorage.setContent("appRefreshToken", app.portal.credential.oAuthRefreshToken);
secureStorage.setContent("tokenServiceUrl", app.portal.credential.tokenServiceUrl);
}
})
} Good Luck! :collision:
... View more
06-13-2023
09:17 PM
|
2
|
1
|
593
|
POST
|
Oh my, the latest version of Let Me Google That For You! Let Me GPT That For You? 🤣 Ummm, thank you? Now off to manage my podcasts! 🚀
... View more
06-12-2023
12:24 PM
|
0
|
0
|
1606
|
POST
|
Thank you for pointing me in the right direction @GKmieliauskas . This sample shows that the ImageObject component is the hero here. Simple and wildly undocumented. Turns out if you load the heic image into imageObject and replace the .heic extension with .jpg extension in the destination path the imageObject will make the conversion when calling the save method. Would love to see this documented but hopefully anyone else with this requirement can find this post. Thanks again, looks like I have my solution. :collision: sample that works // first make the folder if it doesn't exist already
fileFolder.makeFolder();
// now create the full destination path by getting the path to the new folder along with our new pic file name
let destination = fileFolder.filePath(picFileName);
// load our picture into imageObject in prep for save
imageObject.load(fileInfo.filePath);
// if we have a heic format picture swap the .heic suffix for the .jpg suffix
// *note that this is an undocumented hero act that isn't found in readily available Qt\QML libraries
if (fileDialog.fileUrl.toString().toLowerCase().includes("heic")) {
destination = destination.replace(".heic", ".jpg");
}
// now that the selected image is loaded into imageObject
// and we have created our destination path
// call the save method
let copied = imageObject.save(destination);
... View more
06-12-2023
12:21 PM
|
0
|
2
|
1606
|
POST
|
I have a feature that allows my users to select pictures from their device's picture gallery and add as an attachment to a feature. However, since arcgis does not yet support the HEIC image format and iOS uses this format by default, a user cannot use a photo taken from their device as an attachment. I imagine that the solution is to convert the HEIC to JPEG and that the arcgis apps like Survey 123 do that under the hood. However, I cannot find a resource that converts from HEIC to JPEG in Qt\QML or within the AppStudio Framework itself. I am using the AppStudio Framework DocumentDialog, per the Edit Feature Attachments example (note that the sample also only supports jpeg). So, questions: Has anyone found a way to convert from HEIC to JPEG in an AppStudio app? This is ideal. Has anyone implemented a workaround for this issue? I know about changing the picture format on an iOS device but that doesn't help for photos already taken and we don't always have the control to tell users to do that. For reference: Settings > Camera > Formats > Most Compatible ✔️ Thanks for any insights
... View more
06-10-2023
01:35 PM
|
1
|
5
|
1649
|
POST
|
You'll want to store the refresh token that you get back along with the access token when logging in initially. You can then retrieve that refresh token and use it to generate an access token each time the app is fired up. You'd only then be prompted for login when that refresh token expires. I think the default is 2 weeks (?). I pulled a solution together from a couple samples using SecureStorage. Sorry but I can't find the samples I used at the moment. I can drop a few lines of code here to help get you started if that would be helpful.
... View more
06-09-2023
12:18 PM
|
0
|
3
|
606
|
POST
|
Following up to learn if there is more info here. I have since implemented a solution that refreshes the token via a NetworkRequest put on a Timer which works most of the time. However, if the app idles too long in the background the timer will not fire to refresh the access token and the app loses access. This is especially difficult because there is no indication to the user at all. It just doesn't work and there isn't then a way to refresh the token unless I implement a manual way to refresh, inelegant. Any word on whether the refreshTokenExchangeInterval workflow has a workaround here @LucasDanzinger ?
... View more
06-09-2023
12:06 PM
|
0
|
0
|
294
|
POST
|
Appreciate the update. This has turned into a potential issue for us so any further info you can provide would be much appreciated.
... View more
04-05-2023
04:02 PM
|
0
|
0
|
344
|
POST
|
Hmmm @LucasDanzinger this did not work. I set the refreshTokenExchangeInterval on the oAuthClientInfo to 30 but it did not work to automatically refresh the token at the set interval. I started the app and let it sit for 30 minutes and sure enough it timed out. Any other tips? Is it dependent on any other properties?
... View more
03-22-2023
05:41 PM
|
1
|
0
|
369
|
POST
|
Setting the refreshTokenExchangeInterval on the oAuthClientInfo did not work to automatically refresh the token at the set interval.
... View more
03-22-2023
05:38 PM
|
1
|
0
|
375
|
POST
|
Wow. Even easier. I actually had this commented out so you're telling me it would have automatically refreshed the token all along if enabled? 🙄 If this is the expected behavior then I will assume it works. I will report back otherwise. Thanks!
... View more
03-21-2023
11:27 AM
|
0
|
2
|
871
|
POST
|
So @LucasDanzinger if using oAuth, could this example be as simple as using the existing credential's refreshToken to create a new Credential and pass that to challenge.continueWithCredential(credential)? I'm trying to refresh a token without prompting the user to log in again. Or, in my case, the app just hangs and 'acts weird' when the token expires. Thanks for any help.
... View more
03-20-2023
03:17 PM
|
0
|
5
|
882
|
Title | Kudos | Posted |
---|---|---|
1 | Wednesday | |
2 | 06-13-2023 09:17 PM | |
1 | 06-10-2023 01:35 PM | |
1 | 03-22-2023 05:38 PM | |
1 | 03-22-2023 05:41 PM |
Online Status |
Offline
|
Date Last Visited |
Wednesday
|