shawnrice / alfred-bundler

a utility / workflow to handle dependencies
MIT License
21 stars 3 forks source link

LightOrDark always returning 'light' #48

Closed deanishe closed 10 years ago

deanishe commented 10 years ago

I've tried changing themes, but the LightOrDark util always returns light. Even with a black theme.

shawnrice commented 10 years ago

WTF? It had been working perfectly for me, and now it's not. Are you on Yosemite or Mavericks?

shawnrice commented 10 years ago

Maybe I've gotten more sleep today than the last time I was trying to sort through the code, but the Objective-C seems to make more sense in that it doesn't do exactly what we need it to do.

I will say, the LightOrDark was working, but now it's not...

I just pushed the source that I used to compile the utility to a new repo, and I added you both as collaborators.

Basically, what the utility needs to do is

  1. figure out where the alfredpreferences plist is that has the theme data;
  2. identify the current theme;
  3. get the background color of said theme;
  4. evaluate whether it is light or dark; and
  5. return the appropriate value.

We could do everything above in a regular script except for 3. The reason why is that the plists store the colors as Objective-C colors, and I haven't seen a way to convert them to something usable (hex?). If we can find out a way to do that, then I can just rewrite the above as a script. Otherwise, let's see if we can tweak the code.

shawnrice commented 10 years ago

Updating:

  1. Read ~/Library/Preferences/com.runningwithcrayons.Alfred-Preferences.plist to get
    • appearance.theme
    • syncfolder
  2. If syncfolder is not set, then fallback to default at ~/Library/Application Support/Alfred 2/
  3. Find plist at syncfolder/Alfred.alfredpreferences/preferences/appearance/prefs.plist
  4. Get value for themes/<appearance.theme-value-from-step1>/background
  5. Somehow convert that to a usable value. This is where I'm stumped.

So, here's an example colorspace that I've found in step 4: BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARmZmZmAAAAAYY=

If I base64 decode that, then I get streamtyped���@���NSColor�NSObject��c�ffff�

shawnrice commented 10 years ago

Okay. The reason why it's not working anymore is, that, for some reason, the theme name isn't being updated in ~/Library/Preferences/com.runningwithcrayons.Alfred-Preferences.plist.

appearance.theme stays the same no matter what, even if I change it. My current value in there refers to the theme that I usually use, which is light, so it keeps returning those values. The utility is working in the sense that it pulls the relevant information out of the plists.

When I change the theme, then the appearance.theme value doesn't change. So... where is Alfred now storing this value?

shawnrice commented 10 years ago

I just emailed Andrew to ask him that last question of where it's currently being stored. Putting this on hold because I can't track down the file.

deanishe commented 10 years ago

It's in Alfred.alfredpreferences (which may be somewhere in Dropbox).

When I change theme, the file that contains the actual ID of the currently selected theme (i.e. the file that actually changes) is:

preferences/local/3b199235f622c5e93b5731756e19867edfb2f354/appearance/prefs.plist

I'm using the brand-new development version however (w/ proxy support), and that local directory was created today, so it might be somewhere else in the stable version.

shawnrice commented 10 years ago

Looks like its there for me as well. Good to know. That will make it hard to find (for me to get the last dir) in objective-c if it stays there. We might be able to do something to where we get the current version of Alfred and change it depending on that. Andrew said he'd send me a better explanation in a bit, so I'll update this with that information soon.

deanishe commented 10 years ago

If there's only one directory, it shouldn't be a problem. I'm wondering if that random number is some kind of machine ID, which will make it a PITA to work out which is the current machine unless Andrew spills the beans on the ID generation.

shawnrice commented 10 years ago

With most scripting languages we can just "wildcard" it, so it wouldn't matter. I'm assuming that we can do that in Objective-C. If not, then we can alter the binary to take an argument that's the plist, and we can determine the directory via wildcard path completion and send it to the binary.

However, @Ritashugisha knows much more than we do about Objective-C.

deanishe commented 10 years ago

On this topic: what about darkening a light icon? Is that possible? (I don't really understand what the conversion code is doing: I just translated the PHP to Python.)

Does the user have to specify the dark icon if they want to use the automatic alteration?

If that's the case, I'd consider renaming the arguments to icon().

deanishe commented 10 years ago

In that case, @Ritashugisha should perhaps take over. Or we bust the Objective-C code down to "give me the background colour in theme XXX as HSV/RGB". My suggestion would be the former: it's going to run a lot faster in Objective-C.

shawnrice commented 10 years ago

It either darkens or lightens. The V space is calculated as a float between 0 and 1 with .5 as neutral. So, the algorithm takes the initial V and subtracts it from 1, which will either lighten or darken the image and keep the "light/dark" distance from the neutral point. So .3 would turn into .7, and .7 would turn into .3.

An easier example is ffffff evaluates to RGB 255,255,255 and HSL 0, 0, 1. So, the algorithm would return an HSL of 0, 0, 0 (1-1=0), which converts to RGB 0,0,0 and Hex 000000.

shawnrice commented 10 years ago

It might run a lot faster, but the utility is only called to evaluate the background right now.

Evaluating the icon is done in the script. Calling it in the script saves us the expensive system calls, and caching the alternate colors makes it even faster.

shawnrice commented 10 years ago

From Andrew: v2.4 b277 pre-release just came out that includes these environmental variables:

    "alfred_preferences" = "/Users/{USERNAME}/Dropbox/Alfred/Alfred.alfredpreferences";
    "alfred_preferences_localhash" = {HASHFORYOSEMITE};
    "alfred_theme" = "alfred.theme.yosemite";
    "alfred_theme_background" = "rgba(255,255,255,0.98)";
    "alfred_theme_iconstyle" = dark;
    "alfred_version" = "2.4";
    "alfred_version_build" = 276;
    "alfred_workflow_uid" = "user.workflow.FDE54875-6670-45CC-9D6B-1879F9257FBB";

The latter is obviously the path to the workflow. Nice.

Since LightOrDark works on earlier versions, we can always test to see if these environmental variables exist, and, if they don't, then we can fallback to the old logic.

Sound good?

deanishe commented 10 years ago

It either darkens or lightens

Oops. Need to rename some stuff and adjust the logic.

Calling it in the script saves us the expensive system calls, and caching the alternate colors makes it even faster

I thought we needed Objective-C to parse the colour?

shawnrice commented 10 years ago

True. We need Objective-C to parse the colo(u)r from the Alfredplist, but we have to deal with the NSColor object only with the theme value, which the binary does for us. And it returns the light or dark, which is all we need to know about the background.

The colo(u)rs for the icons, however, are still hex values, and we don't need Objective-C to parse those. We could have the binary parse the hex color for us, but then we'd have to make a system call for each icon that has the "alter" flag set rather than just staying with native code.

shawnrice commented 10 years ago

Actually. We don't need the LightOrDark binary at all for v2.4.277+. We can use the alfred_theme_background environmental variables to calculate the value.

shawnrice commented 10 years ago

Here is the new PHP code to test for the light/dark theme when 2.4.277+ in case the logic helps with other languages. I put this in the __construct() method.

if ( isset( $_ENV[ 'alfred_version' ] ) ) {
      // As of Alfred v2.4 Build 277, environmental variables are available
      // that will make this process a lot easier and faster.
      $this->alfredVersion = array( 'version' => $_ENV[ 'alfred_version' ],
                            'build'  => $_ENV[ 'alfred_version_build' ]);
      $this->home = $_ENV[ 'HOME' ];
      $this->alfredPreferences = $_ENV[ 'alfred_preferences' ];
      $this->preferencesHash = $_ENV[ 'alfred_preferences_local_hash' ];
      $this->themeBackground = $_ENV[ 'alfred_theme_background' ];
      $this->theme = $_ENV[ 'alfred_theme' ];

      $plist = "{$this->alfredPreferences}/preferences/local/{$this->preferencesHash}/appearance/prefs.plist";

      if ( ! file_exists( "{$this->data}/data" ) ) {
        mkdir( "{$this->data}/data", 0775, TRUE );
      }

      if ( file_exists( "{$this->data}/data/theme_background" ) ) {
        if ( filemtime( "{$this->data}/data/theme_background" > $plist ) ) {
          $this->background = file_get_contents( "{$this->data}/data/theme_background" );
        } else {
          $update = TRUE;
        }
      } else {
          $update = TRUE;
      }
      if ( isset( $update ) && ( $update == TRUE ) ) {
           // See if RGB value is greater than 127, if so, background is light,
          // else, dark
          preg_match_all("/rgba\(([0-9]{3}),([0-9]{3}),([0-9]{3}),([0-9.]{4,})\)/", "rgba(236,237,216,0.00)", $matches);
          $r = $matches[1];
          $g = $matches[2];
          $b = $matches[3];
          if ( ( ( $r * 299 ) + ( $g * 587 ) + ( $b * 114 ) ) / 1000 > 127 )
            $this->background = 'light';
          else
            $this->background = 'dark';
          file_put_contents( "{$this->data}/data/theme_background", $this->background );
      }
    } else {
      // Pre Alfred v2.4:277.

      // Do stuff here
      $this->setBackground();
    }

Added in 731130472553145796fd4be4946bf6ac0303fb98

shawnrice commented 10 years ago

Whoops. Forgot some code. Altered it above. Fixed it in a462bf2d512e301f34c6d0bd02f43718b27bfe76

deanishe commented 10 years ago

I added this behaviour to the Python version, too.

Am I right in thinking the utility no longer needs changing? It works as before on version 2.3, and the environmental variable method works on 2.4+?

shawnrice commented 10 years ago

You are correct, sir.

But, with the new bundle id and name environmental variables (as of today), we now can remove most of the plist interfacing that we need (well, keep it as a backup).

For testing purposes, we can just use scripts that export the bundle id and name variables so that we don't have to test from inside Alfred. It'll also make writing the automated tests easier.

deanishe commented 10 years ago

I'm closing this issue as fixed.