001package arez.dom;
002
003import akasha.Document;
004import akasha.WindowGlobal;
005import arez.Disposable;
006import java.util.Objects;
007import javax.annotation.Nonnull;
008
009/**
010 * Exposes {@code document.visibilityState} as an observable property for specified documents.
011 *
012 * <p>A very simple example</p>
013 * <pre>{@code
014 * import arez.Arez;
015 * import arez.dom.DocumentVisibility;
016 * import com.google.gwt.core.client.EntryPoint;
017 * import akasha.Console;
018 *
019 * public class DocumentVisibilityExample
020 *   implements EntryPoint
021 * {
022 *   public void onModuleLoad()
023 *   {
024 *     final DocumentVisibility v = DocumentVisibility.create();
025 *     Arez.context().observer( () -> Console.log( "Document Visibility: " + v.getVisibility() ) );
026 *   }
027 * }
028 * }</pre>
029 */
030public final class DocumentVisibility
031  implements Disposable
032{
033  /**
034   * The visibility state of the document.
035   */
036  public enum Visibility
037  {
038    /**
039     * The page content may be at least partially visible. In practice this means that the page is the foreground tab of a non-minimized window.
040     */
041    VISIBLE,
042    /**
043     * The page content is not visible to the user. In practice this means that the document is either a background tab or part of a minimized window, or the OS screen lock is active.
044     */
045    HIDDEN,
046    /**
047     * The page content is being prerendered and is not visible to the user (considered hidden for purposes of document.hidden). The document may start in this state, but will never transition to it from another value. Note: browser support is optional.
048     */
049    PRERENDER
050  }
051
052  /**
053   * The underlying component performing the monitoring.
054   */
055  private final EventDrivenValue<Document, String> _value;
056
057  /**
058   * Create component monitoring the default document.
059   *
060   * @return the new component.
061   */
062  @Nonnull
063  public static DocumentVisibility create()
064  {
065    return create( WindowGlobal.document() );
066  }
067
068  /**
069   * Create component monitoring specific document.
070   *
071   * @param document the document.
072   * @return the new component.
073   */
074  @Nonnull
075  public static DocumentVisibility create( @Nonnull final Document document )
076  {
077    return new DocumentVisibility( Objects.requireNonNull( document ) );
078  }
079
080  private DocumentVisibility( @Nonnull final Document document )
081  {
082    _value = EventDrivenValue.create( document, "visibilitychange", Document::visibilityState );
083  }
084
085  /**
086   * Return the document that monitoring visibility state.
087   *
088   * @return the document.
089   */
090  @Nonnull
091  public Document getDocument()
092  {
093    return _value.getSource();
094  }
095
096  /**
097   * Change the document that is having visibility state monitored.
098   *
099   * @param document the new document.
100   */
101  public void setDocument( @Nonnull final Document document )
102  {
103    _value.setSource( document );
104  }
105
106  /**
107   * Return the visibility state of the document as an enum.
108   *
109   * @return the visibility state as an enum.
110   */
111  @Nonnull
112  public Visibility getVisibility()
113  {
114    return asVisibility( getVisibilityState() );
115  }
116
117  /**
118   * Return the visibility state of the document as a string.
119   *
120   * @return the visibility state as a string.
121   */
122  @Nonnull
123  public String getVisibilityState()
124  {
125    return _value.getValue();
126  }
127
128  /**
129   * Return true if visibility state is "visible".
130   *
131   * @return true if visibility state is "visible".
132   */
133  public boolean isVisible()
134  {
135    return "visible".equals( getVisibilityState() );
136  }
137
138  /**
139   * Return true if visibility state is "hidden".
140   *
141   * @return true if visibility state is "hidden".
142   */
143  public boolean isHidden()
144  {
145    return "hidden".equals( getVisibilityState() );
146  }
147
148  @Override
149  public void dispose()
150  {
151    Disposable.dispose( _value );
152  }
153
154  @Override
155  public boolean isDisposed()
156  {
157    return Disposable.isDisposed( _value );
158  }
159
160  /**
161   * Convert the visibility state as an enum.
162   *
163   * @param state the state.
164   * @return the visibility enum.
165   */
166  @Nonnull
167  private Visibility asVisibility( @Nonnull final String state )
168  {
169    if ( "visible".equals( state ) )
170    {
171      return Visibility.VISIBLE;
172    }
173    else if ( "hidden".equals( state ) )
174    {
175      return Visibility.HIDDEN;
176    }
177    else
178    {
179      assert "prerender".equals( state );
180      return Visibility.PRERENDER;
181    }
182  }
183}