Java tutorial
/* * Copyright 2017 Thomas Andres * * This file is part of Kandroid. * * Kandroid is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Kandroid 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see <http://www.gnu.org/licenses/>. */ package in.andres.kandroid.ui; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.NavigationView; import android.support.design.widget.Snackbar; import android.support.v4.view.GravityCompat; import android.support.v4.view.PagerTitleStrip; import android.support.v4.view.ViewPager; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Dictionary; import java.util.List; import in.andres.kandroid.ArrayPagerAdapter; import in.andres.kandroid.BuildConfig; import in.andres.kandroid.Constants; import in.andres.kandroid.R; import in.andres.kandroid.kanboard.KanboardAPI; import in.andres.kandroid.kanboard.KanboardActivity; import in.andres.kandroid.kanboard.KanboardCategory; import in.andres.kandroid.kanboard.KanboardColor; import in.andres.kandroid.kanboard.KanboardColumn; import in.andres.kandroid.kanboard.KanboardDashboard; import in.andres.kandroid.kanboard.KanboardError; import in.andres.kandroid.kanboard.KanboardProject; import in.andres.kandroid.kanboard.KanboardProjectInfo; import in.andres.kandroid.kanboard.KanboardSwimlane; import in.andres.kandroid.kanboard.KanboardTask; import in.andres.kandroid.kanboard.KanboardUserInfo; import in.andres.kandroid.kanboard.KanbordEvents; import in.andres.kandroid.kanboard.events.OnErrorListener; import in.andres.kandroid.kanboard.events.OnGetActiveSwimlanesListener; import in.andres.kandroid.kanboard.events.OnGetAllCategoriesListener; import in.andres.kandroid.kanboard.events.OnGetAllTasksListener; import in.andres.kandroid.kanboard.events.OnGetColumnsListener; import in.andres.kandroid.kanboard.events.OnGetDefaultColorsListener; import in.andres.kandroid.kanboard.events.OnGetMeListener; import in.andres.kandroid.kanboard.events.OnGetMyActivityStreamListener; import in.andres.kandroid.kanboard.events.OnGetMyDashboardListener; import in.andres.kandroid.kanboard.events.OnGetMyOverdueTasksListener; import in.andres.kandroid.kanboard.events.OnGetMyProjectsListener; import in.andres.kandroid.kanboard.events.OnGetOverdueTasksByProjectListener; import in.andres.kandroid.kanboard.events.OnGetProjectByIdListener; import in.andres.kandroid.kanboard.events.OnGetProjectUsersListener; public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { private String serverURL; private String username; private String password; private Context self; private ViewPager mViewPager; private PagerTitleStrip mTitleStrip; private ArrayPagerAdapter mArrayPager; private View mMainView; private View mProgress; private MenuItem refreshAction; private boolean progressVisible = false; private int progressBarCount = 0; private int mode = 0; private KanboardAPI kanboardAPI; private KanboardUserInfo Me; // private List<KanboardProjectInfo> mProjects; private KanboardProject mProject = null; private KanboardDashboard mDashboard = null; private Dictionary<String, KanboardColor> mColors = null; private List<KanboardProject> mProjectList = null; private List<KanboardActivity> mMyActivities = null; private List<KanboardTask> mMyOverduetasks = null; private List<KanboardColumn> mColumns = null; private List<KanboardSwimlane> mSwimlanes = null; private List<KanboardCategory> mCategories = null; private List<KanboardTask> mActiveTasks = null; private List<KanboardTask> mInactiveTasks = null; private List<KanboardTask> mOverdueTasks = null; private Dictionary<Integer, String> mProjectUsers = null; private KanbordEvents eventHandler = new KanbordEvents() { @Override public void onGetMe(boolean success, KanboardUserInfo userInfo) { } @Override public void onGetMyProjectsList(boolean success, List<KanboardProjectInfo> projects) { // showProgress(false); // mProjects = projects; // NavigationView nav = (NavigationView) findViewById(R.id.nav_view); // SubMenu proj = nav.getMenu().findItem(R.id.projects).getSubMenu(); // proj.clear(); // for (KanboardProjectInfo item: mProjects) { // MenuItem m =proj.add(Menu.NONE, item.ID, Menu.NONE, item.Name); // m.setIcon(R.drawable.project); // } } @Override public void onGetMyDashboard(boolean success, KanboardDashboard dash) { } public void onGetProjectById(boolean success, KanboardProject project) { } @Override public void onError(KanboardError error) { // new AlertDialog.Builder(self) // .setTitle("Error") // .setMessage("Code: " + Integer.toString(error.Code) + "\n" + // "Message: " + error.Message + "\n" + // "HTTP Response: " + Integer.toString(error.HTTPReturnCode)) // .setNeutralButton("Dismiss", null) // .setIcon(android.R.drawable.ic_dialog_alert) // .show(); } @Override public void onDebug(boolean success, String message) { } }; private OnErrorListener errorListener = new OnErrorListener() { @Override public void onError(KanboardError error) { new AlertDialog.Builder(self).setTitle("Error") .setMessage("Code: " + Integer.toString(error.Code) + "\n" + "Message: " + error.Message + "\n" + "HTTP Response: " + Integer.toString(error.HTTPReturnCode)) .setNeutralButton("Dismiss", null).setIcon(android.R.drawable.ic_dialog_alert).show(); } }; private OnGetMeListener getMeListener = new OnGetMeListener() { @Override public void onGetMe(boolean success, KanboardUserInfo result) { Me = result; if (!showProgress(false)) { if (mode == 0) combineDashboard(); else combineProject(); } } }; private OnGetMyDashboardListener getMyDashboardListener = new OnGetMyDashboardListener() { @Override public void onGetMyDashboard(boolean success, KanboardDashboard result) { if (success) { mDashboard = result; if (!showProgress(false)) { combineDashboard(); } } } }; private OnGetMyActivityStreamListener getMyActivityStreamListener = new OnGetMyActivityStreamListener() { @Override public void onGetMyActivityStream(boolean success, List<KanboardActivity> result) { if (success) { mMyActivities = result; if (!showProgress(false)) { combineDashboard(); } } } }; private OnGetMyOverdueTasksListener getMyOverdueTasksListener = new OnGetMyOverdueTasksListener() { @Override public void onGetMyOverdueTasks(boolean success, List<KanboardTask> result) { if (success) { mMyOverduetasks = result; if (!showProgress(false)) { combineDashboard(); } } } }; private OnGetProjectByIdListener getProjectByIdListener = new OnGetProjectByIdListener() { @Override public void onGetProjectById(boolean success, KanboardProject result) { if (success) { mProject = result; if (!showProgress(false)) { combineProject(); } } } }; private OnGetColumnsListener getColumnsListener = new OnGetColumnsListener() { @Override public void onGetColumns(boolean success, List<KanboardColumn> result) { if (success) { mColumns = result; if (!showProgress(false)) { combineProject(); } } } }; private OnGetActiveSwimlanesListener getActiveSwimlanesListener = new OnGetActiveSwimlanesListener() { @Override public void onGetActiveSwimlanes(boolean success, List<KanboardSwimlane> result) { if (success) { mSwimlanes = result; if (!showProgress(false)) { combineProject(); } } } }; private OnGetAllCategoriesListener getAllCategoriesListener = new OnGetAllCategoriesListener() { @Override public void onGetAllCategories(boolean success, List<KanboardCategory> result) { if (success) { mCategories = result; if (!showProgress(false)) { combineProject(); } } } }; private OnGetAllTasksListener getAllTasksListener = new OnGetAllTasksListener() { @Override public void onGetAllTasks(boolean success, int status, List<KanboardTask> result) { if (success) { if (status == 0) { mInactiveTasks = result; if (!showProgress(false)) { combineProject(); } } else if (status == 1) { mActiveTasks = result; if (!showProgress(false)) { combineProject(); } } } } }; private OnGetOverdueTasksByProjectListener getOverdueTasksByProjectListener = new OnGetOverdueTasksByProjectListener() { @Override public void onGetOverdueTasksByProject(boolean success, List<KanboardTask> result) { if (success) { mOverdueTasks = result; if (!showProgress(false)) { combineProject(); } } } }; private OnGetProjectUsersListener getProjectUsersListener = new OnGetProjectUsersListener() { @Override public void onGetProjectUsers(boolean success, Dictionary<Integer, String> result) { if (success) { mProjectUsers = result; if (!showProgress(false)) { combineProject(); } } } }; private OnGetDefaultColorsListener getDefaultColorsListener = new OnGetDefaultColorsListener() { @Override public void onGetDefaultColors(boolean success, Dictionary<String, KanboardColor> colors) { if (success) { mColors = colors; if (!showProgress(false)) { combineDashboard(); } } } }; private OnGetMyProjectsListener getMyProjectsListener = new OnGetMyProjectsListener() { @Override public void onGetMyProjects(boolean success, List<KanboardProject> result) { if (success) { mProjectList = result; Log.i("Projects", Integer.toString(mProjectList.get(0).getId())); if (!showProgress(false)) { combineDashboard(); } } } }; //region overrides @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mMainView = findViewById(R.id.pager); mProgress = findViewById(R.id.main_progress); mViewPager = (ViewPager) mMainView; mTitleStrip = (PagerTitleStrip) mViewPager.findViewById(R.id.pager_title_strip); mArrayPager = new ArrayPagerAdapter(getSupportFragmentManager()); mViewPager.setAdapter(mArrayPager); self = this; FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null) .show(); } }); DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) { public void onDrawerOpened(View drawerView) { TextView mServerUrl = (TextView) findViewById(R.id.nav_serverurl); if ((Me != null) && (mServerUrl != null)) mServerUrl.setText(Me.getName()); } }; drawer.addDrawerListener(toggle); toggle.syncState(); NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener(this); if (savedInstanceState != null) { if (BuildConfig.DEBUG) Log.v(Constants.TAG, "MainActivity: restore savedInstanceState"); if (savedInstanceState.containsKey("dashboard")) { // App was restarted by System, load saved instance mDashboard = (KanboardDashboard) savedInstanceState.getSerializable("dashboard"); } if (savedInstanceState.containsKey("project")) mProject = (KanboardProject) savedInstanceState.getSerializable("project"); } } @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); if (mDashboard != null) savedInstanceState.putSerializable("dashboard", mDashboard); if (mProject != null) savedInstanceState.putSerializable("project", mProject); if (mProjectList != null) savedInstanceState.putSerializable("projectList", (ArrayList<KanboardProject>) mProjectList); savedInstanceState.putInt("ViewPagerItem", mViewPager.getCurrentItem()); savedInstanceState.putInt("mode", mode); if (BuildConfig.DEBUG) Log.v(Constants.TAG, "MainActivity: saved savedInstanceState"); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // User rotated the screen or something if (BuildConfig.DEBUG) Log.v(Constants.TAG, "MainActivity: restore savedInstanceState"); if (savedInstanceState.containsKey("dashboard")) { mDashboard = (KanboardDashboard) savedInstanceState.getSerializable("dashboard"); } if (savedInstanceState.containsKey("projectList")) { mProjectList = (ArrayList<KanboardProject>) savedInstanceState.getSerializable("projectList"); populateProjectsMenu(); } if (savedInstanceState.containsKey("project")) mProject = (KanboardProject) savedInstanceState.getSerializable("project"); mode = savedInstanceState.getInt("mode"); if (mDashboard != null && (progressBarCount <= 0) && (mode == 0)) showDashboard(); if (mProject != null && progressBarCount <= 0 && mode > 0) showProject(); mViewPager.setCurrentItem(savedInstanceState.getInt("ViewPagerItem")); } @Override protected void onStart() { super.onStart(); if ((mDashboard == null && mode == 0) || (mProject == null && mode > 0)) refresh(); else createKandoardAPI(); } @Override protected void onPause() { super.onPause(); } @Override protected void onResume() { super.onResume(); if (mDashboard != null && (progressBarCount <= 0) && (mode == 0)) showDashboard(); if (mProject != null && progressBarCount <= 0 && mode > 0) showProject(); } @Override public void onBackPressed() { DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { super.onBackPressed(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); refreshAction = menu.findItem(R.id.action_refresh); if (progressBarCount > 0) { ProgressBar prog = new ProgressBar(self); prog.getIndeterminateDrawable().setColorFilter(Color.WHITE, android.graphics.PorterDuff.Mode.MULTIPLY); refreshAction.setActionView(prog); refreshAction.expandActionView(); progressVisible = true; } return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_refresh) { refresh(); return true; } return super.onOptionsItemSelected(item); } @SuppressWarnings("StatementWithEmptyBody") @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { // Handle navigation view item clicks here. int id = item.getItemId(); if (id == R.id.nav_dashboard) { Log.i(Constants.TAG, "Select dashboard"); if (mode != 0) mViewPager.setCurrentItem(0); mode = 0; showDashboard(); } else if (id == R.id.nav_sign_in) { Intent iSetting = new Intent(this, SettingsActivity.class); startActivity(iSetting); } else if (id == R.id.nav_refresh) { refresh(); } else if (id == R.id.nav_about) { Intent iAboutScreen = new Intent(this, AboutActivity.class); startActivity(iAboutScreen); } else { Log.i(Constants.TAG, "Select project"); if (mode != id) mViewPager.setCurrentItem(0); mode = id; refresh(); } DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); return true; } //endregion //region private methods private void combineDashboard() { if (mDashboard != null && mMyOverduetasks != null && mMyActivities != null && mProjectList != null) { mDashboard.setExtra(mMyOverduetasks, mMyActivities, mProjectList); populateProjectsMenu(); showDashboard(); } else { Log.w(Constants.TAG, "Something happened while assembling mDashboard."); } } private void combineProject() { if (mProject != null && mColumns != null && mSwimlanes != null && mCategories != null && mActiveTasks != null && mInactiveTasks != null && mOverdueTasks != null && mProjectUsers != null) { mProject.setExtra(mColumns, mSwimlanes, mCategories, mActiveTasks, mInactiveTasks, mOverdueTasks, mProjectUsers); showProject(); } else { Log.w(Constants.TAG, "Something happened while assembling mProject."); } } private void populateProjectsMenu() { if (mProjectList == null) { if (BuildConfig.DEBUG) Log.d("Kandroid", "Tried to populate drawer, but mDashboard was null"); return; } SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this.getBaseContext()); List<KanboardProject> projList = mProjectList; if (preferences.getBoolean("projects_sort_alphabetic", false)) Collections.sort(projList); NavigationView nav = (NavigationView) findViewById(R.id.nav_view); SubMenu projMenu = nav.getMenu().findItem(R.id.projects).getSubMenu(); projMenu.clear(); for (KanboardProject item : projList) projMenu.add(Menu.NONE, item.getId(), Menu.NONE, item.getName()).setIcon(R.drawable.project); } private void showDashboard() { if (mDashboard == null) { if (BuildConfig.DEBUG) Log.d("Kandroid", "Tried to show dashboard, but mDashboard was null"); return; } if (getSupportActionBar() != null) getSupportActionBar().setTitle(getString(R.string.action_dashboard)); mArrayPager.removeAllFragments(); mArrayPager.addFragment(DashProjectsFragment.newInstance(), getString(R.string.tab_projects)); mArrayPager.addFragment(DashOverdueFragment.newInstance(), getString(R.string.tab_overdue_tasks)); mArrayPager.addFragment(DashActivitiesFragment.newInstance(), getString(R.string.tab_activity)); mArrayPager.notifyDataSetChanged(); } private void showProject() { if (mProject == null) { if (BuildConfig.DEBUG) Log.d(Constants.TAG, "Tried to show project, but mProject was null"); return; } if (getSupportActionBar() != null) getSupportActionBar().setTitle(mProject.getName()); mArrayPager.removeAllFragments(); mArrayPager.addFragment(ProjectOverviewFragment.newInstance(), getString(R.string.tab_overview)); for (KanboardColumn column : mProject.getColumns()) { mArrayPager.addFragment(ProjectTasksFragment.newInstance(column), column.getTitle()); } mArrayPager.addFragment(ProjectOverdueTasksFragment.newInstance(), getString(R.string.tab_overdue_tasks)); mArrayPager.addFragment(ProjectInactiveTasksFragment.newInstance(), getString(R.string.tab_inactive_tasks)); mArrayPager.notifyDataSetChanged(); } @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) private boolean showProgress(final boolean show) { // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow // for very easy animations. If available, use these APIs to fade-in // the progress spinner. if (show) progressBarCount++; else progressBarCount = progressBarCount > 0 ? --progressBarCount : 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime); mMainView.setVisibility(progressBarCount > 0 ? View.GONE : View.VISIBLE); mMainView.animate().setDuration(shortAnimTime).alpha(progressBarCount > 0 ? 0 : 1) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mMainView.setVisibility(progressBarCount > 0 ? View.GONE : View.VISIBLE); } }); mProgress.setVisibility(progressBarCount > 0 ? View.VISIBLE : View.GONE); mProgress.animate().setDuration(shortAnimTime).alpha(progressBarCount > 0 ? 1 : 0) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mProgress.setVisibility(progressBarCount > 0 ? View.VISIBLE : View.GONE); } }); } else { // The ViewPropertyAnimator APIs are not available, so simply show // and hide the relevant UI components. mProgress.setVisibility(progressBarCount > 0 ? View.VISIBLE : View.GONE); mMainView.setVisibility(progressBarCount > 0 ? View.GONE : View.VISIBLE); } if (progressBarCount > 0 && refreshAction != null && !progressVisible) { ProgressBar prog = new ProgressBar(self); prog.getIndeterminateDrawable().setColorFilter(Color.WHITE, android.graphics.PorterDuff.Mode.MULTIPLY); refreshAction.setActionView(prog); refreshAction.expandActionView(); progressVisible = true; } if (progressBarCount == 0 && refreshAction != null && progressVisible) { refreshAction.collapseActionView(); refreshAction.setActionView(null); progressVisible = false; } return progressBarCount != 0; } private boolean createKandoardAPI() { // Check if API object already exists if (kanboardAPI != null) return true; Log.d(Constants.TAG, "Creating API object"); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this.getBaseContext()); boolean showLoginScreen = false; if (!preferences.contains("serverurl")) showLoginScreen = true; serverURL = preferences.getString("serverurl", ""); if (!preferences.contains("username")) showLoginScreen = true; username = preferences.getString("username", ""); if (!preferences.contains("password")) showLoginScreen = true; password = preferences.getString("password", ""); if (showLoginScreen) { Log.i("Kandroid", "No credential found. Launching login activity."); Intent iLoginScreen = new Intent(this, LoginActivity.class); startActivity(iLoginScreen); return false; } else { try { kanboardAPI = new KanboardAPI(serverURL, username, password); kanboardAPI.addListener(eventHandler); kanboardAPI.addErrorListener(errorListener); kanboardAPI.addOnGetMeListener(getMeListener); kanboardAPI.addOnGetMyDashboardListener(getMyDashboardListener); kanboardAPI.addOnGetMyActivityStreamListener(getMyActivityStreamListener); kanboardAPI.addOnGetMyOverdueTasksListener(getMyOverdueTasksListener); kanboardAPI.addOnGetProjectByIdListener(getProjectByIdListener); kanboardAPI.addOnGetColumnsListener(getColumnsListener); kanboardAPI.addOnGetActiveSwimlanesListener(getActiveSwimlanesListener); kanboardAPI.addOnGetAllCategoriesListener(getAllCategoriesListener); kanboardAPI.addOnGetAllTasksListener(getAllTasksListener); kanboardAPI.addOnGetOverdueTasksByProjectListener(getOverdueTasksByProjectListener); kanboardAPI.addOnGetProjectUsersListener(getProjectUsersListener); kanboardAPI.addOnGetDefaultColorsListener(getDefaultColorsListener); kanboardAPI.addOnGetMyProjectsListener(getMyProjectsListener); return true; } catch (IOException e) { Log.e(Constants.TAG, "Failed to create API object."); e.printStackTrace(); } } return false; } protected void refresh() { if (!createKandoardAPI()) return; showProgress(true); kanboardAPI.getMe(); if (mode == 0) { Log.i(Constants.TAG, "Loading dashboard data."); showProgress(true); kanboardAPI.getDefaultTaskColors(); showProgress(true); kanboardAPI.getMyProjects(); showProgress(true); kanboardAPI.getMyDashboard(); showProgress(true); kanboardAPI.getMyActivityStream(); showProgress(true); kanboardAPI.getMyOverdueTasks(); } else { Log.i(Constants.TAG, "Loading project date."); showProgress(true); kanboardAPI.getProjectById(mode); showProgress(true); kanboardAPI.getColumns(mode); showProgress(true); kanboardAPI.getActiveSwimlanes(mode); showProgress(true); kanboardAPI.getAllCategories(mode); showProgress(true); kanboardAPI.getAllTasks(mode, 1); showProgress(true); kanboardAPI.getAllTasks(mode, 0); showProgress(true); kanboardAPI.getOverdueTasksByProject(mode); showProgress(true); kanboardAPI.getProjectUsers(mode); } } //endregion //region public methods public KanboardDashboard getDashboard() { return mDashboard; } public KanboardProject getProject() { return mProject; } public KanboardUserInfo getMe() { return Me; } public Dictionary<String, KanboardColor> getColors() { return mColors; } public List<KanboardProject> getProjectList() { return mProjectList; } //endregion }