/*
* Copyright 2014 Artem Chikin
* Copyright 2014 Artem Herasymchuk
* Copyright 2014 Tom Krywitsky
* Copyright 2014 Henry Pabst
* Copyright 2014 Bradley Simons
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ca.ualberta.cmput301w14t08.geochan.fragments;
import java.util.ArrayList;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import ca.ualberta.cmput301w14t08.geochan.R;
import ca.ualberta.cmput301w14t08.geochan.adapters.ThreadListAdapter;
import ca.ualberta.cmput301w14t08.geochan.helpers.ConnectivityBroadcastReceiver;
import ca.ualberta.cmput301w14t08.geochan.helpers.ConnectivityHelper;
import ca.ualberta.cmput301w14t08.geochan.helpers.LocationListenerService;
import ca.ualberta.cmput301w14t08.geochan.helpers.SortUtil;
import ca.ualberta.cmput301w14t08.geochan.helpers.Toaster;
import ca.ualberta.cmput301w14t08.geochan.interfaces.UpdateDialogListenerInterface;
import ca.ualberta.cmput301w14t08.geochan.managers.CacheManager;
import ca.ualberta.cmput301w14t08.geochan.managers.PreferencesManager;
import ca.ualberta.cmput301w14t08.geochan.managers.ThreadManager;
import ca.ualberta.cmput301w14t08.geochan.models.GeoLocation;
import ca.ualberta.cmput301w14t08.geochan.models.ThreadComment;
import ca.ualberta.cmput301w14t08.geochan.models.ThreadList;
import eu.erikw.PullToRefreshListView;
import eu.erikw.PullToRefreshListView.OnRefreshListener;
/**
* Responsible for the UI fragment that displays multiple ThreadComments to the
* user.
*
* @author Henry Pabst
* @author Artem Chikin
*
*/
public class ThreadListFragment extends Fragment implements
UpdateDialogListenerInterface {
private BroadcastReceiver updateReceiver;
private PullToRefreshListView threadListView;
private ThreadListAdapter adapter;
private LocationListenerService locationListener = null;
private CacheManager cacheManager = null;
private ConnectivityHelper connectHelper = null;
private PreferencesManager prefManager = null;
private static boolean refresh = false;
private static int locSortFlag = 0;
/**
* Set up the fragment UI.
*
* @param inflater
* The LayoutInflater used to inflate the fragment's UI.
* @param container
* The parent View that the fragment's UI is attached to.
* @param savedInstanceState
* The previously saved state of the fragment.
* @return The View for the fragment's UI.
*
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater
.inflate(R.layout.fragment_thread_list, container, false);
}
/**
* Sets the fragment's adapter and starts a thread of execution to retrieve
* ThreadComments from ElasticSearch.
*
* @param savedInstanceState
* The previously saved state of the fragment.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
adapter = new ThreadListAdapter(getActivity(), ThreadList.getThreads());
if(prefManager == null){
prefManager = PreferencesManager.getInstance();
}
setHasOptionsMenu(true);
}
/**
* Starts the location listener listening. If we're sorting threads by a
* user-entered location, locSortFlag will be set to 1, so we sort according
* to the specified location and set the flag back to 0.
*/
@Override
public void onResume() {
if (locSortFlag == 1) {
prefManager.setThreadSort(SortUtil.SORT_LOCATION);
SortUtil.sortThreads(SortUtil.SORT_LOCATION,
ThreadList.getThreads());
adapter.notifyDataSetChanged();
locSortFlag = 0;
}
adapter.notifyDataSetChanged();
super.onResume();
}
/**
*Checks the proper sort option in our options menu.
*@param menu The fragment's menu.
*/
@Override
public void onPrepareOptionsMenu(Menu menu){
int sortType = prefManager.getThreadSort();
setSortCheck(sortType, menu);
super.onPrepareOptionsMenu(menu);
}
/**
* Checks if there is a network connection for pulling ThreadComments from
* ElasticSearch.
*
* @param savedInstanceState
* The previously saved state of the fragment.
*/
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
connectHelper = ConnectivityHelper.getInstance();
if (!connectHelper.isConnected()) {
Toaster.toastShort("No network connection.");
}
}
/**
* Initialize's the ThreadList's menu.
*
* @param menu
* The Menu of the fragment.
* @param inflater
* A MenuInflater to inflate the fragment's menu.
*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Inflate the menu; this adds items to the action bar if it is present.
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.thread_list, menu);
MenuItem item = menu.findItem(R.id.action_settings);
item.setVisible(true);
}
/**
* Sets the fragment's locSortFlag to 1 so sorting is done in onResume then
* sends the user to a CustomLocationFragment to enter the location they
* want to sort according to.
*/
private void getSortingLoc() {
Bundle args = new Bundle();
args.putInt("postType", CustomLocationFragment.SORT_THREAD);
CustomLocationFragment frag = new CustomLocationFragment();
frag.setArguments(args);
getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, frag, "customLocFrag")
.addToBackStack(null).commit();
getFragmentManager().executePendingTransactions();
}
/**
* Sets the user selected sorting option in our options menu.
* @param sort Code for the type of sort being used.
* @param menu The fragment's menu.
*/
private void setSortCheck(int sort, Menu menu){
MenuItem item;
switch(sort){
case SortUtil.SORT_DATE_NEWEST:
item = menu.findItem(R.id.thread_sort_date_new);
item.setChecked(true);
return;
case SortUtil.SORT_DATE_OLDEST:
item = menu.findItem(R.id.thread_sort_date_new);
item.setChecked(true);
return;
case SortUtil.SORT_LOCATION:
item = menu.findItem(R.id.thread_sort_location);
item.setChecked(true);
return;
case SortUtil.SORT_USER_SCORE_HIGHEST:
item = menu.findItem(R.id.thread_sort_score_high);
item.setChecked(true);
return;
case SortUtil.SORT_USER_SCORE_LOWEST:
item = menu.findItem(R.id.thread_sort_score_low);
item.setChecked(true);
return;
default:
return;
}
}
/**
* Initializes our fragment with various variables, displays the threads,
* sets up a onItemClickListener so the user is sent to the appropriate
* thread when they click on it, then sorts the threads according to the
* method the user has chosen.
*/
@Override
public void onStart() {
super.onStart();
if (locationListener == null) {
locationListener = new LocationListenerService(getActivity());
}
if (prefManager == null) {
prefManager = PreferencesManager.getInstance();
}
if (cacheManager == null) {
cacheManager = CacheManager.getInstance();
}
threadListView = (PullToRefreshListView) getActivity().findViewById(
R.id.thread_list);
// On start, get the threadList from the cache
ArrayList<ThreadComment> list = cacheManager.deserializeThreadList();
ThreadList.setThreads(list);
adapter = new ThreadListAdapter(getActivity(), ThreadList.getThreads());
threadListView.setEmptyView(getActivity().findViewById(
R.id.empty_list_view));
threadListView.setAdapter(adapter);
threadListView.setOnItemClickListener(new OnItemClickListener() {
@Override
/*
* On click, launch the fragment responsible for thread viewing
*/
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Fragment fragment = new ThreadViewFragment();
Bundle bundle = new Bundle();
bundle.putParcelable("thread",
ThreadList.getThreads().get((int) id));
bundle.putLong("id", id);
fragment.setArguments(bundle);
getFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, fragment,
"thread_view_fragment")
.addToBackStack("thread_view_fragment").commit();
getFragmentManager().executePendingTransactions();
}
});
int sort = prefManager.getThreadSort();
SortUtil.sortThreads(sort, ThreadList.getThreads());
//setSortCheck(sort);
adapter.notifyDataSetChanged();
threadListView.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh() {
if (!connectHelper.isConnected()) {
Toaster.toastShort("No network connection.");
threadListView.onRefreshComplete();
} else {
reload();
}
}
});
// Toggle PullToRefresh programatically on start
if (!refresh && connectHelper.isConnected()) {
threadListView.setRefreshing();
ThreadManager.startGetThreadComments(this);
refresh = true;
}
updateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (isVisible() && connectHelper.getWasNotConnected() == true) {
connectHelper.setWasNotConnected(false);
UpdateDialogFragment fragment = new UpdateDialogFragment();
fragment.show(getFragmentManager(), "updateDialogFrag");
}
}
};
getActivity()
.getApplicationContext()
.registerReceiver(
updateReceiver,
new IntentFilter(
ConnectivityBroadcastReceiver.UPDATE_FROM_SERVER_INTENT));
}
/**
* Determines which sorting method was selected and calls the appropriate
* sorting method on our list of threads.
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.thread_sort_date_new:
// User wants to push new threads to the top.
item.setChecked(true);
prefManager.setThreadSort(SortUtil.SORT_DATE_NEWEST);
SortUtil.sortThreads(SortUtil.SORT_DATE_NEWEST,
ThreadList.getThreads());
adapter.notifyDataSetChanged();
return true;
case R.id.thread_sort_date_old:
// User wants to push old threads to the top.
item.setChecked(true);
prefManager.setThreadSort(SortUtil.SORT_DATE_OLDEST);
SortUtil.sortThreads(SortUtil.SORT_DATE_OLDEST,
ThreadList.getThreads());
adapter.notifyDataSetChanged();
return true;
case R.id.thread_sort_score_high:
// User wants threads with high relevance/score at the top.
item.setChecked(true);
prefManager.setThreadSort(SortUtil.SORT_USER_SCORE_HIGHEST);
SortUtil.setThreadSortGeo(new GeoLocation(locationListener));
SortUtil.sortThreads(SortUtil.SORT_USER_SCORE_HIGHEST,
ThreadList.getThreads());
adapter.notifyDataSetChanged();
return true;
case R.id.thread_sort_score_low:
// User wants threads with low relevance/score at the top.
item.setChecked(true);
prefManager.setThreadSort(SortUtil.SORT_USER_SCORE_LOWEST);
SortUtil.setThreadSortGeo(new GeoLocation(locationListener));
SortUtil.sortThreads(SortUtil.SORT_USER_SCORE_LOWEST,
ThreadList.getThreads());
adapter.notifyDataSetChanged();
return true;
case R.id.thread_sort_location:
// User wants threads close to a selected location at the top.
item.setChecked(true);
locSortFlag = 1;
this.getSortingLoc();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* Starts a thread of execution to retrieve updated ThreadComments from
* ElasticSearch.
*/
@Override
public void reload() {
ThreadManager.startGetThreadComments(this);
}
/**
* Stores the retrieved ThreadComments in cache in case connection dies,
* applies the current sorting method to the newly retrieved ThreadComments,
* and refreshes the adapter so that they display properly.
*/
public void finishReload() {
cacheManager.serializeThreadList(ThreadList.getThreads());
SortUtil.sortThreads(prefManager.getThreadSort(),
ThreadList.getThreads());
adapter = new ThreadListAdapter(getActivity(), ThreadList.getThreads());
// Assign custom adapter to the thread listView.
threadListView.setAdapter(adapter);
adapter.notifyDataSetChanged();
threadListView.onRefreshComplete();
}
}