Does the "/Volumes" name changes based on system language, if yes how to adapt this? - objective-c

I am using this code to check if the client runs from DMG /Volume, and show an alert and quit.
private void IsRunningFromDMG()
{
var currentPath = NSBundle.MainBundle.BundlePath;
if (currentPath.StartsWith("/Volumes", StringComparison.Ordinal))
{
using (var alert = new NSAlert
{
MessageText = "Warning",
InformativeText = "You cannot run this application from DMG, drag move to the " +
"\"/Applications\" folder"
})
{
alert.RunModal();
NSApplication.SharedApplication.Terminate(null);
}
}
}
This is fine if the system language is set to English. I doubt if the /Volumes reacts to localization in that case how to do it?
There should be a system defined constant that would take care of it?
If it is, please help me to know what is it.

Filesystem paths do not change based on localization, they are localized for "display" though (i.e. Pictures, Music, etc... would be localized in Finder for display to the user but the filesystem path is still /User/xxx/Pictures, etc...)
Localized names. The system provides localized names for many system directories, such as Applications, Library, Music, Movies. An app may similarly provide localized names for itself and for any directories it creates.
Display names do not affect the actual name of the file in the file system. Code that accesses a file or directory programmatically must specify the item’s actual name when opening or manipulating the item using the file system interfaces. The only time your app should ever use display names is when displaying the name of a file or directory to the user. You can get the display name for any file or directory using the displayNameAtPath: method of NSFileManager.
i.e.
var urls = NSFileManager.DefaultManager.GetUrls(NSSearchPathDirectory.ApplicationsDirectory, NSSearchPathDomain.System);
var applicationDisplayName = NSFileManager.DefaultManager.DisplayName(urls[0].AbsoluteString);
Note: You should use NSSearchPathDirectory.AllApplicationsDirectory within the NSSearchPathDomain.All domain to obtain a valid list of "Application" urls where your application might/should be located at, instead of hard coding it to the "System" application location.

Related

Store an array on the app group for WidgetKit

I'm trying to store an struct array into the app group container to use it later on the widget.
let's assume, I have an array of string
let = array = ["object1", "object2", "object3"]
and I saw here I can access to the app group container url
let applicationGroupId = "group.com.development.widget"
guard let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: applicationGroupId) else {
fatalError("could not get shared app group directory.")
}
Now, I need to know how I can store this array on app group and how I can read from it on the Widgetkit SwiftUI class
Your help will be appreciated.
Signing, Capabilities, Entitlements
Right now it should be possible to do all of this from within Xcode (12+). In the app's project settings go to the Signing & Capabilities tab and make sure Automatically manage signing is enabled and the Team has a valid development team (either company or personal account).
Tap on the + Capability button on the top left to enter the App Group Capability (this will also add an entitlements file). Now you will find an App Group section. Hit the + button for App Groups and enter a globally unique identifier (something like group.<appid>). This will create the app group on the developer platform and add it to your app's provisioning profile and entitlements.
You must repeat the same steps and use the same app group for all targets (app target, widget extension target and (optionally) intent targets). If you hit the reload button for the other targets' app group it should automatically show the app group you previously registered and you can check the checkbox. If not, hitting + and using the same id should work as well.
Finally, check all entitlements files and ensure that they have the same String in App Groups (copy and paste just to make sure).
Code
In code you now just have to access the user defaults using the chosen app group as suitName. To test whether everything is set up correctly, I would put the following line in application(_:didFinishLaunchingWithOptions):
UserDefaults(suiteName: "group.id.test")!.setValue(["object1", "object2", "object3"], forKey: "test")
In the Widget just try to put it in a Text view:
struct WidgetTestEntryView : View {
var entry: Provider.Entry
var text: String {
(UserDefaults(suiteName: "group.id.test")!.value(forKey: "test") as? [String])?.joined(separator: " ") ?? "Nothing stored yet"
}
var body: some View {
Text(text)
}
}
Note: I force unwrap the user defaults on purpose to fail early and check whether the setup of capabilities/signing worked. In production you should guard against a failure.
Alternative Storage
As you pointed out it's also possible to persist data in a shared container by writing to url provided by FileManager.default.containerURL(forSecurityApplicationGroupIdentifier:) but I don't think you need that for your simple example. If you want to share data that is more complex than String, Int, Array ... make sure to convert it to Data since user defaults cannot handle arbitrary data (even if it's Codable).
Manual Signing
If you use manual signing you just have to do the same step in the developer console starting with registering an app group. After that, add the group to all identifiers' capabilities and recreate all provisioning profiles. From there you should be use similar steps to the ones described above.

File object in WinJS - how to retrieve the containing folder

I have got a app with the getItemsAsync()-method returning a file-object for a picture chosen by the user with a file picker. Now I would like to get the folder-object of the folder which contains the image to make the user able to switch between the pictures in that folder without using the filepicker again.
The path is available upon return from the file picker. See:
Docs for StorageFile
You can in turn then call
Windows.Storage.StorageFolder.getFolderFromPathAsync(path)
.done( /* Your success and error handlers */ );
to get you the StorageFolder from that path.
Docs for GetFolderFromPathAsync()
if the app likely want to 'access' any file in the select folder, using FolderPicker is probably right. otherwise, the app will likely not have access to all files in the folder.

Capture and save a photo in XAML/C# for a Windows store application

I'm trying to take and save a photo using a windows surface device.
I'm using the code below to take a photo and this work but I'd like to automatically create a directory on the device's local drive and save this photo there without any dialog prompts.
So the code I use to capture to photo is as follows:
CameraCaptureUI camera = new CameraCaptureUI();
StorageFile file = await camera.CaptureFileAsync(CameraCaptureUIMode.Photo);
if (file!=null)
{
using (IRandomAccessStream ras=await file.OpenAsync(FileAccessMode.Read))
{
BitmapImage source = new BitmapImage();
source.SetSource(ras);
imageBuildingPhoto.Source = source; // this is just an image control.
}
}
So after this I'd like to automatically save the photo to a new directory. e.g.
My Pictures\NewDirectory\Photo1.jpg
Anybody got any idea how I can do this?
This is a windows store application written using C#4.5 and XAML.
Thanks in advance
Use the CopyAsync method on the StorageFile object you get back (file). You can specify a directory and file name. If you need to create your own directory structure, you will need to enable access to the appropriate library in the Package Manifest then create it in code. You will then use the StorageFolder class and its CreateFolderAsync method to create folders.
http://aka.ms/30Days has some great resources for learning about scenarios like this. Might be worth checking out.
Your code will need to look to see if that folder exists and create it if it does not. Your app will need to declare the capability to access the user's Photos library in the app manifest, too.
To take a picture, your code is correct. I have a walkthrough in case you want to verify it against some other code: http://blog.jerrynixon.com/2012/10/walkthrough-capturing-photos-in-your.html
To interact with the file system, this can be tricky, but I have a longer write up on that if you want to reference it: http://blog.jerrynixon.com/2012/06/windows-8-how-to-read-files-in-winrt.html
The answer to your question is, yes you can. I have done it in my own apps. Now, it's just a matter of you implementing it in yours. You will find it to be pretty easy.

is it possible to locate file on Mac without knowing exact location?

I am trying to locate a file on Machintosh without knowing exact file location. I am developing an app which needs to locate iTunes library XML file and parse it for data. However XML resides in,
/Users/**Current logged in username**/Music/iTunes
Now username may change, So how to set path of let my code find below named file programmatically. Language used is Objective - C.
File name : iTunes Music Library.xml
Possible solution I thought is to get username by code. Is there any method which returns a string of current logged in user's "username".
Thanks
You should be able to use ~/Music/iTunes. ~ represents the home directory of the current user.
Or you could could see this question: Mac OS X: Get current username and home directory for current user from Directory Services
Don't do this! The user's iTunes library doesn't have to be in the default location.
Instead, read the iTunesRecentDatabasePaths key from com.apple.iapps. It'll give you an array that represents the recently used iTunes libraries.
$ defaults read com.apple.iapps iTunesRecentDatabasePaths
(
"/Volumes/Media/iTunes/iTunes Library.xml"
)
NSHomeDirectory() is a Foundation function that returns an NSString of the path to the current user's home directory.
Apple Developer Library - NSHomeDirectory

Liferay 6.0.5 - hide IGFolders from owner on private/public layout of his private community

We need to create hidden "system" subfolders in every IGFolder an normal user creates.
The image gallery portlet resides mainly on the private community layouts of all normal users. The portlets and their configuration is pregenerated so the normal users can't change them (layout.user.[public|private].layouts.modifiable=false).
Why we want to do this
In those system folders we'll store automatically generated size versions of the uploaded images. This is because we also import WebContent/JournalArticle representing image galleries which provide different sizes of the images themselves. In the end we want to display both the IGFolders and the JournalArticle content the same way without to much special code.
What i have tried already
I tried to do this via permissions (resource-actions/imgallery.xml =>
owner-defaults) but on his own community pages the user is also
CommunityAdmin which gives him the rights to do & see almost whatever
he wants. (PermissionCheckerBagImpl.isCommunityAdminImpl)
I thought of creating the layouts that don't belong to the user/his
private Community, but testing this on a public page of another
community that the users belongs to didn't work. I can't get the
system to display the IGFolders of the current user at all, instead
the folders of the community are displayed.
Using another user and group for the subfolders didn't work either,
if the groupId does not match the one of the parent folder the parent
folder id is set to 0, so they are longer subfolders at all
(IGFolderLocalServiceImpl.getParentFolderId).
What might work and i probably just don't get right
changing the owner of the image gallery portlet/the layout
fiddling with the permission in a way i haven't thought of
adding another layer of groups/communities
putting the system folders somewhere else (which of course leads
to more code for maintaining the relation between them and their
parent folder)
Of course i could use expandos to flag the system folders - which i have to do anyway - and hide them after retrieval in the view but then i also would have to fiddle with the folder count, which i would like not to, since i feel this is not the way to do things.
Any ideas are appreciated, please don't feel shy to elaborate, I'm quite new to Liferay
You could create hook plugin and override in it (probably this file)
/portal/portal-web/docroot/html/portlet/image_gallery/view_folders.jsp
There you could add code to ignore your "system" folder if it exists. Perhaps all "system" folders could have same name (for example "_SYSTEM_FOLDER_") that you can test against.
Take note that this just hides folders, so if someone knows folderId and has permission to see/edit it they could craft URL to access it.