Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove custom-color-by-theme method, add resolve-color method #17567

Merged
merged 2 commits into from
Oct 16, 2023

Conversation

J-Son89
Copy link
Contributor

@J-Son89 J-Son89 commented Oct 6, 2023

This pr continues: #16400

In this pr: I remove the use of custom-color-by-theme method as from discussions with the design team I have realised there is a better approach.

Additionally I have created a method resolve-color to replace custom-color function because we are using this method beyond "custom" colors, it also has uses for community colors, network colors, semantic colors.

this method removes the use of internal logic (suffix) and instead moves this to be dependent on theme.
This is possible because we only use the 50 suffix for light and 60 suffix for dark theme
For on-press we use a shadow overlay affect to darken/lighten the color - this is a more generic solution as it works with community colors (hex string).

If there is opacity set then we only use the 50 suffix regardless of theme.

To Test:
I have updated the internal logic to resolve colors of the following components:

avatars/account-avatar
avatars/channel-avatar
avatars/user-avatar

calendar/calendar-day
code/code-snippet
dividers/new-messages
list-items/account-list-card
list-items/channel
list-items/community
list-items/token-value
record-audio/record-audio
selectors/selectors
settings/accounts
wallet/keypair
wallet/network-bridge
wallet/network-link

This was all contained in the quo2 components, probably it will help to have a design review to check the colors too - no component structures etc where changed 👍

@@ -94,17 +93,15 @@
:active-count 112100
:unread-count 5})]
(fn []
(let [customization-color (colors/custom-color-by-theme (:customization-color @state) 50 60)]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the resolving of custom colors should be done internally in the component

@@ -40,8 +39,7 @@
:customization-color :blue
:locked? nil})]
(fn []
(let [customization-color (colors/custom-color-by-theme (:customization-color @state) 50 60)]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the resolving of custom colors should be done internally in the component

@@ -223,8 +223,7 @@
60 "#BD1E56"}})

;;;; Networks

(def networks
(def ^:private networks
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should have the maps private so the mechanism is the way to interact with colors 👍

@status-im-auto
Copy link
Member

status-im-auto commented Oct 6, 2023

Jenkins Builds

Click to see older builds (28)
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ ee87ef4 #1 2023-10-06 10:00:25 ~6 min android-e2e 🤖apk 📲
✔️ ee87ef4 #1 2023-10-06 10:00:46 ~6 min android 🤖apk 📲
✔️ ee87ef4 #1 2023-10-06 10:03:05 ~8 min ios 📱ipa 📲
✔️ ee87ef4 #1 2023-10-06 10:03:14 ~8 min tests 📄log
5561a29 #2 2023-10-09 11:42:04 ~2 min tests 📄log
✔️ 5561a29 #2 2023-10-09 11:45:18 ~6 min android-e2e 🤖apk 📲
✔️ 5561a29 #2 2023-10-09 11:45:19 ~6 min android 🤖apk 📲
✔️ 5561a29 #2 2023-10-09 11:47:25 ~8 min ios 📱ipa 📲
24b68e7 #3 2023-10-12 11:39:12 ~2 min tests 📄log
✔️ 24b68e7 #3 2023-10-12 11:42:58 ~6 min android-e2e 🤖apk 📲
✔️ 24b68e7 #3 2023-10-12 11:43:06 ~6 min android 🤖apk 📲
✔️ 24b68e7 #3 2023-10-12 11:48:43 ~12 min ios 📱ipa 📲
✔️ b47d2c8 #4 2023-10-12 12:05:57 ~5 min android-e2e 🤖apk 📲
✔️ b47d2c8 #4 2023-10-12 12:06:30 ~6 min android 🤖apk 📲
✔️ b47d2c8 #4 2023-10-12 12:09:44 ~9 min ios 📱ipa 📲
b47d2c8 #5 2023-10-12 12:30:49 ~8 min tests 📄log
fc4e184 #6 2023-10-12 22:07:10 ~2 min tests 📄log
✔️ fc4e184 #5 2023-10-12 22:09:59 ~5 min android 🤖apk 📲
✔️ fc4e184 #5 2023-10-12 22:10:00 ~5 min android-e2e 🤖apk 📲
✔️ fc4e184 #5 2023-10-12 22:13:52 ~9 min ios 📱ipa 📲
✔️ 2c1c258 #6 2023-10-13 11:48:15 ~5 min android 🤖apk 📲
✔️ 2c1c258 #6 2023-10-13 11:50:36 ~8 min android-e2e 🤖apk 📲
✔️ 2c1c258 #7 2023-10-13 11:52:15 ~9 min tests 📄log
✔️ 2c1c258 #6 2023-10-13 11:54:53 ~12 min ios 📱ipa 📲
43a9fb1 #8 2023-10-15 15:04:47 ~2 min tests 📄log
✔️ 43a9fb1 #7 2023-10-15 15:08:28 ~6 min android-e2e 🤖apk 📲
✔️ 43a9fb1 #7 2023-10-15 15:08:28 ~6 min android 🤖apk 📲
✔️ 43a9fb1 #7 2023-10-15 15:15:57 ~13 min ios 📱ipa 📲
Commit #️⃣ Finished (UTC) Duration Platform Result
2583143 #9 2023-10-16 07:50:37 ~2 min tests 📄log
✔️ 2583143 #8 2023-10-16 07:53:26 ~5 min android-e2e 🤖apk 📲
✔️ 2583143 #8 2023-10-16 07:53:40 ~5 min android 🤖apk 📲
✔️ 9e865e0 #9 2023-10-16 08:03:01 ~5 min android-e2e 🤖apk 📲
✔️ 9e865e0 #9 2023-10-16 08:03:45 ~6 min ios 📱ipa 📲
✔️ 9e865e0 #9 2023-10-16 08:04:41 ~7 min android 🤖apk 📲
✔️ 9e865e0 #10 2023-10-16 08:06:50 ~9 min tests 📄log

@J-Son89 J-Son89 changed the title Jc/rename color system remove custom-color-by-theme method, add resolve-color method Oct 6, 2023
@J-Son89 J-Son89 self-assigned this Oct 6, 2023
Copy link
Contributor

@ilmotta ilmotta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to see we're touching the colors API.

If there is opacity set then we only use the 50 suffix regardless of theme.

I think we just need to be careful because if this trick based on the opacity stops being correct, we'll need to change a lot of code to pass a theme instead of nil. Because there's nothing stopping designers to make themeable colors with opacity in the future.

Another way to look at the resolve-color function is that the consumer should not know if the theme is needed or not internally, so the caller always pass the theme. This is my preferred choice because it's more future proof, we would change the function to be:

(defn resolve-color
  ([color theme]
   (do-resolve-color color theme nil))
  ([color theme opacity]
   ...))

(alpha resolved-color (/ opacity 100))
resolved-color))))))

(def ^{:deprecated true :superseded-by "resolve-colors"}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: should be resolve-color

color hex string or keyword (resolves from custom, network and semantic colors)
theme :light/:dark
opacity 0-100 (optional) - if set theme is ignored and goes to 50 suffix internally"
(memoize
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to define two functions, one memoized, the other normal/non-memoized, similar to quo2.components.icon. In many occasions (in status-mobile repo or not) I had to do this work manually while in the REPL because I didn't want the function to return the same memoized value.

For instance, for this particular color namespace, if I'm changing any of the vars used by resolve-color like colors-map or customization, the memoized function won't see the new values, which either forces the developer to delete the memoized call during development or extract to a separate var.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure I can add this. it should be like this?

(defn resolve-color
     ([color theme]
      (resolve-color color theme nil))
     ([color theme opacity]
      (let [suffix           (cond opacity         50
                                   (= :dark theme) 60
                                   :else           50)
            resolve-keyword? (keyword? color)
            resolved-color   (if resolve-keyword?
                               (get-from-colors-map color suffix)
                               color)]
        (if opacity
          (alpha resolved-color (/ opacity 100))
          resolved-color))))

(def memo-resolve-color (memoize resolve-color))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, we should have some guidance of when to use each. or the non memo is just for testing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@J-Son89, similar to what we do with the icon component, or the i18n/label function, it's the opposite of the code you shared previously.

The final implementation would be:

  • public var resolve-color
  • private var do-resolve-color, or non-memo-resolve-color, or resolve-color-1 (quite common in the lisp tradition), etc.

Having the non-memoized function defined separately from the public & memoized one gives the developer the chance to change implementations in the REPL more conveniently. It's not a big deal, but I think it's a sensible thing to do, a good practice.

For instance:

  1. resolve-color depends on colors-map, and colors-map depends on customization and networks.
  2. If in a REPL session I call (resolve-color :blue :light), the value will be cached in memory, and if I call with the same args again, the same value will be returned.
  3. If I go ahead and change what :blue means in the colors-map, evaluate in the REPL the new colors-map var, the new blue value won't be used because resolve-color will return the cached value. For the new value to be returned, I need now to also re-evaluate the var resolve-color to reset the memoization cache. This makes iterating in the implementation less convenient, and sometimes frustrating because the dev thinks the implementation has a bug, when in fact it was just using cached results. This flow I'm sharing is happening outside the write file + rerun test, or the hot-reload, here I'm just using the REPL without even saving the file.

I hope what I said makes sense :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other reason could be for testing as you said, although I think it's fine for resolve-color. One could argue that it's better to test the pure function only, and ignore the stateful/memoized one, since testing with memoization is just re-testing the core Clojure function behavior, which could be seen as pointless.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@J-Son89 I agree about add a separate def for the memoized version. In production code we will always use the memoized one and just for testing the one that is not memoized.

I'd like to suggest a refactoring:

(defn- resolve-color*
  ([color theme]
   (resolve-color* color theme nil))
  ([color theme opacity]
   (let [suffix (if (or opacity (= theme :light))
                  50
                  60)]
     (cond-> color
       (keyword? color) (get-from-colors-map suffix)
       opacity          (alpha (/ opacity 100))))))

(defn resolve-color (memoize resolve-color*))

The problem is I feel a little uncomfortable with the suffix var since we are calculating it even if we might not use it (it'll be unused if (keyword? color) is false 🤔). Instead, if we depend on the value of suffix:

(defn- resolve-color*
  ([color theme]
   (resolve-color* color theme nil))
  ([color theme opacity]
   (let [suffix (cond
                  (not (keyword? color))        nil
                  (or opacity (= theme :light)) 50
                  :else                         60)]
     (cond-> color
       suffix  (get-from-colors-map suffix)
       opacity (alpha (/ opacity 100))))))

I think this one is not as clear as the previous one, as always, there are trade-offs.

IDK, just a suggestion, you could pick whatever you like more or just keep the current implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok I like this idea, neat! 🧠

(let [suffix (cond opacity 50
(= :dark theme) 60
:else 50)
hex? (not (keyword? color))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is confusing. If I call (resolve-color "blue"), the hex? binding will be true, but it's not a hex color. Suggestion: rename from hex? to unknown-color?.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know about that, we should not be passing a string unless it has # at the start, perhaps we can add some validation on it :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we shouldn't be passing a valid color, but that's what the code reads in the PR. It says hex?, but the check is only verifying it's not a keyword. In case we want to be a bit more precise in the validation, we have the function hex-string?. I guess we could use it, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah definitely, I will add that!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I need to double check about adding this. I will say a function like this will benefit a lot from Mali 👍

([color]
(resolve-color color nil nil))
([color theme-or-opacity]
(if (keyword? theme-or-opacity)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this function is more complicated than it needs to be. The following diff shows a simplified version that passes the unit tests.

I did 3 things:

  1. Normalize the colors-map var where all colors are maps that can vary based on the 50/60 opacity. Once normalized, we don't need special conditions to check if the color is a string hex or not. There's no perf hit here, because the function to resolve the color is memoized anyway.
  2. Made the 2-arity version simpler by not checking if the second arg is a keyword or not. I think it's just fine to pass nil as the second argument when calling (resolve-color some-color nil 50). I prefer this way because there's no surprise. The dev doesn't need to remember that the second arg may be an opacity or theme. Mixing types can be confusing. I don't feel strong about this point, but I tend to prefer explicitness.
  3. Extracted the non-memoized function. It's common to prefix with do-, but others might prefer other names.
@@ -224,14 +224,14 @@
 
 ;;;; Networks
 (def ^:private networks
-  {:ethereum "#758EEB"
-   :optimism "#E76E6E"
-   :arbitrum "#6BD5F0"
-   :zkSync   "#9FA0FE"
-   :hermez   "#EB8462"
-   :xDai     "#3FC0BD"
-   :polygon  "#AD71F3"
-   :unknown  "#EEF2F5"})
+  {:ethereum {50 "#758EEB" 60 "#758EEB"}
+   :optimism {50 "#E76E6E" 60 "#E76E6E"}
+   :arbitrum {50 "#6BD5F0" 60 "#6BD5F0"}
+   :zkSync   {50 "#9FA0FE" 60 "#9FA0FE"}
+   :hermez   {50 "#EB8462" 60 "#EB8462"}
+   :xDai     {50 "#3FC0BD" 60 "#3FC0BD"}
+   :polygon  {50 "#AD71F3" 60 "#AD71F3"}
+   :unknown  {50 "#EEF2F5" 60 "#EEF2F5"}})
 
 (def ^:private colors-map
   (merge {:primary {50 primary-50
@@ -257,31 +257,26 @@
   [s]
   (and (string? s) (string/starts-with? s "#")))
 
+(defn- do-resolve-color
+  ([color]
+   (do-resolve-color color nil nil))
+  ([color theme]
+   (do-resolve-color color theme nil))
+  ([color theme opacity]
+   (let [suffix         (cond opacity         50
+                              (= :dark theme) 60
+                              :else           50)
+         resolved-color (get-in colors-map [color suffix] color)]
+     (if opacity
+       (alpha resolved-color (/ opacity 100))
+       resolved-color))))
+
 (def resolve-color
   "(resolve-color color theme opacity)
    color   hex string or keyword (resolves from custom, network and semantic colors)
    theme  :light/:dark
    opacity 0-100 (optional) - if set theme is ignored and goes to 50 suffix internally"
-  (memoize
-   (fn
-     ([color]
-      (resolve-color color nil nil))
-     ([color theme-or-opacity]
-      (if (keyword? theme-or-opacity)
-        (resolve-color color theme-or-opacity nil)
-        (resolve-color color nil theme-or-opacity)))
-     ([color theme opacity]
-      (let [suffix         (cond opacity         50
-                                 (= :dark theme) 60
-                                 :else           50)
-            hex?           (not (keyword? color))
-            resolved-color (cond hex?                                 color
-                                 (hex-string? (get colors-map color)) (get colors-map color)
-                                 :else                                (get-in colors-map
-                                                                              [color suffix]))]
-        (if opacity
-          (alpha resolved-color (/ opacity 100))
-          resolved-color))))))
+  (memoize do-resolve-color))
 
 (def ^{:deprecated true :superseded-by "resolve-colors"}
      custom-color

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we can normalise the network colors, if kind of breaks the mould a bit however as there is no -60 network colors in the foundations file.

Another thing is we need the hex string for community colors as that's how they come from the backend

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we can normalise the network colors, if kind of breaks the mould a bit however as there is no -60 network colors in the foundations file.

Exactly, tradeoffs.

Another thing is we need the hex string for community colors as that's how they come from the backend

Could you explain this part @J-Son89? I kind of understand.


About the implementation I suggested, another improvement is to avoid calling twice (get colors-map color). This one also passes the unit tests.

(defn- do-resolve-color
  ([color theme]
   (do-resolve-color color theme nil))
  ([color theme opacity]
   (let [suffix   (cond opacity         50
                        (= :dark theme) 60
                        :else           50)
         resolved (if (hex-string? color)
                    color
                    (let [maybe-resolved (get colors-map color)]
                      (if (hex-string? maybe-resolved)
                        maybe-resolved
                        (get-in colors-map [color suffix]))))]
     (if opacity
       (alpha resolved (/ opacity 100))
       resolved))))

(def resolve-color (memoize do-resolve-color))

Copy link
Contributor Author

@J-Son89 J-Son89 Oct 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, apologies I also meant to revert this -
'''
(if (keyword? theme-or-opacity)

  •    (resolve-color color theme-or-opacity nil)
    
  •    (resolve-color color nil theme-
    

'''
It was just an idea I was experimenting with before discussing with you. D'oh! 🤦‍♂️

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With community colors, the creator of a community can make that any hex string they like. However with user colors, network colors and chat colors these are all from a predefined palette decides by the design team. Hopefully that's a bit clearer 😅

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is, thank you @J-Son89!

@J-Son89
Copy link
Contributor Author

J-Son89 commented Oct 6, 2023

Great to see we're touching the colors API.

If there is opacity set then we only use the 50 suffix regardless of theme.

I think we just need to be careful because if this trick based on the opacity stops being correct, we'll need to change a lot of code to pass a theme instead of nil. Because there's nothing stopping designers to make themeable colors with opacity in the future.

Another way to look at the resolve-color function is that the consumer should not know if the theme is needed or not internally, so the caller always pass the theme. This is my preferred choice because it's more future proof, we would change the function to be:

(defn resolve-color

  ([color theme]

   (do-resolve-color color theme nil))

  ([color theme opacity]

   ...))

Sure I'm happy to have this future proofed 👌

@ilmotta
Copy link
Contributor

ilmotta commented Oct 6, 2023

[Not within the scope of your PR to fix]

@J-Son89, since we're reviewing some color stuff, and maybe this is a question others also have. Do you know why certain color vars are defined in foundations.colors but they are not in Figma Foundations?

I didn't review everything in the namespace, but found these colors for example:

  • neutral-50-opa-40 Used a few times.
  • onboarding-header-black used once.
  • black-opa-30 used once.
  • black-opa-60 used once.

I believe these colors should live outside the foundations.colors namespace if we want to mirror Figma, unless they are in the Foundations Colors page and I couldn't find. Wdty? Should we move them to status_im2/ in the future?

@J-Son89
Copy link
Contributor Author

J-Son89 commented Oct 9, 2023

[Not within the scope of your PR to fix]

@J-Son89, since we're reviewing some color stuff, and maybe this is a question others also have. Do you know why certain color vars are defined in foundations.colors but they are not in Figma Foundations?

I didn't review everything in the namespace, but found these colors for example:

  • neutral-50-opa-40 Used a few times.
  • onboarding-header-black used once.
  • black-opa-30 used once.
  • black-opa-60 used once.

I believe these colors should live outside the foundations.colors namespace if we want to mirror Figma, unless they are in the Foundations Colors page and I couldn't find. Wdty? Should we move them to status_im2/ in the future?

sure, I will get this addressed. I have a lot of work to continue to do here to organise this colors better so this is good to include in that set of work.

Copy link
Contributor

@ilmotta ilmotta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Thank you for this PR @J-Son89.

@@ -83,7 +83,7 @@
:width (:size opts)
:borderRadius (style/get-border-radius (:size opts))
:borderWidth 0.8
:backgroundColor (colors/custom-color-by-theme (:customization-color opts) 50 50 10 10)})
:backgroundColor (colors/resolve-color (:customization-color opts) :light 10)})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the word resolve you chose, and I think the code would be just as clear with the more succinct (colors/resolve ...). If you do this, you'll need to use (:refer-clojure :exclude [resolve]).

Copy link
Member

@smohamedjavid smohamedjavid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! @J-Son89 🚀🚀🚀

It's good to see the notion doc is getting into action. 😄 🎉

Copy link
Contributor

@ulisesmac ulisesmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just left small comments.

Thanks for this PR! 👍 💯

Comment on lines 260 to 264
(defn- get-from-colors-map
[color suffix]
(if (hex-string? (get colors-map color))
(get colors-map color)
(get-in colors-map [color suffix])))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's not a good idea to take a variable number of args inside the function if a condition becomes true, i.e. we only use suffix if the result of (hex-string? ...) is true.

So I'd suggest splitting into to functions:

(defn- get-from-colors-map
  ([color]
   (get colors-map color))
  ([color suffix]
   (get-in colors-map [color suffix])))

We are using both params when provided, it doesn't matter if it's not a hex string, since:

(get "#a hex string" 60)
;; => nil

so we are safe.

And the previous suggestion leads me to think in a more simple function to extract the values:

(defn- get-from-colors-map [& path]
  (get-in colors-map path))

@J-Son89 WDYT?

Copy link
Contributor Author

@J-Son89 J-Son89 Oct 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is kind of needed for structures like network colors map to work ->

(def ^:private networks
  {:ethereum "#758EEB"
   :optimism "#E76E6E"
   :arbitrum "#6BD5F0"
   :zkSync   "#9FA0FE"
   :hermez   "#EB8462"
   :xDai     "#3FC0BD"
   :polygon  "#AD71F3"
   :unknown  "#EEF2F5"})

the alternative is to normalise the data such as @ilmotta suggested but tbh I don't like this as it breaks what is in the foundations file and I prefer to match the mechanism the designers have provided so this system is in some sense self documenting then.
see https://www.figma.com/file/v98g9ZiaSHYUdKWrbFg9eM/Foundations?type=design&node-id=619-10144&mode=dev

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with that, I prefer to not having the data normalized.

And, I was aware of our data structure, the last code I suggested (the get-in version) works for both maps (i.e. the ones with 50/60 and the ones with a string).

color hex string or keyword (resolves from custom, network and semantic colors)
theme :light/:dark
opacity 0-100 (optional) - if set theme is ignored and goes to 50 suffix internally"
(memoize
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@J-Son89 I agree about add a separate def for the memoized version. In production code we will always use the memoized one and just for testing the one that is not memoized.

I'd like to suggest a refactoring:

(defn- resolve-color*
  ([color theme]
   (resolve-color* color theme nil))
  ([color theme opacity]
   (let [suffix (if (or opacity (= theme :light))
                  50
                  60)]
     (cond-> color
       (keyword? color) (get-from-colors-map suffix)
       opacity          (alpha (/ opacity 100))))))

(defn resolve-color (memoize resolve-color*))

The problem is I feel a little uncomfortable with the suffix var since we are calculating it even if we might not use it (it'll be unused if (keyword? color) is false 🤔). Instead, if we depend on the value of suffix:

(defn- resolve-color*
  ([color theme]
   (resolve-color* color theme nil))
  ([color theme opacity]
   (let [suffix (cond
                  (not (keyword? color))        nil
                  (or opacity (= theme :light)) 50
                  :else                         60)]
     (cond-> color
       suffix  (get-from-colors-map suffix)
       opacity (alpha (/ opacity 100))))))

I think this one is not as clear as the previous one, as always, there are trade-offs.

IDK, just a suggestion, you could pick whatever you like more or just keep the current implementation.

Comment on lines +8 to +24
(defn- view-internal
[{:keys [theme]}]
(let [logged-in? (rf/sub [:multiaccount/logged-in?])
has-profiles? (boolean (rf/sub [:profile/profiles-overview]))
root (if has-profiles? :profiles :intro)
light? (= (theme/get-theme) :light)]
light? (= theme :light)]
[quo/page-nav
{:type :title
:title "Quo2 components preview"
:text-align :left
:icon-name :i/close
:right-side [{:icon-name (if light? :i/dark :i/light)
:on-press #(if light? (theme/set-theme :dark) (theme/set-theme :light))}]
:on-press #(if light? (quo.theme/set-theme :dark) (quo.theme/set-theme :light))}]
:on-press #(if (or logged-in? (not= (rf/sub [:view-id]) :quo2-preview))
(rf/dispatch [:navigate-back])
(do
(theme/set-theme :dark)
(quo.theme/set-theme :dark)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good improvement! 👍

@J-Son89 J-Son89 force-pushed the jc/rename-color-system branch 2 times, most recently from 24b68e7 to b47d2c8 Compare October 12, 2023 12:00
@J-Son89
Copy link
Contributor Author

J-Son89 commented Oct 12, 2023

@ulisesmac I will move this pr forward to QA as the discussions are only about the internals of the resolve-color mechanism. Which I am happy to adjust ofc!
However this won't affect the output of this functions and it seems we have consensus on the outer api of resolve-color which is the main thing to move this pr forward.

@status-im-auto
Copy link
Member

84% of end-end tests have passed

Total executed tests: 43
Failed tests: 7
Passed tests: 36
IDs of failed tests: 702732,703495,702783,702786,702846,702731,702808 

Failed tests (7)

Click to expand
  • Rerun failed tests

  • Class TestOneToOneChatMultipleSharedDevicesNewUiTwo:

    1. test_1_1_chat_is_shown_message_sent_delivered_from_offline, id: 702783

    Device 2: Find `Text` by `xpath`: `//*[starts-with(@text,'test message')]/ancestor::android.view.ViewGroup[@content-desc='chat-item']//*[@content-desc='message-status']/android.widget.TextView`
    Device 2: `Text` is `Delivered`

    critical/chats/test_1_1_public_chats.py:601: in test_1_1_chat_is_shown_message_sent_delivered_from_offline
        self.errors.verify_no_errors()
    base_test_case.py:191: in verify_no_errors
        pytest.fail('\n '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
     Message was not delivered after resending from offline 
    

    [[Data delivery issue]]

    Device sessions

    Class TestCommunityOneDeviceMerged:

    1. test_community_navigate_to_channel_when_relaunch, id: 702846

    ## Signed in successfully!
    Device 1: Looking for a message by text: some_text

    critical/chats/test_public_chat_browsing.py:81: in test_community_navigate_to_channel_when_relaunch
        self.drivers[0].fail("Not navigated to channel view after reopening app")
    base_test_case.py:179: in fail
        pytest.fail('Device %s: %s' % (self.number, text))
     Device 1: Not navigated to channel view after reopening app
    



    Device sessions

    Class TestCommunityMultipleDeviceMergedTwo:

    1. test_community_mentions_push_notification, id: 702786

    Device 2: Getting PN by 'user_2'
    Device 2: Looking for a message by text: user_2

    critical/chats/test_public_chat_browsing.py:874: in test_community_mentions_push_notification
        self.errors.verify_no_errors()
    base_test_case.py:191: in verify_no_errors
        pytest.fail('\n '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
     Can not edit a message with a mention
    



    Device sessions

    Class TestOneToOneChatMultipleSharedDevicesNewUi:

    1. test_1_1_chat_pin_messages, id: 702731

    Test is not run, e2e blocker  
    

    [[reason: [NOTRUN] Pin feature is in development]]

    Class TestGroupChatMultipleDeviceMergedNewUI:

    1. test_group_chat_pin_messages, id: 702732

    Test is not run, e2e blocker  
    

    [[reason: [NOTRUN] Pin feature is in development]]

    2. test_group_chat_mute_chat, id: 703495

    Device 2: Click until ChatMessageInput by accessibility id: chat-message-input will be presented
    Device 2: Looking for a message by text: Chat is unmuted now

    critical/chats/test_group_chat.py:473: in test_group_chat_mute_chat
        self.errors.verify_no_errors()
    base_test_case.py:191: in verify_no_errors
        pytest.fail('\n '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
     New messages counter near chats tab button is 1 after unmute, but should be 2
    



    Device sessions

    3. test_group_chat_offline_pn, id: 702808

    Device 3: Looking for a message by text: message from old member
    Device 3: Looking for a message by text: message from new member

    critical/chats/test_group_chat.py:309: in test_group_chat_offline_pn
        self.errors.verify_no_errors()
    base_test_case.py:191: in verify_no_errors
        pytest.fail('\n '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
     Messages PN was not fetched from offline 
    

    [[Data delivery issue]]

    Device sessions

    Passed tests (36)

    Click to expand

    Class TestOneToOneChatMultipleSharedDevicesNewUiTwo:

    1. test_1_1_chat_delete_via_long_press_relogin, id: 702784
    Device sessions

    2. test_1_1_chat_mute_chat, id: 703496
    Device sessions

    Class TestCommunityMultipleDeviceMerged:

    1. test_community_several_images_send_reply, id: 703194
    Device sessions

    2. test_community_one_image_send_reply, id: 702859
    Device sessions

    3. test_community_emoji_send_copy_paste_reply, id: 702840
    Device sessions

    4. test_community_mark_all_messages_as_read, id: 703086
    Device sessions

    5. test_community_contact_block_unblock_offline, id: 702894
    Device sessions

    6. test_community_message_delete, id: 702839
    Device sessions

    7. test_community_message_send_check_timestamps_sender_username, id: 702838
    Device sessions

    8. test_community_links_with_previews_github_youtube_twitter_gif_send_enable, id: 702844
    Device sessions

    9. test_community_message_edit, id: 702843
    Device sessions

    10. test_community_unread_messages_badge, id: 702841
    Device sessions

    Class TestActivityMultipleDevicePRTwo:

    1. test_activity_center_mentions, id: 702957
    Device sessions

    2. test_activity_center_admin_notification_accept_swipe, id: 702958
    Device sessions

    Class TestActivityMultipleDevicePR:

    1. test_navigation_jump_to, id: 702936
    Device sessions

    2. test_activity_center_reply_read_unread_delete_filter_swipe, id: 702947
    Device sessions

    Class TestCommunityOneDeviceMerged:

    1. test_restore_multiaccount_with_waku_backup_remove_switch, id: 703133
    Device sessions

    2. test_community_copy_and_paste_message_in_chat_input, id: 702742
    Device sessions

    3. test_community_discovery, id: 703503
    Device sessions

    4. test_community_undo_delete_message, id: 702869
    Device sessions

    5. test_community_mute_community_and_channel, id: 703382
    Device sessions

    Class TestOneToOneChatMultipleSharedDevicesNewUi:

    1. test_1_1_chat_emoji_send_reply_and_open_link, id: 702782
    Device sessions

    2. test_1_1_chat_text_message_delete_push_disappear, id: 702733
    Device sessions

    3. test_1_1_chat_push_emoji, id: 702813
    Device sessions

    4. test_1_1_chat_non_latin_messages_stack_update_profile_photo, id: 702745
    Device sessions

    5. test_1_1_chat_edit_message, id: 702855
    Device sessions

    6. test_1_1_chat_send_image_save_and_share, id: 703391
    Device sessions

    7. test_1_1_chat_message_reaction, id: 702730
    Device sessions

    Class TestCommunityMultipleDeviceMergedTwo:

    1. test_community_markdown_support, id: 702809
    Device sessions

    2. test_community_hashtag_links_to_community_channels, id: 702948
    Device sessions

    3. test_community_leave, id: 702845
    Device sessions

    Class TestGroupChatMultipleDeviceMergedNewUI:

    1. test_group_chat_send_image_save_and_share, id: 703297
    Device sessions

    2. test_group_chat_reactions, id: 703202
    Device sessions

    3. test_group_chat_join_send_text_messages_push, id: 702807
    Device sessions

    Class TestActivityCenterContactRequestMultipleDevicePR:

    1. test_activity_center_contact_request_accept_swipe_mark_all_as_read, id: 702851
    Device sessions

    2. test_activity_center_contact_request_decline, id: 702850
    Device sessions

    @J-Son89 J-Son89 force-pushed the jc/rename-color-system branch from b47d2c8 to fc4e184 Compare October 12, 2023 22:04
    @pavloburykh pavloburykh self-assigned this Oct 13, 2023
    @J-Son89 J-Son89 force-pushed the jc/rename-color-system branch from fc4e184 to 2c1c258 Compare October 13, 2023 11:42
    @pavloburykh
    Copy link
    Contributor

    @J-Son89 thank you! no issues from my side. Ready for design review. cc @Francesca-G

    @J-Son89 J-Son89 force-pushed the jc/rename-color-system branch from 2c1c258 to 43a9fb1 Compare October 15, 2023 15:02
    Copy link

    @Francesca-G Francesca-G left a comment

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Colors look good to me ✨

    @J-Son89 J-Son89 force-pushed the jc/rename-color-system branch from 43a9fb1 to 2583143 Compare October 16, 2023 07:47
    @J-Son89 J-Son89 force-pushed the jc/rename-color-system branch from 2583143 to 9e865e0 Compare October 16, 2023 07:57
    @J-Son89 J-Son89 merged commit dd20d88 into develop Oct 16, 2023
    2 checks passed
    @J-Son89 J-Son89 deleted the jc/rename-color-system branch October 16, 2023 08:20
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    Archived in project
    Archived in project
    Development

    Successfully merging this pull request may close these issues.

    8 participants