/*
* Copyright © 2016 TIBCO Software,Inc.All rights reserved.
* http://community.jaspersoft.com/project/jaspermobile-android
*
* Unless you have purchased a commercial license agreement from TIBCO Jaspersoft,
* the following license terms apply:
*
* This program is part of TIBCO Jaspersoft Mobile for Android.
*
* TIBCO Jaspersoft Mobile is free software:you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation,either version 3of the License,or
* (at your option)any later version.
*
* TIBCO Jaspersoft Mobile is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY;without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with TIBCO Jaspersoft Mobile for Android.If not,see
* <http://www.gnu.org/licenses/lgpl>.
*/
package com.jaspersoft.android.jaspermobile.widget;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import com.jaspersoft.android.jaspermobile.Analytics;
import com.jaspersoft.android.jaspermobile.R;
import com.jaspersoft.android.jaspermobile.ui.model.ProfileViewModel;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ItemClick;
import org.androidannotations.annotations.ViewById;
import java.util.ArrayList;
import java.util.List;
import timber.log.Timber;
/**
* @author Andrew Tivodar
* @since 2.0
*/
@EViewGroup(R.layout.view_navigation_panel)
public class NavigationPanelLayout extends RelativeLayout {
private final String TAG = NavigationPanelLayout.class.getName();
private NavigationListener mListener;
private View selectedItemView;
boolean isShowingMenu;
@ViewById(R.id.vg_navigation_menu)
ViewGroup navigationMenu;
@ViewById(R.id.lv_accounts_menu)
ListView accountsMenu;
@ViewById(R.id.tv_profile)
TextView tvProfile;
@ViewById(R.id.iv_profile_arrow)
ImageView ivProfileArrow;
private View footerDivider;
private Analytics analytics;
private ProfilesAdapter mProfilesAdapter;
//---------------------------------------------------------------------
// Public methods
//---------------------------------------------------------------------
public NavigationPanelLayout(Context context) {
super(context);
}
public NavigationPanelLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NavigationPanelLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setAnalytics(Analytics analytics) {
this.analytics = analytics;
}
public void setListener(NavigationListener listener) {
this.mListener = listener;
}
public void setItemSelected(int viewId) {
selectItem(findViewById(viewId));
}
public void notifyPanelClosed() {
isShowingMenu = true;
showActivatedPanel(isShowingMenu);
accountsMenu.setSelectionAfterHeaderView();
((ScrollView) navigationMenu).fullScroll(FOCUS_UP);
}
@AfterViews
final void initNavigationLayout() {
Timber.tag(TAG);
isShowingMenu = true;
View accountsFooter = LayoutInflater.from(getContext()).inflate(R.layout.view_accounts_footer, null, false);
accountsFooter.findViewById(R.id.vg_add_account).setOnClickListener(onAddProfileClickListener);
accountsFooter.findViewById(R.id.vg_manage_accounts).setOnClickListener(onManageProfileClickListener);
footerDivider = accountsFooter.findViewById(R.id.footer_divider);
accountsMenu.addFooterView(accountsFooter);
initAccountsView();
}
private void initAccountsView() {
mProfilesAdapter = new ProfilesAdapter();
accountsMenu.setAdapter(mProfilesAdapter);
}
/**
* Calculation width of Left Panel Menu. The size should be minimum of 2 values: screen width - ab size or 320dp.
* NOTE: http://www.google.com/design/spec/patterns/navigation-drawer.html But minimum size(5 * ab size) is incorrect.
*/
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
DisplayMetrics dm = getResources().getDisplayMetrics();
int screenWidth = Math.min(dm.widthPixels, dm.heightPixels);
int toolbarHeight = (int) getResources().getDimension(android.support.v7.appcompat.R.dimen.abc_action_bar_default_height_material);
getLayoutParams().width = (int) Math.min(screenWidth - toolbarHeight, 320 * dm.scaledDensity);
}
private OnClickListener onAddProfileClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
navigateTo(v.getId());
}
};
private OnClickListener onManageProfileClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
navigateTo(v.getId());
}
};
@Click(R.id.vg_profile)
final void profilePanelClicked() {
isShowingMenu = !isShowingMenu;
showActivatedPanel(isShowingMenu);
}
@Click(R.id.tv_feedback)
final void navigateToFeedback(View view) {
navigateTo(view.getId());
trackNavigateEvent(Analytics.EventLabel.FEEDBACK.getValue());
}
@Click(R.id.tv_settings)
final void navigateToSettings(View view) {
navigateTo(view.getId());
trackNavigateEvent(Analytics.EventLabel.SETTINGS.getValue());
}
@Click(R.id.tv_about)
final void navigateToAbout(View view) {
navigateTo(view.getId());
trackNavigateEvent(Analytics.EventLabel.ABOUT.getValue());
}
@Click(R.id.vg_library)
final void navigateToLibrary(View newSelectItem) {
selectItem(newSelectItem);
trackNavigateEvent(Analytics.EventLabel.LIBRARY.getValue());
}
@Click(R.id.vg_repository)
final void navigateToRepository(View newSelectItem) {
selectItem(newSelectItem);
trackNavigateEvent(Analytics.EventLabel.REPOSITORY.getValue());
}
@Click(R.id.vg_favorites)
final void navigateToFavorites(View newSelectItem) {
selectItem(newSelectItem);
trackNavigateEvent(Analytics.EventLabel.FAVORITES.getValue());
}
@Click(R.id.vg_saved_items)
final void navigateToSavedItems(View newSelectItem) {
selectItem(newSelectItem);
trackNavigateEvent(Analytics.EventLabel.SAVED_ITEMS.getValue());
}
@Click(R.id.vg_recent)
final void navigateToRecent(View newSelectItem) {
selectItem(newSelectItem);
trackNavigateEvent(Analytics.EventLabel.RECENTLY_VIEWED.getValue());
}
@Click(R.id.vg_jobs)
final void navigateToJobs(View newSelectItem) {
selectItem(newSelectItem);
trackNavigateEvent(Analytics.EventLabel.JOBS.getValue());
}
@ItemClick(R.id.lv_accounts_menu)
public void onAccountSelect(ProfileViewModel profile) {
if (mListener != null) {
mListener.onActiveProfileChange(profile);
}
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
NavigationPanelSavedState savedState = new NavigationPanelSavedState(superState);
savedState.isShowingMenu = this.isShowingMenu;
savedState.selectedViewId = selectedItemView != null ? selectedItemView.getId() : -1;
return savedState;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof NavigationPanelSavedState)) {
super.onRestoreInstanceState(state);
return;
}
NavigationPanelSavedState savedState = (NavigationPanelSavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());
this.isShowingMenu = savedState.isShowingMenu;
showActivatedPanel(isShowingMenu);
if (savedState.selectedViewId != -1) {
this.selectedItemView = findViewById(savedState.selectedViewId);
setItemSelected(selectedItemView, true);
}
}
public void loadProfiles(@NonNull List<ProfileViewModel> profiles) {
boolean hasProfiles = !profiles.isEmpty();
footerDivider.setVisibility(hasProfiles ? VISIBLE : GONE);
ProfileViewModel activeProfile = selectActiveProfile(profiles);
setActiveProfile(activeProfile);
profiles.remove(activeProfile);
mProfilesAdapter.setProfiles(profiles);
}
private ProfileViewModel selectActiveProfile(List<ProfileViewModel> profiles) {
for (ProfileViewModel profile : profiles) {
if (profile.isActive()) {
return profile;
}
}
return ProfileViewModel.getEmpty();
}
private void setActiveProfile(@NonNull ProfileViewModel profile) {
if (ProfileViewModel.getEmpty().equals(profile)) {
tvProfile.setText(getContext().getString(R.string.nd_select_account));
} else {
tvProfile.setText(profile.getLabel());
}
}
//---------------------------------------------------------------------
// Helper methods
//---------------------------------------------------------------------
private void selectItem(View newSelectItem) {
if (selectedItemView != null) {
setItemSelected(selectedItemView, false);
}
setItemSelected(newSelectItem, true);
selectedItemView = newSelectItem;
navigateTo(newSelectItem.getId());
}
private void navigateTo(int viewId) {
if (mListener != null) {
mListener.onNavigate(viewId);
}
}
private void showActivatedPanel(boolean isShowingMenu) {
if (!isShowingMenu) {
ivProfileArrow.setImageResource(R.drawable.ic_arrow_up);
navigationMenu.setVisibility(GONE);
accountsMenu.setVisibility(VISIBLE);
((ScrollView) navigationMenu).fullScroll(FOCUS_UP);
} else {
ivProfileArrow.setImageResource(R.drawable.ic_arrow_down);
navigationMenu.setVisibility(VISIBLE);
accountsMenu.setVisibility(GONE);
accountsMenu.setSelectionAfterHeaderView();
}
}
private void setItemSelected(View item, boolean selected) {
item.setSelected(selected);
try {
ViewGroup itemGroup = ((ViewGroup) item);
for (int i = 0; i < itemGroup.getChildCount(); i++) {
View view = itemGroup.getChildAt(i);
view.setSelected(selected);
}
} catch (ClassCastException e) {
Timber.w(TAG, "Selected navigation item is not a layout.");
}
}
private void trackNavigateEvent(String location) {
analytics.sendEvent(
Analytics.EventCategory.MENU.getValue(),
Analytics.EventAction.CLICKED.getValue(),
location
);
}
//---------------------------------------------------------------------
// Nested classes
//---------------------------------------------------------------------
private static class ProfilesAdapter extends BaseAdapter {
private final List<ProfileViewModel> mProfiles = new ArrayList<>();
public void setProfiles(List<ProfileViewModel> profiles) {
mProfiles.clear();
mProfiles.addAll(profiles);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mProfiles.size();
}
@Override
public ProfileViewModel getItem(int position) {
return mProfiles.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
AccountsViewHolder mViewHolder;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.item_account, null);
mViewHolder = new AccountsViewHolder();
mViewHolder.tvAccountName = (TextView) convertView.findViewById(R.id.tv_account_name);
mViewHolder.tvAccountVersion = (TextView) convertView.findViewById(R.id.tv_account_version);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (AccountsViewHolder) convertView.getTag();
}
ProfileViewModel item = getItem(position);
mViewHolder.tvAccountName.setText(item.getLabel());
//We need to show only 2 digits of version
String serverVersion = new String(item.getVersion().substring(0, 3));
// This possible due to migration issues from version 1.8 to 2.0
// Some instances will have missing version names
boolean versionNotDefined = Double.parseDouble(serverVersion) == 0d;
mViewHolder.tvAccountVersion.setText(versionNotDefined ? "?" : serverVersion);
return convertView;
}
private class AccountsViewHolder {
TextView tvAccountName;
TextView tvAccountVersion;
}
}
static class NavigationPanelSavedState extends BaseSavedState {
int selectedViewId;
boolean isShowingMenu;
NavigationPanelSavedState(Parcelable superState) {
super(superState);
}
private NavigationPanelSavedState(Parcel in) {
super(in);
selectedViewId = in.readInt();
isShowingMenu = in.readInt() != 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(selectedViewId);
out.writeInt(isShowingMenu ? 1 : 0);
}
public static final Parcelable.Creator<NavigationPanelSavedState> CREATOR =
new Parcelable.Creator<NavigationPanelSavedState>() {
public NavigationPanelSavedState createFromParcel(Parcel in) {
return new NavigationPanelSavedState(in);
}
public NavigationPanelSavedState[] newArray(int size) {
return new NavigationPanelSavedState[size];
}
};
}
public interface NavigationListener {
/**
* @param viewId returns selected view Id or 0 for same view
*/
void onNavigate(int viewId);
void onActiveProfileChange(ProfileViewModel profile);
}
}