package architect; import android.support.v4.util.ArrayMap; import android.view.View; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * @author Lukasz Piliszczuk - lukasz.pili@gmail.com */ public class Transitions { private static final int MATCH_NONE = 0; private static final int MATCH_EXACT = 1; private static final int MATCH_WILDCARD = 2; /** * Mapping of target -> from -> transition * This structure should be optimized to something better for android memory */ private final Map<Key, Map<Key, ViewTransition>> transitions; public Transitions() { transitions = new HashMap<>(); } public Transitions register(TransitionsMapping mapping) { Preconditions.checkNotNull(mapping, "Mapping cannot be null"); if (!mapping.list.isEmpty()) { for (TransitionsMapping.Mapping map : mapping.list) { register(map); } } return this; } private Transitions register(TransitionsMapping.Mapping mapping) { Key target = new Key(mapping.view); Preconditions.checkArgument(!transitions.containsKey(target), "Cannot register the same transition destination view multiple times: %s", mapping.view); Map<Key, ViewTransition> targetTransitions; if (mapping.from == null || mapping.from.length == 0) { // from any targetTransitions = new HashMap<>(1); targetTransitions.put(new Key(), mapping.transition); } else { targetTransitions = new HashMap<>(mapping.from.length); for (Class cls : mapping.from) { targetTransitions.put(new Key(cls), mapping.transition); } } transitions.put(target, targetTransitions); return this; } ViewTransition findTransition(View originView, View destinationView, ViewTransitionDirection direction) { // depending on transition direction, the target view is either the origin or destination View target = direction == ViewTransitionDirection.FORWARD ? destinationView : originView; View from = direction == ViewTransitionDirection.FORWARD ? originView : destinationView; return findTransition(target, from); } private ViewTransition findTransition(View targetView, View fromView) { Key targetKey = getBestMatchKey(targetView.getClass(), transitions.keySet()); if (targetKey == null) { return null; } Map<Key, ViewTransition> targetTransitions = transitions.get(targetKey); Key fromKey = getBestMatchKey(fromView.getClass(), targetTransitions.keySet()); if (fromKey == null) { return null; } ViewTransition transition = targetTransitions.get(fromKey); return transition; } /** * Get best key that matches in the order: Exact, Wildcard, None */ private Key getBestMatchKey(Class cls, Set<Key> keys) { int match = compare(cls, keys); if (match == MATCH_NONE) { return null; } return match == MATCH_EXACT ? new Key(cls) : new Key(); } private int compare(Class cls, Set<Key> keys) { int bestMatch = MATCH_NONE; for (Key key : keys) { if (key.cls != null && key.cls.equals(cls)) { return MATCH_EXACT; } if (key.cls == null && bestMatch == MATCH_NONE) { bestMatch = MATCH_WILDCARD; } } return bestMatch; } public static class Key { private final Class cls; public Key() { this(null); } private Key(Class cls) { this.cls = cls; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Key key = (Key) o; return !(cls != null ? !cls.equals(key.cls) : key.cls != null); } @Override public int hashCode() { return cls != null ? cls.hashCode() : 0; } } }