package com.nuscomputing.ivle.online; import java.util.Arrays; import java.util.List; import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.LoaderManager; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.actionbarsherlock.app.SherlockListFragment; import com.nuscomputing.ivle.DataLoader; import com.nuscomputing.ivle.IVLEUtils; import com.nuscomputing.ivle.R; import com.nuscomputing.ivlelapi.FailedLoginException; import com.nuscomputing.ivlelapi.IVLE; import com.nuscomputing.ivlelapi.JSONParserException; import com.nuscomputing.ivlelapi.Module; import com.nuscomputing.ivlelapi.Module.Description; import com.nuscomputing.ivlelapi.NetworkErrorException; import com.nuscomputing.ivlelapi.NoSuchModuleException; /** * Fragment to list modules. * @author yjwong */ public class ModuleInfoFragment extends SherlockListFragment { // {{{ properties /** TAG for logging */ public static final String TAG = "ModuleInfoFragment"; /** The module IVLE ID */ private String mModuleIvleId; /** The main listview */ private ListView mListView; // }}} // {{{ methods @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the module info view. return inflater.inflate(R.layout.module_info_fragment, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Obtain the module ID. Bundle args = getArguments(); mModuleIvleId = args.getString("moduleIvleId"); if (mModuleIvleId == null) { throw new IllegalStateException("No module IVLE ID was passed to ModuleInfoFragment"); } // Obtain the listview. mListView = getListView(); // Find and insert the linear layout. LinearLayout layout = (LinearLayout) getActivity().getLayoutInflater().inflate(R.layout.module_info_fragment_list_header, null); layout.setClickable(true); ArrayAdapter<String> loadingAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, new String[] { getString(R.string.loading) }); mListView.addHeaderView(layout); mListView.setAdapter(loadingAdapter); // Load the module info. getLoaderManager().initLoader(DataLoader.LOADER_MODULE_INFO_FRAGMENT_INFO, args, new InfoLoaderCallbacks()); // Load the module descriptions. getLoaderManager().initLoader(DataLoader.LOADER_MODULE_INFO_FRAGMENT_DESCRIPTIONS, args, new DescriptionsLoaderCallbacks()); } // }}} // {{{ classes /** * The loader callbacks for module information. * @author yjwong */ class InfoLoaderCallbacks implements LoaderManager.LoaderCallbacks<Module> { // {{{ methods @Override public Loader<Module> onCreateLoader(int id, Bundle args) { return new InfoLoader(getActivity(), args); } @TargetApi(11) @Override public void onLoadFinished(Loader<Module> loader, Module result) { // Set the view data. if (result != null) { TextView tvCourseName = (TextView) getActivity().findViewById(R.id.module_info_fragment_course_name); tvCourseName.setText(result.courseName); TextView tvCourseCode = (TextView) getActivity().findViewById(R.id.module_info_fragment_course_code); tvCourseCode.setText(result.courseCode); TextView tvCourseAcadYear = (TextView) getActivity().findViewById(R.id.module_info_fragment_course_acad_year); tvCourseAcadYear.setText(result.courseAcadYear); TextView tvCourseSemester = (TextView) getActivity().findViewById(R.id.module_info_fragment_course_semester); tvCourseSemester.setText(result.courseSemester); } else { Toast.makeText(getActivity(), R.string.module_info_fragment_unable_to_load, Toast.LENGTH_SHORT).show(); // Stop all other tasks. if (Build.VERSION.SDK_INT >= 11) { getActivity().getLoaderManager().destroyLoader(DataLoader.LOADER_MODULE_INFO_FRAGMENT_INFO); getActivity().getLoaderManager().destroyLoader(DataLoader.LOADER_MODULE_INFO_FRAGMENT_DESCRIPTIONS); getActivity().getLoaderManager().destroyLoader(DataLoader.LOADER_MODULE_LECTURERS_FRAGMENT); } getActivity().finish(); } } @Override public void onLoaderReset(Loader<Module> loader) { // Do nothing. } // }}} } /** * The module information loader. * @author yjwong */ static class InfoLoader extends AsyncTaskLoader<Module> { // {{{ properties /** Arguments to this loader */ private Bundle mArgs; /** The context */ private Context mContext; /** The module information */ private Module mModule; // }}} // {{{ methods InfoLoader(Context context, Bundle args) { super(context); mContext = context; mArgs = args; } @Override public void onStartLoading() { if (mModule != null ) { deliverResult(mModule); } if (takeContentChanged() || mModule == null) { forceLoad(); } } @Override public Module loadInBackground() { // Obtain the IVLE ID. String moduleIvleId = mArgs.getString("moduleIvleId"); // Acquire a new IVLE object. IVLE ivle = IVLEUtils.getIVLEInstance(mContext); try { Module module = ivle.getModule(moduleIvleId); return module; } catch (NetworkErrorException e) { Log.e(TAG, "NetworkErrorException encountered while loading module"); } catch (FailedLoginException e) { Log.e(TAG, "FailedLoginException encountered while loading module"); } catch (JSONParserException e) { Log.e(TAG, "JSONParserException encountered while loading module"); } catch (NoSuchModuleException e) { Log.e(TAG, "NoSuchModuleException encountered while loading module"); } return null; } // }}} } /** * The array adapter for module descriptions. * @author yjwong */ class DescriptionArrayAdapter extends ArrayAdapter<Description> { // {{{ properties /** The descriptions */ private List<Description> mObjects; // }}} // {{{ methods public DescriptionArrayAdapter(Context context, int textViewResourceId, List<Description> objects) { super(context, textViewResourceId, objects); mObjects = objects; } @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = getActivity().getLayoutInflater(); View view = inflater.inflate(R.layout.module_info_fragment_list_item, null); // Set the text. convertView = view.findViewById(R.id.module_info_fragment_list_description_title); ((TextView) convertView).setText(mObjects.get(position).title); return view; } // }}} } /** * The loader callbacks for module descriptions. * @author yjwong */ class DescriptionsLoaderCallbacks implements LoaderManager.LoaderCallbacks<List<Description>> { // {{{ methods @Override public Loader<List<Description>> onCreateLoader(int id, Bundle args) { return new DescriptionsLoader(getActivity(), args); } @Override public void onLoadFinished(Loader<List<Description>> loader, List<Description> descriptions) { // Check for errors. if (descriptions != null) { if (descriptions.size() > 0) { DescriptionArrayAdapter adapter = new DescriptionArrayAdapter(getActivity(), R.layout.module_info_fragment_list_item, descriptions); mListView.setAdapter(adapter); mListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // If the position is zero then we ignore. if (position == 0) { return; } // Obtain the description. Description description = (Description) parent.getItemAtPosition(position); // Add the description and title as arguments. Bundle args = new Bundle(); args.putString("description", description.description); args.putString("title", description.title); // Instantiate a new dialog fragment. FragmentManager manager = getActivity().getSupportFragmentManager(); DialogFragment fragment = new ModuleInfoDescriptionDialogFragment(); fragment.setArguments(args); fragment.show(manager, null); } }); } else { ArrayAdapter<String> adapter = new ArrayAdapter<String>( getActivity(), R.layout.module_info_fragment_list_item, R.id.module_info_fragment_list_description_title ); adapter.add(getString(R.string.module_info_fragment_no_additional_info)); mListView.setAdapter(adapter); } } else { ArrayAdapter<String> adapter = new ArrayAdapter<String>( getActivity(), R.layout.module_info_fragment_list_item, R.id.module_info_fragment_list_description_title ); adapter.add(getString(R.string.module_info_fragment_failed_to_load)); mListView.setAdapter(adapter); Toast.makeText( getActivity(), getString(R.string.module_info_fragment_unable_to_load_additional), Toast.LENGTH_SHORT) .show(); } } @Override public void onLoaderReset(Loader<List<Description>> loader) { } // }}} } /** * The loader for module descriptions. * @author yjwong */ static class DescriptionsLoader extends AsyncTaskLoader<List<Description>> { // {{{ properties /** Arguments to this loader */ private Bundle mArgs; /** The context */ private Context mContext; /** The descriptions */ private List<Description> mDescriptions; // }}} // {{{ methods DescriptionsLoader(Context context, Bundle args) { super(context); mContext = context; mArgs = args; } @Override public void onStartLoading() { if (mDescriptions != null) { deliverResult(mDescriptions); } if (takeContentChanged() || mDescriptions == null) { forceLoad(); } } @Override public List<Description> loadInBackground() { // Check if the descriptions are already loaded. if (mDescriptions != null) { return mDescriptions; } // Get the module IVLE ID. String moduleIvleId = mArgs.getString("moduleIvleId"); try { // Acquire a new IVLE object. IVLE ivle = IVLEUtils.getIVLEInstance(mContext); Module module = ivle.getModule(moduleIvleId); // Get the description. Description[] descriptions = module.getDescriptions(); mDescriptions = Arrays.asList(descriptions); return mDescriptions; } catch (NetworkErrorException e) { Log.w(TAG, "Unable to load module descriptions: network error"); } catch (FailedLoginException e) { Log.e(TAG, "Unable to load module descriptions: API raised FailedLoginException"); } catch (JSONParserException e) { Log.e(TAG, "Unable to load module descriptions: API raised JSONParserException"); } catch (NoSuchModuleException e) { Log.e(TAG, "Unable to load module descriptions: API raised NoSuchModuleException"); } return null; } // }}} } // }}} }