content: package im.actor.runtime.mvvm;
  
  import com.google.j2objc.annotations.ObjectiveCName;
  
  import java.util.ArrayList;
  
  /**
   * Bindable MVVM Value. Used in UI data binding
   *
   * @param <T> type of value
   */
  public abstract class Value<T> {
  
      private ArrayList<ValueChangedListener<T>> listeners = new ArrayList<>();
  
      private String name;
  
      /**
       * Default constructor of value
       *
       * @param name name of Value
       */
      public Value(String name) {
          this.name = name;
      }
  
      /**
       * Get current value
       *
       * @return the value
       */
      @ObjectiveCName("get")
      public abstract T get();
  
      /**
       * Getting Name of Value
       * Useful for debugging current bindings and notifications
       *
       * @return name of value
       */
      public String getName() {
          return name;
      }
  
      /**
       * Subscribe to value updates
       *
       * @param listener update listener
       */
      @ObjectiveCName("subscribeWithListener:")
      public void subscribe(ValueChangedListener<T> listener) {
          subscribe(listener, true);
      }
  
      /**
       * Subscribe to value updates
       *
       * @param listener update listener
       * @param notify   perform notify about current value
       */
      @ObjectiveCName("subscribeWithListener:notify:")
      public void subscribe(ValueChangedListener<T> listener, boolean notify) {
          // im.actor.runtime.Runtime.checkMainThread();
  
          if (listeners.contains(listener)) {
              return;
          }
          listeners.add(listener);
          if (notify) {
              listener.onChanged(get(), this);
          }
      }
  
      /**
       * Remove subscription for updates
       *
       * @param listener update listener
       */
      @ObjectiveCName("unsubscribeWithListener:")
      public void unsubscribe(ValueChangedListener<T> listener) {
          // im.actor.runtime.Runtime.checkMainThread();
  
          listeners.remove(listener);
      }
  
      /**
       * Performing notification to subscribers
       *
       * @param value new value
       */
      protected void notify(final T value) {
          im.actor.runtime.Runtime.postToMainThread(() -> notifyInMainThread(value));
      }
  
      /**
       * Performing notification to subscribers if we know that we are on mainthread
       * Useful for chainging updates from chain of values
       *
       * @param value new value
       */
      protected void notifyInMainThread(final T value) {
          for (ValueChangedListener<T> listener : listeners) {
              listener.onChanged(value, Value.this);
          }
      }
  }
  