org.aweture.wonk.substitutions.Activity.java Source code

Java tutorial

Introduction

Here is the source code for org.aweture.wonk.substitutions.Activity.java

Source

package org.aweture.wonk.substitutions;

import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.Loader;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
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.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import org.aweture.wonk.Application;
import org.aweture.wonk.LicensesDialogFragment;
import org.aweture.wonk.R;
import org.aweture.wonk.background.PlanUpdateReceiver;
import org.aweture.wonk.background.PlanUpdateService;
import org.aweture.wonk.log.LogUtil;
import org.aweture.wonk.models.Plan;
import org.aweture.wonk.models.Substitution;
import org.aweture.wonk.models.Teacher;
import org.aweture.wonk.storage.SimpleData;

import java.util.ArrayList;
import java.util.List;

public class Activity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Plan> {

    private View feedbackContainer;
    private View noDataText;
    private View progessBar;

    private PartAdapter adapter;
    private List<RecyclerView> recyclerViews = new ArrayList<RecyclerView>();
    private Plan plan;

    private PlanUpdateReceiver receiver;

    private boolean isStudent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // This Activity is in every case the landing activity. But that doesn't mean that the
        // users should be shown this Activity. Maybe they should be redirected to the
        // landing Activity.
        if (shouldDisplayLanding()) {
            displayLandingActivity();
            return;
        }

        // Set content view and toolbar
        setContentView(R.layout.activity_substitutions);
        setSupportActionBar((Toolbar) findViewById(R.id.toolbar));

        // Set up ViewPager with an adapter and tabs.
        adapter = new PartAdapter();
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        viewPager.setAdapter(adapter);
        TabLayout tabLayout = (TabLayout) findViewById(R.id.tabLayout);
        tabLayout.setupWithViewPager(viewPager);

        // Set up the member variables.
        feedbackContainer = findViewById(R.id.feedbackContainer);
        noDataText = findViewById(R.id.noDataText);
        progessBar = findViewById(R.id.progressBar);

        // The ProgressBar might have a color that makes it hard to distinguish.
        // So it is set to the primary color to make sure everything is laid out properly.
        int primaryColor = ContextCompat.getColor(this, R.color.primary);
        ((ProgressBar) progessBar).getIndeterminateDrawable().setColorFilter(primaryColor, PorterDuff.Mode.SRC_IN);

        // Init the LoaderManager to load the content.
        LoaderManager loaderManager = getSupportLoaderManager();
        loaderManager.initLoader(R.id.SUBSTITUTIONS_ACTIVTY_PLAN_LOADER, null, this);
    }

    /**
     * shouldDisplayLanding() determines whether the users should be shown the landing Activity
     * before interacting with this Activity.
     * @return true in the case that the user should be redirected
     */
    private boolean shouldDisplayLanding() {
        SimpleData data = new SimpleData(this);
        return !data.isPasswordEntered();
    }

    /**
     * displayLandingActivity() redirects the user to the landing Activity and finishes
     * this Activity.
     */
    private void displayLandingActivity() {
        Intent intent = new Intent(this, org.aweture.wonk.landing.Activity.class);
        startActivity(intent);
        finish();
    }

    /**
     * showLoadingLayout() displays a progressbar and is intended to be used in loading
     * situations, as the name suggests.
     */
    private void showLoadingLayout() {
        feedbackContainer.setVisibility(View.VISIBLE);
        noDataText.setVisibility(View.GONE);
        progessBar.setVisibility(View.VISIBLE);
    }

    /**
     * showNoDataLayout() shows a text which acknowleges that the Activity has no data to show.
     */
    private void showNoDataLayout() {
        feedbackContainer.setVisibility(View.VISIBLE);
        noDataText.setVisibility(View.VISIBLE);
        progessBar.setVisibility(View.GONE);
    }

    /**
     * showNormalLayout() reverses the changes made by {@link #showLoadingLayout()}
     * and {@link #showNoDataLayout()}.
     */
    private void showNormalLayout() {
        feedbackContainer.setVisibility(View.GONE);
        noDataText.setVisibility(View.GONE);
        progessBar.setVisibility(View.GONE);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu according to IN_DEBUG_MODE flag.
        MenuInflater inflater = getMenuInflater();
        int menuId = Application.IN_DEBUG_MODE ? R.menu.substitutes_debug_mode : R.menu.substitutes;
        inflater.inflate(menuId, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_update:
            performPlanUpdate();
            return true;
        case R.id.action_show_licenses:
            LicensesDialogFragment fragment = new LicensesDialogFragment();
            fragment.show(getFragmentManager(), "LicensesDialog");
            return true;
        case R.id.action_settings:
            startActivity(new Intent(this, org.aweture.wonk.settings.Activity.class));
            return true;
        default:
            return false;
        }
    }

    private void performPlanUpdate() {
        if (!Application.hasConnectivity(this)) {
            Toast.makeText(this, "Keine Internetverbindung", Toast.LENGTH_SHORT).show();
            return;
        } else if (receiver != null) {
            Toast.makeText(this, "Update luft bereits.", Toast.LENGTH_SHORT).show();
            return;
        }

        showLoadingLayout();

        Intent intent = new Intent(this, PlanUpdateService.class);
        startService(intent);

        receiver = new PlanUpdateReceiver(new PlanUpdateReceiver.Handler() {
            @Override
            public void handleEvent(final Intent intent) {
                LogUtil.d("Processing intent form PlanUpdateService.");

                if (intent.getBooleanExtra(PlanUpdateService.EXTRA_FINISHED_SUCCESSFULLY, true)) {
                    // The update was successfull.
                    LogUtil.d("PlanUpdateService finished successfully. Loader will update UI.");
                } else {
                    // The update failed.
                    LogUtil.d("PlanUpdateService finished with exception. Showing pre update UI.");
                    showNormalLayout();
                    Toast.makeText(Activity.this, "Fehler beim Herunterladen", Toast.LENGTH_SHORT).show();
                }

                // Unregister the receiver when this broadcast is handled.
                LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(Activity.this);
                broadcastManager.unregisterReceiver(receiver);
                receiver = null;
                LogUtil.d("Unregistered PlanUpdateReceiver.");
            }

        });

        // Register the receiver.
        LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
        broadcastManager.registerReceiver(receiver, receiver.getIntentFilter());
    }

    @Override
    public Loader<Plan> onCreateLoader(int id, Bundle args) {
        return new PlanLoader(this);
    }

    @Override
    public void onLoadFinished(Loader<Plan> loader, Plan data) {
        // Set the new display mode.
        SimpleData sd = new SimpleData(this);
        isStudent = sd.isStudent();

        // Set the now
        plan = data;
        adapter.notifyDataSetChanged();

        if (plan.parts.length == 0) {
            // No plan or exception while reading.
            showNoDataLayout();
        } else {
            // There is a new plan. Update UI.
            showNormalLayout();

            // Inform all RecyclerViews about the new data.
            for (RecyclerView r : recyclerViews) {
                r.getAdapter().notifyDataSetChanged();
            }
        }
    }

    @Override
    public void onLoaderReset(Loader<Plan> loader) {
    }

    private class PartAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            if (plan == null)
                return 0;
            return plan.parts.length;
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Object instantiateItem(ViewGroup collection, int position) {
            // Create the item.
            View v = getLayoutInflater().inflate(R.layout.view_part, collection, false);
            RecyclerView rv = (RecyclerView) v.findViewById(R.id.recyclerView);
            recyclerViews.add(rv);
            rv.setLayoutManager(new LinearLayoutManager(Activity.this));
            rv.addItemDecoration(new DividerItemDecoration());

            // Create an Adapter.
            rv.setAdapter(new SubstitutionsAdapter(position));

            // Add the item to the ViewPager.
            collection.addView(v);

            if (plan.parts[position].substitutions.length == 0) {
                rv.setVisibility(View.GONE);
            }

            return v;
        }

        @Override
        public void destroyItem(ViewGroup collection, int position, Object view) {
            ((ViewPager) collection).removeView((View) view);
            RecyclerView rv = (RecyclerView) ((View) view).findViewById(R.id.recyclerView);
            recyclerViews.remove(rv);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            Plan.Part part = plan.parts[position];
            String relativeWord = part.day.resolveToRelativeWord();
            if (relativeWord == null) {
                return part.day.toDateString();
            } else {
                return relativeWord;
            }
        }

        private class DividerItemDecoration extends RecyclerView.ItemDecoration {
            Paint paint = new Paint();
            int deviderHeight = 1;

            public DividerItemDecoration() {
                paint.setColor(Color.LTGRAY);
            }

            @Override
            public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
                super.getItemOffsets(outRect, view, parent, state);

                if (parent.getChildAdapterPosition(view) == 0) {
                    return;
                }

                outRect.top = deviderHeight;
            }

            @Override
            public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
                int dividerLeft = parent.getPaddingLeft();
                int dividerRight = parent.getWidth() - parent.getPaddingRight();

                int childCount = parent.getChildCount();
                for (int i = 0; i < childCount - 1; i++) {
                    View child = parent.getChildAt(i);

                    RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

                    int dividerTop = child.getBottom() + params.bottomMargin;
                    int dividerBottom = dividerTop + deviderHeight;

                    canvas.drawRect(dividerLeft, dividerTop, dividerRight, dividerBottom, paint);
                }
            }
        }
    }

    private class SubstitutionsAdapter extends RecyclerView.Adapter<MyViewHolder> {
        private int part;
        private ViewInfo[] viewInfos;

        public SubstitutionsAdapter(int part) {
            this.part = part;
        }

        @Override
        public int getItemViewType(int position) {
            return viewInfos[position].type;
        }

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == 0) {
                return new MyViewHolder((TextView) LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.view_class_headline, parent, false));
            } else {
                return new MyViewHolder((TextView) LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.view_substitution, parent, false));
            }
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            ViewInfo vi = viewInfos[position];
            Substitution s = plan.parts[part].substitutions[vi.reference];
            if (isStudent) {
                holder.view.setText(textForStudent(vi, s));
            } else {
                holder.view.setText(textForTeacher(vi, s));
            }
        }

        private String textForStudent(ViewInfo vi, Substitution s) {
            if (vi.type == 0) {
                return s.className;
            } else {
                StringBuilder sb = new StringBuilder();
                sb.append(s.period);
                sb.append(". Stunde: ");
                if (s.instdSubject.name.length() > 0) {
                    sb.append(s.instdSubject.name);
                } else {
                    sb.append(s.instdSubject.abbr);
                }
                sb.append(" (");
                if (s.instdTeacher.name.length() > 0) {
                    sb.append(s.instdTeacher.name);
                } else {
                    sb.append(s.instdTeacher.abbr);
                }
                sb.append(")\n");
                sb.append(s.kind);
                if (s.kind.equals("Vertretung")) {
                    sb.append(": ");
                    if (s.substTeacher.name.length() > 0) {
                        sb.append(s.substTeacher.name);
                    } else {
                        sb.append(s.substTeacher.abbr);
                    }
                }
                if (s.text.length() > 0) {
                    sb.append("\n");
                    sb.append(s.text);
                }
                return sb.toString();
            }
        }

        private String textForTeacher(ViewInfo vi, Substitution s) {
            if (vi.type == 0) {
                return s.modeTaskProvider ? s.taskProvider.getName() : s.substTeacher.getName();
            } else {
                StringBuilder sb = new StringBuilder();
                sb.append(s.period);
                sb.append(". Stunde: ");
                if (s.modeTaskProvider) {
                    sb.append("Aufgabe stellen");
                } else if (s.substTeacher.abbr.equals(s.taskProvider.abbr)) {
                    sb.append(s.kind);
                    sb.append("/Aufgabe stellen");
                } else {
                    sb.append(s.kind);
                }
                sb.append("\n");
                sb.append(s.className);
                sb.append(", statt ");
                sb.append(s.instdSubject.name);
                sb.append(" (");
                sb.append(s.instdTeacher.abbr);
                sb.append(")");
                if (s.text.length() > 0) {
                    sb.append("\n");
                    sb.append(s.text);
                }
                return sb.toString();
            }
        }

        @Override
        public int getItemCount() {
            ArrayList<ViewInfo> viewInfos = new ArrayList<ViewInfo>(plan.parts[part].substitutions.length);
            for (int i = 0; i < plan.parts[part].substitutions.length; i++) {
                if (i == 0) {
                    // The first shown item is always a header.
                    // Make a header pointing to 0.
                    viewInfos.add(new ViewInfo(0, 0));
                    // Make a subtitution item showing the content of 0.
                    viewInfos.add(new ViewInfo(1, 0));
                } else if (isStudent) {
                    if (plan.parts[part].substitutions[i].className
                            .equalsIgnoreCase(plan.parts[part].substitutions[i - 1].className)) {
                        // If this class name equals the previous one, the next item shows the content of i.
                        viewInfos.add(new ViewInfo(1, i));
                    } else {
                        // If this class name does not equal the previous one, the next item is a header.
                        viewInfos.add(new ViewInfo(0, i));
                        // Then the actual i'th content is shown.
                        viewInfos.add(new ViewInfo(1, i));
                    }
                } else {
                    // Get this teacher and the previous one.
                    Substitution s = plan.parts[part].substitutions[i];
                    Teacher thisTeacher = s.modeTaskProvider ? s.taskProvider : s.substTeacher;
                    s = plan.parts[part].substitutions[i - 1];
                    Teacher prevTeacher = s.modeTaskProvider ? s.taskProvider : s.substTeacher;

                    if (thisTeacher.abbr.equalsIgnoreCase(prevTeacher.abbr)) {
                        // If the teacher names are equal, the next item shows the content of i.
                        viewInfos.add(new ViewInfo(1, i));
                    } else {
                        // If the teacher names are not equal, the next item is a header of i.
                        viewInfos.add(new ViewInfo(0, i));
                        // Then the actual i'th content is shown.
                        viewInfos.add(new ViewInfo(1, i));
                    }
                }
            }
            this.viewInfos = viewInfos.toArray(new ViewInfo[viewInfos.size()]);
            return viewInfos.size();
        }

        private class ViewInfo {
            public int type;
            public int reference;

            public ViewInfo(int type, int reference) {
                this.type = type;
                this.reference = reference;
            }
        }

    }

    private class MyViewHolder extends RecyclerView.ViewHolder {

        public TextView view;

        public MyViewHolder(TextView v) {
            super(v);
            view = v;
        }

    }
}