001package arez.dom; 002 003import akasha.EventListener; 004import akasha.WindowGlobal; 005import arez.ComputableValue; 006import arez.annotations.Action; 007import arez.annotations.ArezComponent; 008import arez.annotations.ComputableValueRef; 009import arez.annotations.DepType; 010import arez.annotations.Feature; 011import arez.annotations.Memoize; 012import arez.annotations.Observable; 013import arez.annotations.OnActivate; 014import arez.annotations.OnDeactivate; 015import java.util.Date; 016import javax.annotation.Nonnull; 017 018/** 019 * An observable model that declares state that tracks when the user is "online". 020 * The online state is essentially a reflection of the browsers "navigator.onLine" 021 * value. If an observer is observing the model, the model listens for changes from 022 * the browser and updates the online state as appropriate. However if there is no 023 * observer for the state, the model will not listen to to the browser events so as 024 * not to have any significant performance impact. 025 * 026 * <p>A very simple example</p> 027 * <pre>{@code 028 * import com.google.gwt.core.client.EntryPoint; 029 * import akasha.Global; 030 * import akasha.Console; 031 * import arez.Arez; 032 * import arez.networkstatus.NetworkStatus; 033 * 034 * public class NetworkStatusExample 035 * implements EntryPoint 036 * { 037 * public void onModuleLoad() 038 * { 039 * final NetworkStatus networkStatus = NetworkStatus.create(); 040 * Arez.context().observer( () -> { 041 * Console.log( "Network Status: " + ( networkStatus.isOnLine() ? "Online" : "Offline" ) ); 042 * if ( networkStatus.isOffLine() ) 043 * { 044 * Console.log( "Offline since: " + networkStatus.getLastChangedAt() ); 045 * } 046 * } ); 047 * } 048 * } 049 * }</pre> 050 */ 051@ArezComponent( requireId = Feature.DISABLE ) 052public abstract class NetworkStatus 053{ 054 @Nonnull 055 private final EventListener _listener = e -> updateOnlineStatus( getOnLineComputableValue() ); 056 057 /** 058 * Create an instance of NetworkStatus. 059 * 060 * @return the NetworkStatus instance. 061 */ 062 @Nonnull 063 public static NetworkStatus create() 064 { 065 return new Arez_NetworkStatus( new Date() ); 066 } 067 068 NetworkStatus() 069 { 070 } 071 072 /** 073 * Return true if the browser is offline, false otherwise. 074 * 075 * @return true if the browser is offline, false otherwise. 076 */ 077 public boolean isOffLine() 078 { 079 return !isOnLine(); 080 } 081 082 /** 083 * Return true if the browser is online, false otherwise. 084 * 085 * @return true if the browser is online, false otherwise. 086 */ 087 @Memoize( depType = DepType.AREZ_OR_EXTERNAL ) 088 public boolean isOnLine() 089 { 090 return WindowGlobal.navigator().onLine(); 091 } 092 093 /** 094 * Return the last time at which online status changed. 095 * This will default to the time the component was created, otherwise 096 * the time at which the online status was changed. 097 * 098 * @return the last time at which online status changed. 099 */ 100 @Observable 101 @Nonnull 102 public abstract Date getLastChangedAt(); 103 104 abstract void setLastChangedAt( @Nonnull Date lastChangedAt ); 105 106 @ComputableValueRef 107 abstract ComputableValue<?> getOnLineComputableValue(); 108 109 @OnActivate 110 void onOnLineActivate() 111 { 112 WindowGlobal.addOnlineListener( _listener ); 113 WindowGlobal.addOfflineListener( _listener ); 114 } 115 116 @OnDeactivate 117 void onOnLineDeactivate() 118 { 119 WindowGlobal.removeOnlineListener( _listener ); 120 WindowGlobal.removeOfflineListener( _listener ); 121 } 122 123 @Action 124 void updateOnlineStatus( @Nonnull final ComputableValue<?> computableValue ) 125 { 126 computableValue.reportPossiblyChanged(); 127 setLastChangedAt( new Date() ); 128 } 129}