summaryrefslogtreecommitdiff
path: root/src/com/google/gct/login/ui/UsersListCellRenderer.java
blob: e74531e6bf187c461878b05b57744c07048baa98 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.gct.login.ui;

import com.google.api.client.util.Maps;
import com.google.gct.login.CredentialedUser;
import com.google.gct.login.GoogleLogin;
import com.intellij.ui.JBColor;
import com.intellij.util.ui.UIUtil;
import icons.GoogleLoginIcons;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.util.Map;

/**
 * A custom cell render for {@link GoogleLoginUsersPanel#list} that manages
 * how each user item in the Google Login panel would be displayed.
 */
public class UsersListCellRenderer extends JComponent implements ListCellRenderer {
  private final static String CLOUD_LABEL_TEXT = "Open Google Developers Console";
  private final static String PLAY_LABEL_TEXT = "Open Google Play Console";
  private final static String DEFAULT_AVATAR = "/icons/loginAvatar@2x.png";
  private final static String SIGN_IN_TEXT = "<HTML> Sign in with your Google account to start <br> adding "
    + "Cloud functionality to your <br> Android applications from Android Studio. </HTML>";
  private static final String LEARN_MORE_TEXT = "Learn more";
  private static final int PLAIN_USER_IMAGE_WIDTH = 48;
  private static final int PLAIN_USER_IMAGE_HEIGHT = 48;
  private static final int ACTIVE_USER_IMAGE_WIDTH = 96;
  private static final int ACTIVE_USER_IMAGE_HEIGHT = 96;
  private static final int GOOGLE_IMAGE_NORTH = 18;
  private static final int GOOGLE_IMAGE_WEST = 18;
  private static final int WELCOME_LABEL_NORTH = 15;
  private static final int WELCOME_LABEL_SOUTH = 25;
  private static final int WELCOME_LABEL_EAST = 38;
  private static final int USER_LABEL_VERTICAL_STRUT = 3;
  private static final int HGAP = 10;
  private static final int VGAP = 10;
  private final Color myActiveColor;
  private final Color myInactiveColor;
  private final int myGeneralFontHeight;
  private final Font myNameFont;
  private final Font myGeneralFont;
  private final Dimension myMainPanelDimension;
  private final Dimension myActiveMainPanelDimension;
  private final Dimension myCloudLabelDimension;
  private final Dimension myPlayLabelDimension;
  private final Dimension myLearnMoreLabelDimension;
  private JLabel myGoogleImageLabel;

  /** Maps user emails to large user image icons. */
  private final Map<String, Image> myUserLargeImageCache = Maps.newHashMap();
  /** Maps user emails to small user image icons. */
  private final Map<String, Image> myUserSmallImageCache = Maps.newHashMap();

  public UsersListCellRenderer() {
    myNameFont = new Font("Helvetica", Font.BOLD, 13);
    myGeneralFont = new Font("Helvetica", Font.PLAIN, 13);
    myMainPanelDimension = new Dimension(250, 68);
    myActiveMainPanelDimension = new Dimension(250, 116);
    myActiveColor = UIUtil.isUnderDarcula() ? UIManager.getColor("TextField.background") : Color.WHITE;
    myInactiveColor = UIUtil.isUnderDarcula() ? UIManager.getColor("darcula.inactiveBackground") : new Color(0xf5f5f5);

    FontMetrics fontMetrics = getFontMetrics(myGeneralFont);
    myGeneralFontHeight = fontMetrics.getHeight();
    myCloudLabelDimension = new Dimension(fontMetrics.stringWidth(CLOUD_LABEL_TEXT), myGeneralFontHeight);
    myPlayLabelDimension = new Dimension(fontMetrics.stringWidth(PLAY_LABEL_TEXT), myGeneralFontHeight);
    myLearnMoreLabelDimension = new Dimension(fontMetrics.stringWidth(LEARN_MORE_TEXT), myGeneralFontHeight);
  }

  @Nullable
  @Override
  public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    if (value instanceof NoUsersListItem) {
      return createNoUserDisplay();
    }
    if (!(value instanceof UsersListItem)) {
      return null;
    }

    final UsersListItem usersListItem = (UsersListItem)value;
    final CredentialedUser activeUser = GoogleLogin.getInstance().getActiveUser();
    final boolean isActiveUserSelected = activeUser != null && usersListItem.getUserEmail().equals(activeUser.getEmail());

    JPanel mainPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, HGAP, VGAP));
    mainPanel.setMinimumSize(isActiveUserSelected ? myActiveMainPanelDimension : myMainPanelDimension);
    mainPanel.setAlignmentX(LEFT_ALIGNMENT);

    // Update colors
    final Color bg = isActiveUserSelected ? myActiveColor : myInactiveColor;
    final Color fg = isActiveUserSelected ? UIUtil.getListSelectionForeground() : UIUtil.getListForeground();
    mainPanel.setBackground(bg);
    mainPanel.setForeground(fg);

    Image image = usersListItem.getUserPicture();
    if (image == null){
      // Use default profile image.
      image = Toolkit.getDefaultToolkit().getImage(UsersListCellRenderer.class.getResource(DEFAULT_AVATAR));
    }

    final int imageWidth, imageHeight;
    final Map<String, Image> userImageCache;
    if (isActiveUserSelected) {
      imageWidth = ACTIVE_USER_IMAGE_WIDTH;
      imageHeight = ACTIVE_USER_IMAGE_HEIGHT;
      userImageCache = myUserLargeImageCache;
    } else {
      imageWidth = PLAIN_USER_IMAGE_WIDTH;
      imageHeight = PLAIN_USER_IMAGE_HEIGHT;
      userImageCache = myUserSmallImageCache;
    }

    final Image scaledImage;
    if (!userImageCache.containsKey(usersListItem.getUserEmail())) {
      scaledImage = image.getScaledInstance(imageWidth, imageHeight, Image.SCALE_SMOOTH);
      userImageCache.put(usersListItem.getUserEmail(), scaledImage);
    } else {
      scaledImage = userImageCache.get(usersListItem.getUserEmail());
    }

    final JComponent textPanel;
    if (isActiveUserSelected) {
      textPanel = createActiveTextDisplay(usersListItem);
    } else {
      textPanel = createTextDisplay(false, usersListItem);
    }

    mainPanel.add(new JLabel(new ImageIcon(scaledImage)));
    mainPanel.add(textPanel);
    mainPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIUtil.getBorderColor()));

    return mainPanel;
  }

  public boolean inPlayConsoleUrl(Point point, int activeIndex) {
    // 2 is for the number of labels before this one
    double playYStart = VGAP + ACTIVE_USER_IMAGE_HEIGHT - myPlayLabelDimension.getHeight()
      - myCloudLabelDimension.getHeight() - 2 + (myMainPanelDimension.getHeight() * activeIndex)
      + USER_LABEL_VERTICAL_STRUT;
    double playYEnd = playYStart + myPlayLabelDimension.getHeight();
    double playXStart = ACTIVE_USER_IMAGE_WIDTH + HGAP + VGAP;
    double playXEnd = playXStart + myPlayLabelDimension.getWidth();
    return (point.getX() > playXStart) && (point.getX() < playXEnd) && (point.getY() > playYStart) && (point.getY() < playYEnd);
  }

  public boolean inCloudConsoleUrl(Point point, int activeIndex) {
    // 3 is for the number of labels before this one
    double playYStart = VGAP + ACTIVE_USER_IMAGE_HEIGHT - myCloudLabelDimension.getHeight()
      - 3 + (myMainPanelDimension.getHeight() * activeIndex) + (USER_LABEL_VERTICAL_STRUT * 2);
    double playYEnd = playYStart + myCloudLabelDimension.getHeight();
    double playXStart = ACTIVE_USER_IMAGE_WIDTH + HGAP + VGAP;
    double playXEnd = playXStart + myCloudLabelDimension.getWidth();
    return (point.getX() > playXStart) && (point.getX() < playXEnd) && (point.getY() > playYStart) && (point.getY() < playYEnd);
  }

  public boolean inLearnMoreUrl(Point point) {
    // 3 is for the number of labels and row of texts
    double urlYStart = GOOGLE_IMAGE_NORTH + myGoogleImageLabel.getIcon().getIconHeight() + WELCOME_LABEL_NORTH
      + (myGeneralFontHeight * 3) + 3;
    double urlYEnd = urlYStart + myLearnMoreLabelDimension.getHeight();
    double urlXStart = GOOGLE_IMAGE_WEST;
    double urlXEnd = urlXStart + myLearnMoreLabelDimension.getWidth();
    return (point.getX() > urlXStart) && (point.getX() < urlXEnd) && (point.getY() > urlYStart) && (point.getY() < urlYEnd);
  }

  public int getMainPanelHeight() {
    return (int)myMainPanelDimension.getHeight();
  }

  public int getActivePanelHeight() {
    return (int)myActiveMainPanelDimension.getHeight();
  }

  private JComponent createTextDisplay(boolean isSelected, UsersListItem usersListItem) {
    final JPanel panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

    final Color bg = isSelected ? myActiveColor : myInactiveColor;
    final Color fg = isSelected ? UIUtil.getListSelectionForeground() : UIUtil.getListForeground();
    panel.setBackground(bg);
    panel.setForeground(fg);

    JLabel nameLabel = new JLabel( usersListItem.getUserName());
    nameLabel.setFont(myNameFont);
    panel.add(nameLabel);
    panel.add(Box.createVerticalStrut(USER_LABEL_VERTICAL_STRUT));

    JLabel emailLabel = new JLabel(usersListItem.getUserEmail());
    emailLabel.setFont(myGeneralFont);
    panel.add(emailLabel);

    return panel;
  }

  private JComponent createActiveTextDisplay(UsersListItem usersListItem) {
    JPanel mainPanel = new JPanel();
    mainPanel.setLayout(new GridBagLayout());

    mainPanel.setBackground(myActiveColor);
    mainPanel.setForeground(UIUtil.getListSelectionForeground());
    mainPanel.setPreferredSize(new Dimension(220, ACTIVE_USER_IMAGE_HEIGHT));

    JPanel bottomPanel = new JPanel();
    bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.PAGE_AXIS));
    bottomPanel.setBackground(myActiveColor);
    bottomPanel.setForeground(UIUtil.getListSelectionForeground());
    bottomPanel.setPreferredSize(new Dimension(220, (myGeneralFontHeight * 2) + USER_LABEL_VERTICAL_STRUT));

    JLabel playLabel = new JLabel(PLAY_LABEL_TEXT);
    playLabel.setFont(myGeneralFont);
    playLabel.setForeground(JBColor.BLUE);
    playLabel.setPreferredSize(myPlayLabelDimension);
    bottomPanel.add(playLabel, BOTTOM_ALIGNMENT);
    bottomPanel.add(Box.createVerticalStrut(USER_LABEL_VERTICAL_STRUT));

    JLabel cloudLabel = new JLabel(CLOUD_LABEL_TEXT);
    cloudLabel.setFont(myGeneralFont);
    cloudLabel.setForeground(JBColor.BLUE);
    cloudLabel.setPreferredSize(myCloudLabelDimension);
    bottomPanel.add(cloudLabel, BOTTOM_ALIGNMENT);

    GridBagConstraints topConstraints = new GridBagConstraints();
    topConstraints.gridx = 0;
    topConstraints.gridy = 0;
    topConstraints.anchor = GridBagConstraints.NORTHWEST;

    GridBagConstraints bottomConstraints = new GridBagConstraints();
    bottomConstraints.gridx = 0;
    bottomConstraints.gridy = 1;
    bottomConstraints.weightx = 1;
    bottomConstraints.weighty = 5;
    bottomConstraints.anchor = GridBagConstraints.SOUTHWEST;

    JComponent topPanel = createTextDisplay(true, usersListItem);
    mainPanel.add(topPanel, topConstraints);
    mainPanel.add(bottomPanel, bottomConstraints);
    return mainPanel;
  }

  private JPanel createNoUserDisplay() {
    JPanel mainPanel = new JPanel();
    BoxLayout layout = new BoxLayout(mainPanel, BoxLayout.Y_AXIS);
    mainPanel.setLayout(layout);
    mainPanel.setBackground(JBColor.WHITE);
    mainPanel.setBorder(BorderFactory.createEmptyBorder(0, GOOGLE_IMAGE_WEST, 0, 0));

    myGoogleImageLabel = new JLabel(GoogleLoginIcons.GOOGLE_LOGO);

    JLabel signInLabel = new JLabel(SIGN_IN_TEXT);
    signInLabel.setFont(myGeneralFont);
    Dimension textSize = signInLabel.getPreferredSize();
    signInLabel.setPreferredSize(new Dimension((int)textSize.getWidth() + WELCOME_LABEL_EAST, (int)textSize.getHeight()));

    JLabel urlLabel = new JLabel(LEARN_MORE_TEXT);
    urlLabel.setFont(myGeneralFont);
    urlLabel.setForeground(JBColor.BLUE);
    urlLabel.setPreferredSize(myLearnMoreLabelDimension);

    mainPanel.add(Box.createVerticalStrut(GOOGLE_IMAGE_NORTH));
    mainPanel.add(myGoogleImageLabel);
    mainPanel.add(Box.createVerticalStrut(WELCOME_LABEL_NORTH));
    mainPanel.add(signInLabel);
    mainPanel.add(urlLabel);
    mainPanel.add(Box.createVerticalStrut(WELCOME_LABEL_SOUTH));

    return mainPanel;
  }
}