package com.google.photos.library.sample.views;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

/** Represents an abstract view that can show, hide and update itself. */
public abstract class AbstractCustomView extends JFrame {
  private static final String DEFAULT_DIALOG_BACKGROUND = "0xf8f9fa";

  private final LoadingView loadingView;
  private final Thread updateThread;

  public AbstractCustomView() {
    hideView();
    loadingView = LoadingView.getLoadingView();
    updateThread = getUpdateThread();

    getRootPane().setOpaque(false);
    getContentPane().setBackground(Color.decode(DEFAULT_DIALOG_BACKGROUND));
  }

  public final void showView() {
    setVisible(true);
  }

  public final void hideView() {
    setVisible(false);
  }

  /** Initializes the view in a new thread and shows loading indicator. */
  public final void initializeView() {
    loadingView.showView();
    getInitializationThread().start();
  }

  /** Updates the view in a new thread and shows loading indicator. */
  public final void updateView() {
    loadingView.showView();
    updateThread.start();
  }

  /** View initialization method */
  protected abstract void initialize() throws Exception;

  /** View update method */
  protected abstract void update() throws Exception;

  private final Thread getUpdateThread() {
    return new Thread(
        () -> {
          try {
            update();
            loadingView.hideView();
          } catch (Exception e) {
            JOptionPane.showMessageDialog(this, e.getMessage());
          }
        });
  }

  private final Thread getInitializationThread() {
    return new Thread(
        () -> {
          try {
            moveToCenter();
            initialize();
            requestFocusInWindow();
            loadingView.hideView();
            showView();
          } catch (Exception e) {
            JOptionPane.showMessageDialog(this, e.getMessage());
          }
        });
  }

  private final void moveToCenter() {
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    setLocation(
        screenSize.width / 2 - this.getSize().width / 2,
        screenSize.height / 2 - this.getSize().height / 2);
  }
}

@@ -117,16 +117,47 @@
 oolkit;%0A
+import java.lang.Thread.State;%0A
 import j
@@ -452,16 +452,17 @@
 ngView;%0A
+%0A
   privat
@@ -476,28 +476,164 @@
  Thread 
-updateThread
+initializationThread;%0A%0A  private final Object updateLock = new Object();%0A  private Thread updateThread = null;%0A  private boolean rerunUpdate = false
 ;%0A%0A  pub
@@ -731,32 +731,48 @@
     
-updateThread = getUpdate
+initializationThread = getInitialization
 Thre
@@ -1123,32 +1123,90 @@
 tializeView() %7B%0A
+    if (initializationThread.getState() == State.NEW) %7B%0A  
     loadingView.
@@ -1221,20 +1221,19 @@
 ();%0A    
-getI
+  i
 nitializ
@@ -1243,18 +1243,16 @@
 onThread
-()
 .start()
@@ -1245,32 +1245,38 @@
 Thread.start();%0A
+    %7D%0A
   %7D%0A%0A  /** Updat
@@ -1366,24 +1366,250 @@
 ateView() %7B%0A
+    synchronized (updateLock) %7B%0A      if ((updateThread == null %7C%7C updateThread.getState() == State.TERMINATED)%0A          && initializationThread.getState() == State.TERMINATED) %7B%0A        updateThread = getUpdateThread();%0A    
     loadingV
@@ -1624,24 +1624,28 @@
 View();%0A    
+  
+  
 updateThread
@@ -1654,16 +1654,73 @@
 tart();%0A
+      %7D else %7B%0A        rerunUpdate = true;%0A      %7D%0A    %7D%0A
   %7D%0A%0A  /
@@ -1943,34 +1943,39 @@
     
-return new Thread(%0A       
+final Runnable updateRunnable =
  () 
@@ -1981,38 +1981,30 @@
  -%3E %7B%0A      
-  
-  
 try %7B%0A
-    
         upda
@@ -2013,48 +2013,8 @@
 ();%0A
-            loadingView.hideView();%0A    
     
@@ -2031,36 +2031,32 @@
 (Exception e) %7B%0A
-    
         JOptionP
@@ -2110,286 +2110,823 @@
     
+%7D%0A
     %7D
+;
 %0A    
-    %7D);%0A  %7D%0A%0A  private final Thread getInitializationThread() %7B%0A    return new Thread(%0A        () -%3E %7B%0A          try %7B%0A            moveToCenter();%0A            initialize();%0A            requestFocusInWindow();%0A            loadingView.hideView();%0A            showView();
+return new Thread(() -%3E %7B%0A      while (true) %7B%0A        updateRunnable.run();%0A        synchronized (updateLock) %7B%0A          if (rerunUpdate) %7B%0A            rerunUpdate = false;%0A          %7D else %7B%0A            loadingView.hideView();%0A            break;%0A          %7D%0A        %7D%0A      %7D%0A    %7D);%0A  %7D%0A%0A  private final Thread getInitializationThread() %7B%0A    return new Thread(%0A        () -%3E %7B%0A          try %7B%0A            moveToCenter();%0A            initialize();%0A            requestFocusInWindow();%0A            showView();%0A            synchronized (updateLock) %7B%0A              if (rerunUpdate) %7B%0A                rerunUpdate = false;%0A                updateThread = getUpdateThread();%0A                updateThread.start();%0A              %7D else %7B%0A                loadingView.hideView();%0A              %7D%0A            %7D
 %0A   

Fix IllegalThreadException when uploading images.