Date   

Re: Retrieve all available Finder tags on Monterey and later

Thomas Tempelmann
 

Oh, damnit! I looked at the High Sierra version of Finder. I only realized that now when I found the tags inside /Users/tempi/Library/SyncedPreferences/com.apple.finder.plist

Sigh. Will try again on Monterey now.


Re: Retrieve all available Finder tags on Monterey and later

Thomas Tempelmann
 

This is probably also relevant when looking at the previous code:

/* @class TiCloudTagReplicator */

-(void *)iCloudDictionary {

    rdi = self->_store;

    rax = [[rdi dictionaryRepresentation] objectForKey:@"FinderTagDict"];

    return rax;

}


If I interpret this right, then the iCloud store for Finder has a FinderTagDict. I have no clue if other apps can access that, though.


Re: Retrieve all available Finder tags on Monterey and later

Thomas Tempelmann
 

Searching in Hopper for "tags" finds methods such as "readTagsFromCloud:". Do you have iCloud active? Maybe that's where they're now exclusively stored.

Could you check this: Create a second user where iCloud is not used. Does that then bring back the plist file that was used pre-Monterey?

And there's a class TTagInfoRegistry. It seems to manage the tags and observe changes to them.

The code inside readTagsFromCloud is below. Can anyone make sense of it? I'm not familiar with the Cloud APIs:

/* @class TiCloudTagReplicator */

-(void)readTagsFromCloud:(bool)arg2 {

    var_DC = arg2;

    r14 = [self iCloudDictionary];

    if (r14 != 0x0) {

            [r14 objectForKeyedSubscript:@"FinderTagDictVersion"];

            if (sub_1002b519c() == 0x2) {

                    [r14 objectForKeyedSubscript:@"FinderTagSerialNumber"];

                    r12 = sub_1002b519c();

                    if ((r12 > [TUserDefaults integerForRegID:0xb7]) || (var_DC != 0x0)) {

                            rbx = [r14 objectForKeyedSubscript:@"FinderTags"];

                            if (rbx != 0x0) {


Thomas


Re: Retrieve all available Finder tags on Monterey and later

Thomas Tempelmann
 

The next step would be to use "Hopper Disassembler" and find the code that shows and sets up the Finder prefs window, in order to find out where it loads the information from. Hopper can turn the machine code into pseudo code and can also show the names of methods and strings, so it might lead to something.

Thomas


Re: Retrieve all available Finder tags on Monterey and later

Leo
 

On Fri, Jan 13, 2023 at 10:35 AM, Thomas Tempelmann wrote:
The best I could come up with so far is to use AppleScript to read the tag names from the Preferences window, see below.
But it sucks because it has to actually open the Finders's Prefs window.
Thanks Thomas,

Interesting script. I'll keep it as a great example of UI scripting.

Like you mentioned, it has to open the actual Prefs window so not exactly suitable to, say, populate a popup with tags for the user to choose from. Plus the app I need it for is on Mac App Store where they don't allow System Events anyway.

I'm truly curious why Apple hides the list of tags so hard.


Leo



Re: Retrieve all available Finder tags on Monterey and later

Leo
 

On Fri, Jan 13, 2023 at 09:25 AM, Thomas Tempelmann wrote:
...I've already searched ALL files on a startup's data volume for the appearance of the name of a custom tag I added. No luck. Meaning it's no stored in a plist or something like that in plain text. Maybe in compressed form or in a database in a different format (again, compressed).
Yep I did do a similar search and reached the same conclusion.


Re: Retrieve all available Finder tags on Monterey and later

Thomas Tempelmann
 

The best I could come up with so far is to use AppleScript to read the tag names from the Preferences window, see below.

But it sucks because it has to actually open the Finders's Prefs window.

use AppleScript version "2.4" -- Yosemite (10.10) or later

use scripting additions


set prefsWinWasOpen to false


tell application "Finder"

set prefs to Finder preferences

set prefsWin to window of prefs

tell prefsWin

try

get id

set prefsWinWasOpen to true

on error

set prefsWinWasOpen to false

open

end try

set current panel to Label Preferences panel

end tell

end tell


set rowNames to {}


tell application "System Events"

tell front window of (first application process whose name is "Finder")

set uiElems to entire contents

repeat with uiElem in uiElems

if class of uiElem is table then

set theTable to uiElem

exit repeat

end if

end repeat

set itsRows to rows of theTable

repeat with oneRow in itsRows

set end of rowNames to name of first UI element of oneRow

end repeat

end tell

end tell


if not prefsWinWasOpen then

tell application "Finder"

close prefsWin

end tell

end if


return rowNames



Re: Retrieve all available Finder tags on Monterey and later

Thomas Tempelmann
 

As the developer of FindAnyFile, which has a more powerful text search feature that EasyFind (it can find text in both UTF-8 and -16, in LE and BE, and even considers unicode pre/decomposition alternatives), I've already searched ALL files on a startup's data volume for the appearance of the name of a custom tag I added. No luck. Meaning it's no stored in a plist or something like that in plain text. Maybe in compressed form or in a database in a different format (again, compressed).

It must be stored _somewhere_, but I'm at the end of my wits, too.


On Fri, Jan 13, 2023 at 5:52 PM Leo <var@...> wrote:
On Thu, Jan 12, 2023 at 11:11 AM, Gary L. Wade wrote:
I’m not sure if it’s officially documented somewhere, but what I’d do is add some tags to a particular file, see what that file looks like from the Terminal (e.g., xattr), and do a search for info about what it looks like vs another file that doesn’t have tags.  If there’s no official documentation once you see what you’re needing to see, file a feedback request to get it documented.
 
Thanks Gary,

Yes, there's no issue to retrieve applied tags - xattr is indeed the simplest way to do this.

I'm talking about the list of all available tags - including the ones that are available to the user but not yet applied to any file.

I will file a feedback request to Apple eventually, which of course won't solve the issue for a few years at least.

Maybe I'll finally take advantage of those Technical Support Incident requests that Apple offers via the developer program.


Thanks,
Leo


Re: Retrieve all available Finder tags on Monterey and later

Leo
 

On Thu, Jan 12, 2023 at 11:11 AM, Gary L. Wade wrote:
I’m not sure if it’s officially documented somewhere, but what I’d do is add some tags to a particular file, see what that file looks like from the Terminal (e.g., xattr), and do a search for info about what it looks like vs another file that doesn’t have tags.  If there’s no official documentation once you see what you’re needing to see, file a feedback request to get it documented.
 
Thanks Gary,

Yes, there's no issue to retrieve applied tags - xattr is indeed the simplest way to do this.

I'm talking about the list of all available tags - including the ones that are available to the user but not yet applied to any file.

I will file a feedback request to Apple eventually, which of course won't solve the issue for a few years at least.

Maybe I'll finally take advantage of those Technical Support Incident requests that Apple offers via the developer program.


Thanks,
Leo


Re: Retrieve all available Finder tags on Monterey and later

Leo
 

Thanks Alex,
 
It's just all the solutions you mentioned are PRE-Monterey.
 
They all rely on the ~/Library/SyncedPreferences/com.apple.finder.plist file which doesn't exist since Monterey.
 
I myself was using this file for years.
 
At this point there doesn't seem to be a known way to retrieve the list of tags on Monterey and later.
 
So I was basically posting this question in hope that someone has figured out an unknown way.
 
 
Best,
Leo


Re: Retrieve all available Finder tags on Monterey and later

Alex Zavatone
 

A few options.

Create a unique tag and then use EasyFind to search all files on your drive to detect the one that contains that string.

Here’s a link to an AppleScript script that is supposed to return all tag names


(* Generate an inclusive list of standard and user defined tag names Tested: macOS 11.2.3 Author: VikingOSX, 2021-03-09, Apple Support Communities, no warranties *) use framework "AppKit" use scripting additions property NSWorkspace : a reference to current application's NSWorkspace set tagfile to POSIX path of ((path to home folder as text) & "Library:SyncedPreferences:com.apple.finder.plist") as text set keyPath to "values:FinderTagDict:value:FinderTags" set AWKCMD to " | awk '/n/ {print substr($0, index($0, $3))}'" -- if custom tag names were created in Finder this file will exist if exists ((POSIX file tagfile) as alias) = true then set allTags to paragraphs of (do shell script "/usr/libexec/PlistBuddy -c \"print " & keyPath & "\" " & tagfile's quoted form & AWKCMD) else -- no custom tag names exist, so get default Finder tag names set allTags to NSWorkspace's sharedWorkspace()'s fileLabels() as list end if if exists (allTags) is true then set {TID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, return} display dialog (items of allTags) as text with title "User Defined Tag Names" set AppleScript's text item delimiters to TID end if return


Hope that works on Monterey.
Cheers, 
Alex Zavatone



On Jan 13, 2023, at 9:23 AM, Alex Zavatone via groups.io <zav@...> wrote:

There's unfortunately no API in macOS to retrieve the tags that you have created yourself in the Finder.

The solution is to parse the ~/Library/SyncedPreferences/com.apple.finder.plist:


This gets all Finder tags labels.

You can also select only the custom tags (ignore the system ones):

func customTagLabels() -> [String] {
    let url = URL(fileURLWithPath: "\(NSHomeDirectory())/Library/SyncedPreferences/com.apple.finder.plist")
    let keyPath = "values.FinderTagDict.value.FinderTags"
    if let d = try? Data(contentsOf: url) {
        if let plist = try? PropertyListSerialization.propertyList(from: d, options: [], format: nil),
            let pdict = plist as? NSDictionary,
            let ftags = pdict.value(forKeyPath: keyPath) as? [[AnyHashable: Any]]
        {
            return ftags.flatMap { tag in
                if let n = tag["n"] as? String,
                    tag.values.count != 2
                {
                    return n
                }
                return nil
            }
        }
    }
    return []
}

Text copied verbatum from StackOverflow.

Hope this helps.
Alex Zavatone

On Jan 13, 2023, at 8:31 AM, Steve Mills via groups.io <sjmills@...> wrote:

On Jan 12, 2023, at 12:37, Thomas Tempelmann <tempelmann@...> wrote:

I doubt it's Spotlight that stores them because they also work on vols where the Spotlight index is disabled.

Spotlight has to store them in order to find them, so they'd be stored there as well as where ever the file system puts them.

--
Steve Mills
Drummer, Mac geek









Re: Retrieve all available Finder tags on Monterey and later

Alex Zavatone
 

A little more info.

Also, just as a FYI allTagLabels did return all tags, but customTagLabels didn't return all custom tags I had created. Going through the differences will actually probably be useful for me. 

On Monterey (12.0), this file is no longer present in that directory. It has moved to ~/Library/Preferences, BUT the contents are different, AND, they no longer contain all the necessary information. Now, only the tag names are present, but not the mapping to colors.

This looks like a shortcoming in the API.  I wonder if it’s it’s possible through AppleScript of all arcane solutions.  I’ll keep looking.

Alex Zavatone



On Jan 13, 2023, at 9:23 AM, Alex Zavatone via groups.io <zav@...> wrote:

There's unfortunately no API in macOS to retrieve the tags that you have created yourself in the Finder.

The solution is to parse the ~/Library/SyncedPreferences/com.apple.finder.plist:


This gets all Finder tags labels.

You can also select only the custom tags (ignore the system ones):

func customTagLabels() -> [String] {
    let url = URL(fileURLWithPath: "\(NSHomeDirectory())/Library/SyncedPreferences/com.apple.finder.plist")
    let keyPath = "values.FinderTagDict.value.FinderTags"
    if let d = try? Data(contentsOf: url) {
        if let plist = try? PropertyListSerialization.propertyList(from: d, options: [], format: nil),
            let pdict = plist as? NSDictionary,
            let ftags = pdict.value(forKeyPath: keyPath) as? [[AnyHashable: Any]]
        {
            return ftags.flatMap { tag in
                if let n = tag["n"] as? String,
                    tag.values.count != 2
                {
                    return n
                }
                return nil
            }
        }
    }
    return []
}

Text copied verbatum from StackOverflow.

Hope this helps.
Alex Zavatone

On Jan 13, 2023, at 8:31 AM, Steve Mills via groups.io <sjmills@...> wrote:

On Jan 12, 2023, at 12:37, Thomas Tempelmann <tempelmann@...> wrote:

I doubt it's Spotlight that stores them because they also work on vols where the Spotlight index is disabled.

Spotlight has to store them in order to find them, so they'd be stored there as well as where ever the file system puts them.

--
Steve Mills
Drummer, Mac geek









Re: Retrieve all available Finder tags on Monterey and later

Alex Zavatone
 

There's unfortunately no API in macOS to retrieve the tags that you have created yourself in the Finder.

The solution is to parse the ~/Library/SyncedPreferences/com.apple.finder.plist:


This gets all Finder tags labels.

You can also select only the custom tags (ignore the system ones):

func customTagLabels() -> [String] {
    let url = URL(fileURLWithPath: "\(NSHomeDirectory())/Library/SyncedPreferences/com.apple.finder.plist")
    let keyPath = "values.FinderTagDict.value.FinderTags"
    if let d = try? Data(contentsOf: url) {
        if let plist = try? PropertyListSerialization.propertyList(from: d, options: [], format: nil),
            let pdict = plist as? NSDictionary,
            let ftags = pdict.value(forKeyPath: keyPath) as? [[AnyHashable: Any]]
        {
            return ftags.flatMap { tag in
                if let n = tag["n"] as? String,
                    tag.values.count != 2
                {
                    return n
                }
                return nil
            }
        }
    }
    return []
}

Text copied verbatum from StackOverflow.

Hope this helps.
Alex Zavatone

On Jan 13, 2023, at 8:31 AM, Steve Mills via groups.io <sjmills@...> wrote:

On Jan 12, 2023, at 12:37, Thomas Tempelmann <tempelmann@...> wrote:

I doubt it's Spotlight that stores them because they also work on vols where the Spotlight index is disabled.

Spotlight has to store them in order to find them, so they'd be stored there as well as where ever the file system puts them.

--
Steve Mills
Drummer, Mac geek








Re: Retrieve all available Finder tags on Monterey and later

Steve Mills
 

On Jan 12, 2023, at 12:37, Thomas Tempelmann <tempelmann@...> wrote:

I doubt it's Spotlight that stores them because they also work on vols where the Spotlight index is disabled.
Spotlight has to store them in order to find them, so they'd be stored there as well as where ever the file system puts them.

--
Steve Mills
Drummer, Mac geek


Re: Retrieve all available Finder tags on Monterey and later

Thomas Tempelmann
 

I doubt it's Spotlight that stores them because they also work on vols where the Spotlight index is disabled.

On Thu, Jan 12, 2023 at 7:01 PM Jens Alfke <jens@...> wrote:

Maybe this is managed by Spotlight (i.e. Metadata.framework) now? Since it’s Spotlight that actually stores the tags.

—Jens


Re: Retrieve all available Finder tags on Monterey and later

Gary L. Wade
 

I’m not sure if it’s officially documented somewhere, but what I’d do is add some tags to a particular file, see what that file looks like from the Terminal (e.g., xattr), and do a search for info about what it looks like vs another file that doesn’t have tags.  If there’s no official documentation once you see what you’re needing to see, file a feedback request to get it documented.

On Jan 11, 2023, at 8:27 PM, Leo <var@...> wrote:

I wonder if anyone has figured out a way to retrieve ALL available Finder tags on Monterey and later?

On pre-Monterey systems, it was possible by reading this file:

~/Library/SyncedPreferences/com.apple.finder.plist

However, this file doesn't exist anymore.

Other methods (such as reading Finder prefs or fileLabels of NSWorkspace) only return the 8 standard labels - but not any custom tags created by the user.

Googling the subject didn't produce any results.


Thanks for any info,
Leo 


Re: Retrieve all available Finder tags on Monterey and later

 



On Jan 11, 2023, at 8:27 PM, Leo <var@...> wrote:

I wonder if anyone has figured out a way to retrieve ALL available Finder tags on Monterey and later? 

Maybe this is managed by Spotlight (i.e. Metadata.framework) now? Since it’s Spotlight that actually stores the tags.

—Jens


Retrieve all available Finder tags on Monterey and later

Leo
 

I wonder if anyone has figured out a way to retrieve ALL available Finder tags on Monterey and later?

On pre-Monterey systems, it was possible by reading this file:

~/Library/SyncedPreferences/com.apple.finder.plist

However, this file doesn't exist anymore.

Other methods (such as reading Finder prefs or fileLabels of NSWorkspace) only return the 8 standard labels - but not any custom tags created by the user.

Googling the subject didn't produce any results.


Thanks for any info,
Leo 


Re: SwiftUI AttributedString on Watch

Alex Zavatone
 

Would you use a sizeToFit or sizeThatFits method call to do that for you even after you’ve set the attributed text?

I have some old Objective-C libraries that I wrote for CVS to set iOS app text to their standard fonts.

Here’s a chunk of it.  You can see how I apply the font size to the dictionary.  Cheers!

   // Set base font & size.
    CGFloat fontSize = 20.0;
    UIFont *fnt = [UIFont fontWithName:@"Helvetica" size:fontSize]; // never initialize a font with a size of 0.0, or it will always be Helvetica

    

    // Define base string.
    NSString *myString;
    //myString = @"beauty club®"; // with R
    myString = @"beauty club™"; // with TM

    

    // Define base color and font definitions.

    

    fontSize = 24;
    UIColor *myBlue = [UIColor colorWithRed:.02 green:.48 blue:.66 alpha:1.0]; // Unused.  Kept as an example.
    UIColor *myPink = [UIColor colorWithRed:.93 green:.36 blue:.62 alpha:1.0];
    UIFont *thickFont = [UIFont fontWithName:@"HelveticaNeue-Bold" size:fontSize];
    UIFont *thinFont = [UIFont fontWithName:@"HelveticaNeue-Light" size:fontSize];
    thinFont = [UIFont fontWithName:@"HelveticaNeue-Medium" size:fontSize];

    

    // Define attributes dictionary for bold text.
    NSDictionary *boldAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                    thickFont, NSFontAttributeName,
                                    myPink, NSForegroundColorAttributeName,
                                    nil];

    

    // Find range of text to make bold.
    NSString *textToBeBoldAndPink = @"beauty";
    NSRange boldAndPinkRange = [myString rangeOfString:textToBeBoldAndPink];

    

    // Define attributes dictionary for thin text.
    NSDictionary *thinAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                    thinFont, NSFontAttributeName,
                                    myPink, NSForegroundColorAttributeName,
                                    nil];

    

    // Find range of text to make thin.
    NSString *textToBeThin;
    //        textToBeThin= @"club®"; // with R
    textToBeThin= @"club™"; // with TM
    NSRange thinTextRange = [myString rangeOfString:textToBeThin];

    

    

    // Make the basic attributed string
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:myString
                                                                                         attributes:@{NSFontAttributeName: [fnt fontWithSize:fontSize]}];

    

    // Apply bold and thin formatting to strings using appropriate ranges.
    [attributedString setAttributes:boldAttributes range:boldAndPinkRange];
    [attributedString setAttributes:thinAttributes range:thinTextRange];

    

    // AZ - find position of desired character to superscript in string
    NSString *charToFind;
    //charToFind = @"®"; // In case we are using R instead.  Just an example.
    charToFind = @"™"; // In case we are using TM instead.  Just an example.

    

    NSRange positionOfSuperscriptCharacter = [myString rangeOfString:charToFind];

    

    // Setting the point sizes using exact numbers
    //  NSInteger superscriptCharSize = 12;
    //  CGFloat pointsToRaiseBaseLineOfSupercriptChar = 8.0;
    //  UIColor *colorOfSuperText = myPink;
    //  NSNumber *characterBaselineOffsetUp = [NSNumber numberWithFloat:pointsToRaiseBaseLineOfSupercriptChar];

    

    // Set point size of superscript text relative to display font size as a percentage of original.
    CGFloat superscriptCharacterPercentOfFullsizeText = 0.60f; // 12 pt if original is 20 point
    NSInteger superscriptCharSize = fontSize * superscriptCharacterPercentOfFullsizeText ;

    

    // Set points to raise superscript text relative to font size as a percentage of original.

    

    CGFloat superscriptCharacterPercentOfFullsizeTextToRaiseChar = 0.40f; // 8 points if original is 20 point
    CGFloat pointsToRaiseBaseLineOfSupercriptChar = fontSize * superscriptCharacterPercentOfFullsizeTextToRaiseChar ;

    

    NSNumber *characterBaselineOffsetUp = [NSNumber numberWithFloat:pointsToRaiseBaseLineOfSupercriptChar];

    

    // Set color for text.
    UIColor *colorOfSuperText = myPink;

    

    // Set attributes to be applied to string.
    NSDictionary *superTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                         [fnt fontWithSize:superscriptCharSize], NSFontAttributeName,
                                         colorOfSuperText, NSForegroundColorAttributeName,
                                         characterBaselineOffsetUp, NSBaselineOffsetAttributeName,
                                         nil];

    

    // Apply the formatting for the superscript to the range of text for the string.
    [attributedString setAttributes:superTextAttributes range:positionOfSuperscriptCharacter];

    

    return attributedString;


On Nov 7, 2022, at 6:06 AM, Gerriet M. Denkmann <gerriet@...> wrote:

I have a Watch-App using SwiftUI.

let fontSize = 40.0
struct WatchContentView: View
{
@State var timeAttributedStr = AttributedString("--")
let timer = Timer.publish(every: 1, tolerance: 0.1, on: .main, in: .common).autoconnect()

var body: some View
{
VStack
{
Text(timeAttributedStr)
}
.onReceive(timer)
{ currentTime  in

timeAttributedStr = … make from currentTime using fontSize …

//  compare size of timeAttributedStr to window and decrease fontSize if needed
// no idea how to do this
      }
}
}

The Problem:
I want to make fontSize as big as possible. And then do:
if timeAttributedStr.size.width > window.size.width then decrease fontSize

But sadly, AttributedString has no size.

A fixed fontSize is less than ideal, because the optimal timeAttributedStr will depend both on Locale and Watch model.

Gerriet.








Re: SwiftUI AttributedString on Watch

Laurent Daudelin
 

Doesn’t AttributedString uses a dictionary to set its attributes, including font and font size?

-Laurent.
-- 
Laurent Daudelin   laurent@...
Skype: LaurentDaudelin
Logiciels Némésys Software   https://www.nemesys-soft.com/

On Nov 7, 2022, at 07:06, Gerriet M. Denkmann <gerriet@...> wrote:

I have a Watch-App using SwiftUI.

let fontSize = 40.0
struct WatchContentView: View
{
@State var timeAttributedStr = AttributedString("--")
let timer = Timer.publish(every: 1, tolerance: 0.1, on: .main, in: .common).autoconnect()

var body: some View
{
VStack
{
Text(timeAttributedStr)
}
.onReceive(timer)
{ currentTime  in

timeAttributedStr = … make from currentTime using fontSize …

//  compare size of timeAttributedStr to window and decrease fontSize if needed
// no idea how to do this
      }
}
}

The Problem:
I want to make fontSize as big as possible. And then do:
if timeAttributedStr.size.width > window.size.width then decrease fontSize

But sadly, AttributedString has no size.

A fixed fontSize is less than ideal, because the optimal timeAttributedStr will depend both on Locale and Watch model.

Gerriet.

21 - 40 of 1516