1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.deskclock.uidata;
18 
19 import android.content.SharedPreferences;
20 import android.text.TextUtils;
21 
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.List;
25 import java.util.Locale;
26 
27 import static android.view.View.LAYOUT_DIRECTION_RTL;
28 import static com.android.deskclock.uidata.UiDataModel.Tab;
29 
30 /**
31  * All tab data is accessed via this model.
32  */
33 final class TabModel {
34 
35     private final SharedPreferences mPrefs;
36 
37     /** The listeners to notify when the selected tab is changed. */
38     private final List<TabListener> mTabListeners = new ArrayList<>();
39 
40     /** The listeners to notify when the vertical scroll state of the selected tab is changed. */
41     private final List<TabScrollListener> mTabScrollListeners = new ArrayList<>();
42 
43     /** The scrolled-to-top state of each tab. */
44     private final boolean[] mTabScrolledToTop = new boolean[Tab.values().length];
45 
46     /** An enumerated value indicating the currently selected tab. */
47     private Tab mSelectedTab;
48 
TabModel(SharedPreferences prefs)49     TabModel(SharedPreferences prefs) {
50         mPrefs = prefs;
51         Arrays.fill(mTabScrolledToTop, true);
52     }
53 
54     //
55     // Selected tab
56     //
57 
58     /**
59      * @param tabListener to be notified when the selected tab changes
60      */
addTabListener(TabListener tabListener)61     void addTabListener(TabListener tabListener) {
62         mTabListeners.add(tabListener);
63     }
64 
65     /**
66      * @param tabListener to no longer be notified when the selected tab changes
67      */
removeTabListener(TabListener tabListener)68     void removeTabListener(TabListener tabListener) {
69         mTabListeners.remove(tabListener);
70     }
71 
72     /**
73      * @return the number of tabs
74      */
getTabCount()75     int getTabCount() {
76         return Tab.values().length;
77     }
78 
79     /**
80      * @param ordinal the ordinal (left-to-right index) of the tab
81      * @return the tab at the given {@code ordinal}
82      */
getTab(int ordinal)83     Tab getTab(int ordinal) {
84         return Tab.values()[ordinal];
85     }
86 
87     /**
88      * @param position the position of the tab in the user interface
89      * @return the tab at the given {@code ordinal}
90      */
getTabAt(int position)91     Tab getTabAt(int position) {
92         final int ordinal;
93         if (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == LAYOUT_DIRECTION_RTL) {
94             ordinal = getTabCount() - position - 1;
95         } else {
96             ordinal = position;
97         }
98         return getTab(ordinal);
99     }
100 
101     /**
102      * @return an enumerated value indicating the currently selected primary tab
103      */
getSelectedTab()104     Tab getSelectedTab() {
105         if (mSelectedTab == null) {
106             mSelectedTab = TabDAO.getSelectedTab(mPrefs);
107         }
108         return mSelectedTab;
109     }
110 
111     /**
112      * @param tab an enumerated value indicating the newly selected primary tab
113      */
setSelectedTab(Tab tab)114     void setSelectedTab(Tab tab) {
115         final Tab oldSelectedTab = getSelectedTab();
116         if (oldSelectedTab != tab) {
117             mSelectedTab = tab;
118             TabDAO.setSelectedTab(mPrefs, tab);
119 
120             // Notify of the tab change.
121             for (TabListener tl : mTabListeners) {
122                 tl.selectedTabChanged(oldSelectedTab, tab);
123             }
124 
125             // Notify of the vertical scroll position change if there is one.
126             final boolean tabScrolledToTop = isTabScrolledToTop(tab);
127             if (isTabScrolledToTop(oldSelectedTab) != tabScrolledToTop) {
128                 for (TabScrollListener tsl : mTabScrollListeners) {
129                     tsl.selectedTabScrollToTopChanged(tab, tabScrolledToTop);
130                 }
131             }
132         }
133     }
134 
135     //
136     // Tab scrolling
137     //
138 
139     /**
140      * @param tabScrollListener to be notified when the scroll position of the selected tab changes
141      */
addTabScrollListener(TabScrollListener tabScrollListener)142     void addTabScrollListener(TabScrollListener tabScrollListener) {
143         mTabScrollListeners.add(tabScrollListener);
144     }
145 
146     /**
147      * @param tabScrollListener to be notified when the scroll position of the selected tab changes
148      */
removeTabScrollListener(TabScrollListener tabScrollListener)149     void removeTabScrollListener(TabScrollListener tabScrollListener) {
150         mTabScrollListeners.remove(tabScrollListener);
151     }
152 
153     /**
154      * Updates the scrolling state in the {@link UiDataModel} for this tab.
155      *
156      * @param tab an enumerated value indicating the tab reporting its vertical scroll position
157      * @param scrolledToTop {@code true} iff the vertical scroll position of this tab is at the top
158      */
setTabScrolledToTop(Tab tab, boolean scrolledToTop)159     void setTabScrolledToTop(Tab tab, boolean scrolledToTop) {
160         if (isTabScrolledToTop(tab) != scrolledToTop) {
161             mTabScrolledToTop[tab.ordinal()] = scrolledToTop;
162             if (tab == getSelectedTab()) {
163                 for (TabScrollListener tsl : mTabScrollListeners) {
164                     tsl.selectedTabScrollToTopChanged(tab, scrolledToTop);
165                 }
166             }
167         }
168     }
169 
170     /**
171      * @param tab identifies the tab
172      * @return {@code true} iff the content in the given {@code tab} is currently scrolled to top
173      */
isTabScrolledToTop(Tab tab)174     boolean isTabScrolledToTop(Tab tab) {
175         return mTabScrolledToTop[tab.ordinal()];
176     }
177 }