public class MainShoppingListView extends AppCompatActivity implements IBaseActivity, IBaseActivityListEvent, IOnShoppingListClickListenerEvents {

    private final static String LOG_TAG = MainShoppingListView.class.getName();
    private final static String DEFAULT_CATEGORY_NAME = "(default)";

    public final static String KEY_LISTNAME = "list_name";
    public final static String KEY_LISTID = "list_id";
    public static final String SIDE_DRAWER_TRANSLATE = "side_drawer_translate";

    private ICategoryController mCategoryController;
    private IListController mListController;

    private Toolbar mToolbar;
    private View.OnClickListener mToolbarClickListener;
    private FrameLayout mFrameLayout;
    private RelativeLayout mLeftMenuDrawerRelativeLayout;
    private EditText mNewNameEditText;

    private Button mAddListButton;
    private Button mAddCategoryButton;

    /**
     * For creation of an icon at the toolbar to toggle the navbar.
     */
    private ActionBarDrawerToggle mNavBarToggle;

    /**
     * Layout reference of the side drawer navbar.
     */
    private DrawerLayout mDrawerLayout;

    private Button mSettingsButton;

    /**
     * Title of the toolbar.
     */
    private String mTitle;

    /**
     * Name of the current list
     */
    private String mCurrentListName;

    private String mDefaultCategoryId;

    private SideDrawerListManager mDrawerListManager;

    private List<IFragment> mFragments;
    private float mLastDrawerTranslate = 0.0f;

    private Activity mActivity;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(LOG_TAG, "onCreate: " + this.toString());

        EventBus.getDefault().register(this);
        mActivity = this;
        mFragments = new ArrayList<>(1);

        setContentView(R.layout.activity_main_shopping_list_view);

        mCategoryController = ControllerFactory.getCategoryController(this);
        mListController = ControllerFactory.getListController(this);

        ExpandableListView expandableListView;
        ListView plainListView;

        // init PreferencesManager
        PreferencesManager.initializeInstance(this);
        mDefaultCategoryId = PreferencesManager.getInstance().getStringValue(PreferencesManager.KEY_DEFAULT_CATEGORY_ID);
        Category category = mCategoryController.getCategoryByID(mDefaultCategoryId);

        /*if (category == null) {
            // if not set generate a standard category and set the id of it to preferences
            category = mCategoryController.createCategory(DEFAULT_CATEGORY_NAME);
            mDefaultCategoryId = category.mUUID;
            PreferencesManager.getInstance().setValue(PreferencesManager.KEY_DEFAULT_CATEGORY_ID, mDefaultCategoryId);
        }*/

        // init and setup toolbar
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(mToolbar);
        if(getSupportActionBar() != null)
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        mDrawerLayout = (DrawerLayout) findViewById(R.id.main_drawer_layout_container);
        expandableListView = (ExpandableListView) findViewById(R.id.drawer_layout_custom_list_name_view);

        plainListView = (ListView) findViewById(R.id.drawer_layout_custom_plain_shopping_list_overview);
        mNewNameEditText = (EditText) findViewById(R.id.drawer_layout_custom_new_name);

        mAddListButton = (Button) findViewById(R.id.drawer_layout_custom_create_list);
        mAddCategoryButton = (Button) findViewById(R.id.drawer_layout_custom_create_category);

        mLeftMenuDrawerRelativeLayout = (RelativeLayout) findViewById(R.id.list_view_left_side_navigation);
        mSettingsButton = (Button) findViewById(R.id.drawer_layout_custom_settings);
        mFrameLayout = (FrameLayout) findViewById(R.id.container);
        mDrawerListManager = new SideDrawerListManager(this, plainListView, expandableListView);

        mDrawerLayout.setFitsSystemWindows(true);
        assignDrawer();
        // mNavBarToggle.setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
        mToolbarClickListener = mNavBarToggle.getToolbarNavigationClickListener();
        //  setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
        // setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);

        if (savedInstanceState == null) {
            List<ShoppingList> foundListsInCat = mListController.getListsByCategory(category);
            if (foundListsInCat.size() > 0) {
                selectList(foundListsInCat.get(0));
            } else {
                EventBus.getDefault().post(new ToolbarChangeMessage(false, getString(R.string.abc_no_shopping_list_selected)));
                EventBus.getDefault().post(new DrawerControlMessage(true));
            }
        }
    }

    @Override
    public void onCreateContextMenu(ContextMenu _Menu, View _View, ContextMenu.ContextMenuInfo _MenuInfo) {
        Log.i(LOG_TAG, "Context menu called.");
        _Menu = mDrawerListManager.createContextMenu(_Menu, _View, _MenuInfo);
        super.onCreateContextMenu(_Menu, _View, _MenuInfo);
    }

    @Override
    public boolean onContextItemSelected(MenuItem _Item) {
        Log.i(LOG_TAG, "Context menu item selected.");
        mDrawerListManager.onContextMenuItemClicked(_Item);
        return super.onContextItemSelected(_Item);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        //getMenuInflater().inflate(R.menu.menu_main, menu);
        //mToolbar.inflateMenu(R.menu.menu_toolbar_main_listview);
        // check if the drawer is open

        return true;
    }

    public void onEventMainThread(ToolbarChangeMessage _message) {
        if (_message.mNewLockState != null) {
            setDrawerLockMode(_message.mNewLockState ? DrawerLayout.LOCK_MODE_LOCKED_CLOSED :
                    DrawerLayout.LOCK_MODE_UNLOCKED);
        }
        if (_message.mNewTitle != null) {
            setToolbarTitle(_message.mNewTitle);
        }
    }

    /**
     * EventBus-Method for catching messages about created or deleted ListItem's.
     */
    public void onEventMainThread(ListItemChangedMessage _message) {
        switch (_message.mChange) {
            case CREATED:
            case DELETED:
                mDrawerListManager.updateList(_message.mEntry.mList);
        }
    }

    /**
     * Event when a category was changed.
     *
     * @param _message the message that was sent.
     */
    public void onEvent(CategoryChangedMessage _message) {
        switch (_message.mChange) {
            case CHANGED:
                mDrawerListManager.updateCategory(_message.mCategory);
                break;
            case CREATED:
                mDrawerListManager.addCategory(_message.mCategory);
                break;
            case DELETED:
                Category category = mCategoryController.getCategoryByID(mDefaultCategoryId);
                List<ShoppingList> shoppingLists = mListController.getListsByCategory(null);
                for (ShoppingList shoppingList : shoppingLists) {
                    ShoppingList shoppingList1 = mListController.moveToCategory(shoppingList, category);
                    mDrawerListManager.updateList(shoppingList1);
                }
                mDrawerListManager.removeCategory(_message.mCategory);
                break;
        }
    }

    /**
     * Handle the open and close messages for the side drawer.
     *
     * @param _message the sent msg.
     */
    public void onEvent(DrawerControlMessage _message) {
        if (_message.mOpenDrawer) {
            mDrawerLayout.openDrawer(Gravity.LEFT);
            mNewNameEditText.requestFocus();
            // set the add buttons visible state
            mAddCategoryButton.setVisibility(View.VISIBLE);
            mAddListButton.setVisibility(View.VISIBLE);
        }
    }

    /**
     * Event when a category was changed.
     *
     * @param _message the message that was sent.
     */
    public void onEvent(ListChangedMessage _message) {
        switch (_message.mChange) {
            case CHANGED:
                mDrawerListManager.updateList(_message.mList);
                break;
            case CREATED:
                mDrawerListManager.addList(_message.mList);
                break;
            case DELETED:
                mDrawerListManager.removeList(_message.mList);
                notifyFragmentsShoppingListRemoved(_message.mList);

                break;
        }
    }


    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mLeftMenuDrawerRelativeLayout);
        if (drawerOpen) {
            menu.clear();
        }

        return super.onPrepareOptionsMenu(menu);
    }

    @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();

        // The action bar home/up action should open or close the navbar.
        // ActionBarDrawerToggle will take care of this.
        // Consume the the onOptionsItemSelected event.
        if (mNavBarToggle.onOptionsItemSelected(item)) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        mNavBarToggle.syncState();
    }


    @Override
    protected void onResume() {
        super.onResume();

        EventBus bus = EventBus.getDefault();
        if (!bus.isRegistered(this)) {
            bus.register(this);
        }

        mAddListButton.setOnClickListener(new OnShoppingListAddClickListener(this, mDefaultCategoryId, mNewNameEditText));

        mAddCategoryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String categoryName = ViewUtils.validateAndGetResultEditText(v.getContext(), mNewNameEditText);
                if (categoryName == null) {
                    return;
                }

                // create new category if insert of category failed, there will be shown an
                // error hint to the user.
                Category category = mCategoryController.createCategory(categoryName);
                if (category == null) {
                    mNewNameEditText.setError(getResources().getString(R.string.category_exists));
                } else {
                    mAddCategoryButton.setVisibility(View.GONE);
                    ViewUtils.removeSoftKeyBoard(v.getContext(), mNewNameEditText);
                    mNewNameEditText.setText("");
                    mNewNameEditText.clearFocus();
                }
            }
        });

        mNewNameEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View _View, boolean _HasFocus) {
                if (_HasFocus) {
                    ((EditText) _View).setError(null);
                    mAddCategoryButton.setVisibility(View.VISIBLE);
                    mAddListButton.setVisibility(View.VISIBLE);
                } else {
                    mAddCategoryButton.setVisibility(View.GONE);
                    mAddListButton.setVisibility(View.GONE);
                    ViewUtils.removeSoftKeyBoard(_View.getContext(), mNewNameEditText);
                }
            }
        });
        mNewNameEditText.setOnKeyListener(new View.OnKeyListener() {

            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                ((EditText) v).setError(null);
                return false;
            }
        });

        mSettingsButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent settingsIntent;
                settingsIntent = new Intent(mActivity, SettingsActivity.class);
                startActivity(settingsIntent);
            }
        });

        bus.post(new ActivityStateMessage(this, ActivityStateMessage.State.RESUMED));
    }


    @Override
    protected void onPause() {
        super.onPause();
        mAddListButton.setOnClickListener(null);
        mNewNameEditText.setOnKeyListener(null);
        mSettingsButton.setOnClickListener(null);

        EventBus bus = EventBus.getDefault();
        bus.unregister(this);
        bus.post(new ActivityStateMessage(this, ActivityStateMessage.State.PAUSED));
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggls
        mNavBarToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public void onBackPressed() {

        if (getFragmentManager().getBackStackEntryCount() > 1) {
            getFragmentManager().popBackStack();
        } else {
            exitApp();
        }
    }

    public void exitApp() {
        super.onBackPressed();
    }

    // --------------------------------------------------------------------------------
    // own public methods
    // --------------------------------------------------------------------------------


    @Override
    public void selectList(ShoppingList _ShoppingList) {
        if (_ShoppingList.mName == null) {
            throw new NullPointerException("Name of ShoppingList must be set.");
        }

        // always close the drawer
        mDrawerLayout.closeDrawer(mLeftMenuDrawerRelativeLayout);

        // decl
        Bundle args;
        Fragment fragment;

        // init
        mCurrentListName = _ShoppingList.mName;
        fragment = ShoppingListOverviewFragment.newInstance(_ShoppingList.mUUID);
        ViewUtils.addFragment(this, fragment);
    }

    @Override
    public boolean onKeyUp(int _KeyCode, KeyEvent _Event) {
        if (_KeyCode == KeyEvent.KEYCODE_BACK) {
            if (mNewNameEditText.hasFocus()) {
                mNewNameEditText.clearFocus();
                return true;
            } else if (mDrawerLayout.isDrawerOpen(mLeftMenuDrawerRelativeLayout)) {
                mDrawerLayout.closeDrawers();
                return true;
            }
        }
        return super.onKeyUp(_KeyCode, _Event);
    }

    @Override
    public void setDrawerLockMode(int _DrawerLayoutMode) {
        // bindDrawerLayout();
        if (_DrawerLayoutMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
            mNavBarToggle.setDrawerIndicatorEnabled(false);

            // mToolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
            setNavigationClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onBackPressed();
                }
            });
        } else {
            assignDrawer();
            //setNavigationClickListener(mToolbarClickListener);
            mNavBarToggle.setDrawerIndicatorEnabled(true);
            mNavBarToggle.syncState();
        }
        mDrawerLayout.setDrawerLockMode(_DrawerLayoutMode);
    }

    /**
     * Changes from the current fragment to the given fragment.
     * Adds the current fragment to the backstack.
     *
     * @param _Fragment the fragment that should be created.
     */
    @Override
    public void changeFragment(Fragment _Fragment) {
        Log.w("NoOrg Deprecated", "MainShoppingListView's changeFragment.");
        ViewUtils.addFragment(this, _Fragment);
    }
/*
    @Override
    public void setNavigationIcon(int _ResId) {
        //mToolbar.setNavigationIcon(_ResId);
    }*/

    @Override
    public void setNavigationClickListener(View.OnClickListener _ClickListener) {
        mToolbar.setNavigationOnClickListener(_ClickListener);
    }

    @Override
    public void bindDrawerLayout() {
        setNavigationClickListener(mToolbarClickListener);
    }

    /**
     * Sets the text of the toolbar title, when activity is updated.
     *
     * @param _Title, the title of the toolbar
     */
    @Override
    public void setToolbarTitle(String _Title) {
        mTitle = _Title;
        mToolbar.setTitle(mTitle);
    }

    @Override
    public void setSideDrawerAddListButtonListener(String _CategoryId) {
        mAddListButton.setOnClickListener(new OnShoppingListAddClickListener(this, _CategoryId, mNewNameEditText));
    }

    @Override
    public void onShoppingListClicked(ShoppingList _ShoppingList) {
        selectList(_ShoppingList);
    }

    /**
     * Set a drawer to a fragmentlayout.
     */
    public void assignDrawer() {
        //mToolbar.setNavigationIcon(R.mipmap.ic_menu_white_36dp);
        // navbar custom design of toolbar

        mNavBarToggle = new ActionBarDrawerToggle(
                this,                       // host activity
                mDrawerLayout,              // DrawerLayout instance
                mToolbar,                   // Reference to toolbar
                R.string.nav_drawer_open,   // text for drawer on open icon
                R.string.nav_drawer_close   // text for drawer on close icon
        ) {

            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                // mToolbar.setNavigationIcon(R.mipmap.ic_menu_white_36dp);
                mToolbar.setTitle(mTitle);
                // check if options menu has changed
                invalidateOptionsMenu();
            }

            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                //mToolbar.setNavigationIcon(R.mipmap.ic_arrow_back_white_36dp);
                String tmpTitle = getString(R.string.choose_list);
                mToolbar.setTitle(tmpTitle);
                // check if options menu has changed
                invalidateOptionsMenu();
            }

            @Override
            public void onDrawerSlide(View _DrawerView, float _SlideOffset) {
                super.onDrawerSlide(_DrawerView, _SlideOffset);
                float moveFactor = (mDrawerLayout.getWidth() * _SlideOffset);
                slideDrawer(moveFactor);
            }
        };
        mDrawerLayout.setDrawerListener(mNavBarToggle);
        mNavBarToggle.setDrawerIndicatorEnabled(true);
    }

    private void slideDrawer(float _MoveFactor) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            mFrameLayout.setTranslationX(_MoveFactor);
        } else {
            TranslateAnimation anim = new TranslateAnimation(mLastDrawerTranslate, _MoveFactor, 0.0f, 0.0f);
            anim.setDuration(0);
            anim.setFillAfter(true);
            mFrameLayout.startAnimation(anim);
            mLastDrawerTranslate = _MoveFactor;
        }
    }

    @Override
    public void registerFragment(Fragment fragment) {
        try {
            mFragments.add((IFragment) fragment);
        } catch (ClassCastException e) {
            throw new ClassCastException(fragment.getClass().toString() + " has no IFragment implemented");
        }
    }

    @Override
    public void unregisterFragment(Fragment fragment) {
        mFragments.remove(fragment);
    }

    /**
     * Notifies registered Fragments that an ShoppingList was removed.
     *
     * @param _ShoppingList the shopping list that was removed.
     */
    public void notifyFragmentsShoppingListRemoved(ShoppingList _ShoppingList) {
        for (IFragment fragment : mFragments) {
            fragment.onShoppingListRemoved(_ShoppingList);
        }
    }
} public class AmountPicker extends LinearLayout {

    private ImageButton mDecreaseButton;
    private ImageButton mIncreaseButton;
    private EditText    mValueField;

    private float       mStep;

    private static final Integer DECREASE_TAG = -1;
    private static final Integer INCREASE_TAG =  1;

    private IValueChangeListener mListener;

    /**
     * Default constructor as described at the android docs.
     * {@see http://developer.android.com/guide/topics/ui/custom-components.html}
     */
    public AmountPicker(Context _context, AttributeSet _attributes) {
        super(_context, _attributes);

        mDecreaseButton = new ImageButton(_context);
        mIncreaseButton = new ImageButton(_context);
        mValueField     = new EditText(_context);

        IndecreaseListener changeListener = new IndecreaseListener();
        mDecreaseButton.setBackground(null);
        mDecreaseButton.setTag(DECREASE_TAG);
        mDecreaseButton.setOnClickListener(changeListener);

        mIncreaseButton.setBackground(null);
        mIncreaseButton.setTag(INCREASE_TAG);
        mIncreaseButton.setOnClickListener(changeListener);

        mValueField.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
        mValueField.setKeyListener(ViewUtils.getNumberListener());
        mValueField.setHint(R.string.product_details_amount_hint);
        mValueField.addTextChangedListener(new TextValueChangedListener());
        mValueField.setGravity(View.TEXT_ALIGNMENT_CENTER);

        if (getOrientation() == LinearLayout.HORIZONTAL) {
            mDecreaseButton.setImageResource(R.mipmap.ic_remove_black_24dp);
            mIncreaseButton.setImageResource(R.mipmap.ic_add_black_24dp);

            addView(mDecreaseButton);
            addView(mValueField);
            addView(mIncreaseButton);
        } else {
            mDecreaseButton.setImageResource(R.mipmap.ic_expand_more_black_24dp);
            mIncreaseButton.setImageResource(R.mipmap.ic_expand_less_black_24dp);

            addView(mIncreaseButton);
            addView(mValueField);
            addView(mDecreaseButton);
        }

        mStep = 1.0f;
    }

    /**
     * Sets a callback for changes. It will be called when a change was made via the UI. So calling
     * {@link #setValue(float)} should have no effect.
     * @param _newListener Either a listener or null to remove the listener. The given listener will
     *                     replace the old one (if one was set).
     */
    public void setChangeListener(IValueChangeListener _newListener) {
        mListener = _newListener;
    }

    /**
     * Sets the new value. Does not change anything if the new value is not conform.
     * @param _NewValue The new value, not lesser than 0.0f, not NaN and not infinite.
     */
    public void setValue(float _NewValue) {
        if (_NewValue < 0.0f || Float.isNaN(_NewValue) || Float.isInfinite(_NewValue)) {
            return;
        }

        mValueField.setText(new DecimalFormat("#.###").format(_NewValue));
    }

    /**
     * Reads the current value from the integrated textfield.
     * @return The value or 0.0f, if nothing set.
     */
    public float getValue() {
        return ViewUtils.parseFloatFromLocal(mValueField.getText().toString());
    }

    /**
     * Sets the step for incrementation or decrementation buttons.
     * @param _NewStep The new step-size. Must be a positive, finite number.
     */
    public void setStep(float _NewStep) {
        if (_NewStep < 0.0f || Float.isNaN(_NewStep) || Float.isInfinite(_NewStep)) {
            return;
        }

        mStep = _NewStep;
    }

    public float getStep() {
        return mStep;
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable parentState = super.onSaveInstanceState();

        SavedState rtn = new SavedState(parentState);
        rtn.mValue = getValue();

        return rtn;
    }

    @Override
    public void onRestoreInstanceState(Parcelable _restoreData) {
        if (!(_restoreData instanceof SavedState)) {
            super.onRestoreInstanceState(_restoreData);
            return;
        }

        SavedState savedData = (SavedState) _restoreData;
        super.onRestoreInstanceState(savedData.getSuperState());

        mValueField.setText(savedData.mValue + "");
    }

    public interface IValueChangeListener {
        void onValueChanged(AmountPicker _picker, float _newValue);
    }

    private static class SavedState extends BaseSavedState {
        public float mValue;

        public SavedState(Parcelable _superState) {
            super(_superState);
        }

        private SavedState(Parcel _loadParcel) {
            super(_loadParcel);
            mValue = _loadParcel.readFloat();
        }

        @Override
        public void writeToParcel(Parcel _output, int _flags) {
            super.writeToParcel(_output, _flags);
            _output.writeFloat(mValue);
        }

        /**
         * needed for making Parcels to Parcelables.
         * {@see http://stackoverflow.com/a/3542895/1354246}
         */
        public static final Parcelable.Creator<SavedState> CREATOR =
                new Parcelable.Creator<SavedState>() {
                    public SavedState createFromParcel(Parcel in) {
                        return new SavedState(in);
                    }
                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                };
    }

    private class IndecreaseListener implements View.OnClickListener {
        @Override
        public void onClick(View _view) {
            if (_view.getTag() instanceof Integer) {
                Integer tag = (Integer) _view.getTag();

                if (tag.compareTo(INCREASE_TAG) == 0) {
                    float newValue = getValue() + mStep;
                    setValue(newValue);
                    if (mListener != null) {
                        mListener.onValueChanged(AmountPicker.this, newValue);
                    }
                } else if (tag.compareTo(DECREASE_TAG) == 0) {
                    float newValue = Math.max(0.0f, getValue() - mStep);
                    setValue(newValue);
                    if (mListener != null) {
                        mListener.onValueChanged(AmountPicker.this, newValue);
                    }
                }

            }
        }
    }

    private class TextValueChangedListener implements TextWatcher {

        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            // Not used.
        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            // Not used.
        }

        @Override
        public void afterTextChanged(Editable editable) {
            if (mListener != null) {
                float newValue = getValue();
                mListener.onValueChanged(AmountPicker.this, newValue);
            }
        }
    }

} public class DividerItemListDecoration extends RecyclerView.ItemDecoration{

    private Drawable mDivider;
    private boolean mShowFirstDivider = false;
    private boolean mShowLastDivider = false;


    public DividerItemListDecoration(Context context, AttributeSet attrs) {
        final TypedArray a = context
                .obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
        mDivider = a.getDrawable(0);
        a.recycle();
    }

    public DividerItemListDecoration(Drawable divider) {
        mDivider = divider;
    }

    public DividerItemListDecoration(Drawable divider, boolean showFirstDivider,
                                 boolean showLastDivider) {
        this(divider);
        mShowFirstDivider = showFirstDivider;
        mShowLastDivider = showLastDivider;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                               RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (mDivider == null) {
            return;
        }
        if (parent.getChildLayoutPosition(view) < 1) {
            return;
        }

        if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
            // real height of divider
            outRect.top = mDivider.getIntrinsicHeight();
        } else {
            outRect.left = mDivider.getIntrinsicWidth();
        }
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mDivider == null) {
            super.onDrawOver(c, parent, state);
            return;
        }

        // Initialization needed to avoid compiler warning
        int left = 0, right = 0, top = 0, bottom = 0, size;
        int orientation = getOrientation(parent);
        int childCount = parent.getChildCount();

        if (orientation == LinearLayoutManager.VERTICAL) {
            size = mDivider.getIntrinsicHeight();
            left = parent.getPaddingLeft();
            right = parent.getWidth() - parent.getPaddingRight();
        } else { //horizontal
            size = mDivider.getIntrinsicWidth();
            top = parent.getPaddingTop();
            bottom = parent.getHeight() - parent.getPaddingBottom();
        }

        for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) {
            View child = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            if (orientation == LinearLayoutManager.VERTICAL) {
                top = child.getTop() - params.topMargin;
                bottom = top + size;
            } else { //horizontal
                left = child.getLeft() - params.leftMargin;
                right = left + size;
            }
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }

        // show last divider
        if (mShowLastDivider && childCount > 0) {
            View child = parent.getChildAt(childCount - 1);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            if (orientation == LinearLayoutManager.VERTICAL) {
                top = child.getBottom() + params.bottomMargin;
                bottom = top + size;
            } else { // horizontal
                left = child.getRight() + params.rightMargin;
                right = left + size;
            }
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    private int getOrientation(RecyclerView parent) {
        if (parent.getLayoutManager() instanceof LinearLayoutManager) {
            LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
            return layoutManager.getOrientation();
        } else {
            throw new IllegalStateException(
                    "DividerItemDecoration can only be used with a LinearLayoutManager.");
        }
    }


} public class ActivityStateMessage {
    public enum State {
        PAUSED,
        RESUMED
    }

    /**
     * The activity which state changes.
     */
    public Activity mActivity;

    /**
     * The new state of the activity.
     */
    public State    mState;

    public ActivityStateMessage(Activity _activity, State _state) {
        mActivity = _activity;
        mState    = _state;
    }
} public class ShoppingListOverviewFragmentActiveEvent {

    public boolean mActive;

    public ShoppingListOverviewFragmentActiveEvent(boolean _active){
        mActive = _active;
    }
} public class ShoppingListSelectedMessage {

    /**
     * The attribute ShoppingList.
     */
    public ShoppingList mShoppingList;

    /**
     * Constructor of the EventMessage.
     * @param _shoppingList the shoppingList that was selected.
     */
    public ShoppingListSelectedMessage(@NonNull ShoppingList _shoppingList) {
        mShoppingList = _shoppingList;
    }
} public class ToolbarChangeMessage {
    public Boolean mNewLockState;
    public String  mNewTitle;

    public ToolbarChangeMessage(Boolean _newLockState, String _newTitle) {
        mNewLockState = _newLockState;
        mNewTitle     = _newTitle;
    }
} public interface IBaseActivity {
    /**
     * Changes the current Fragment to the given Fragment.
     * @param _NewFragment The Fragment to move to.
     */
    void    changeFragment(Fragment _NewFragment);

    /**
     * Set the toolbar title to the given string.
     * @param _ToolbarTitle the string to display on the toolbar.
     */
    void    setToolbarTitle(String _ToolbarTitle);

    /**
     * Set the DrawerLayout mode. (Closed, Open,..)
     * @param _DrawerLayoutMode the DrawerLayout mode.
     */
    void setDrawerLockMode(int _DrawerLayoutMode);

    /**
     * Called when Back was pressed.
     */
    void onBackPressed();

    /**
     * Sets the Navigation Icon.
     * @param _ResId the resource id of the resource. (drawable|mipmap)
     */
    //void setNavigationIcon(int _ResId);

    /**
     * Set the NavigationClickListener.
     * @param _ClickListener the click listener that implements the logic when pressed.
     */
    void setNavigationClickListener(View.OnClickListener _ClickListener);

    /**
     * Updates the DrawerLayout. Needed to provide that it is working. Also updates the option menu.
     * Best place to call it, before a fragment is removed and the user should be led to the ShoppingList overview.
     */
    void bindDrawerLayout();

    /**
     * UnRegister the given view for context menu.
     * @param _View the view to be registered for contextmenu.
     */
    void unregisterForContextMenu(View _View);

    /**
     * Register the view for the contextmenu.
     * @param _View The view to be registered for the contextmenu.
     */
    void registerForContextMenu(View _View);

    /**
     * Create a new listener with the given category id.
     * @param _CategoryId the Id of category where the category should be placed in.
     */
    void setSideDrawerAddListButtonListener(String _CategoryId);

    void registerFragment(Fragment fragment);
    void unregisterFragment(Fragment fragment);
} public interface IFragment {

    /**
     * Called when @Link{ShoppingList} has been removed.
     * @param _ShoppingList the @Link{ShoppingList} that has been removed.
     */
    void onShoppingListRemoved(ShoppingList _ShoppingList);
} public class ShoppingItemListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements IShoppingListEntryAction {

    //region private attributes
    private static String LOG_TAG = ShoppingItemListAdapter.class.getName();

    /**
     * The list of Entries.
     */
    private List<ListEntryItemWrapper> mListOfEntries = null;

    /**
     * The context of the app.
     */
    private Context mContext;

    /**
     * The current comparator that is assigned for sorting of the data in mListOfEntries.
     */
    private Comparator<ListEntryItemWrapper> mCurrentComparator;

    /**
     * The current ListEntry that is in edit mode. Used to shorten acceess time.
     */
    private ListEntryItemWrapper mCurrentItemInEditMode;

    //endregion

    //region Constructor

    /**
     * Constructor of ShoppingItemListAdapter2.
     * Uses by default the Alphabetical comparator.
     *
     * @param _Context       The context of the app.
     * @param _ListOfEntries the array of ListEntries that should be used.
     */
    public ShoppingItemListAdapter(Context _Context, List<ListEntry> _ListOfEntries) {
        if (_ListOfEntries == null) {
            throw new IllegalArgumentException("List cannot be null!");
        }

        mListOfEntries = new ArrayList<>(_ListOfEntries.size());
        for (ListEntry listEntry : _ListOfEntries) {
            mListOfEntries.add(new ListEntryItemWrapper(listEntry));
        }

        mContext = _Context;
        mCurrentComparator = new AlphabeticalListEntryComparator();
    }
    //endregion

    public static class ViewType {
        public static final int NORMAL_VIEW        = 0;
        public static final int EDIT_MODE_VIEW     = 1;
        public static final int SELECTED_MODE_VIEW = 2;
    }

    // -----------------------------------------------------------

    //region private Viewholder
    private final static class ViewHolder {
        public final static class ShoppingListProductViewHolder extends RecyclerView.ViewHolder {
            private TextView mProductAmount;
            private TextView mProductType;
            private TextView mProductName;

            //private Context mContext;

            public ShoppingListProductViewHolder(View _ItemView, Context _Context) {
                super(_ItemView);

                mProductAmount = (TextView) _ItemView.findViewById(R.id.list_product_shopping_product_amount);
                mProductType = (TextView) _ItemView.findViewById(R.id.list_product_shopping_product_amount_type);
                mProductName = (TextView) _ItemView.findViewById(R.id.list_product_shopping_product_name);

                // mContext = _Context;
            }

            public void init(ListEntry _SingleEntry) {

                mProductAmount.setText(ViewUtils.formatFloat(_SingleEntry.mAmount));
                mProductName.setText(String.valueOf(_SingleEntry.mProduct.mName));

                if (_SingleEntry.mProduct.mUnit != null && _SingleEntry.mProduct.mUnit.mName.length() > 0) {
                    mProductType.setText(_SingleEntry.mProduct.mUnit.mName);
                } else {
                    mProductType.setText("");
                }
                List<TextView> textViewsToStroke = new ArrayList<>();
                textViewsToStroke.add(mProductAmount);
                textViewsToStroke.add(mProductName);
                textViewsToStroke.add(mProductType);
                ViewUtils.setStrokeView(_SingleEntry.mStruck, textViewsToStroke);
            }

        }

        public final static class ShoppingListEditProductViewHolder extends RecyclerView.ViewHolder {

            public AmountPicker mProductAmount;
            public Spinner      mProductType;
            public TextView     mProductName;

            private Context mContext;
            private IUnitController mUnitController;

            public ShoppingListEditProductViewHolder(View _ItemView, Context _Context) {
                super(_ItemView);
                mContext = _Context;
                mProductAmount = (AmountPicker) _ItemView.findViewById(R.id.list_product_shopping_product_amount_edit);
                mProductType = (Spinner) _ItemView.findViewById(R.id.list_product_shopping_product_amount_type_edit);
                mProductName = (TextView) _ItemView.findViewById(R.id.list_product_shopping_product_name);
                mUnitController = ControllerFactory.getUnitController(mContext);
            }

            public void init(ListEntry _SingleEntry) {
                mProductName.setText(_SingleEntry.mProduct.mName);
                mProductType.setAdapter(new UnitSpinnerAdapter(mContext, mUnitController.
                        listAll(null, false)));
                mProductAmount.setValue(_SingleEntry.mAmount);
            }

        }
    }
    //endregion

    @Override
    public int getItemViewType(int _Position) {
        switch (mListOfEntries.get(_Position).getMode()) {
            default:
            case ListEntryItemWrapper.ACTION_MODE.NORMAL_MODE:
                return ViewType.NORMAL_VIEW;
            case ListEntryItemWrapper.ACTION_MODE.EDIT_MODE:
                return ViewType.EDIT_MODE_VIEW;
            case ListEntryItemWrapper.ACTION_MODE.SELECT_MODE:
                return ViewType.SELECTED_MODE_VIEW;
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup _Parent, int _ViewType) {

        View           view;
        LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        switch (_ViewType) {
            case ViewType.NORMAL_VIEW:
                view = layoutInflater.inflate(R.layout.list_shopping_product_entry, _Parent, false);
                return new ViewHolder.ShoppingListProductViewHolder(view, mContext);
            case ViewType.EDIT_MODE_VIEW:
                view = layoutInflater.inflate(R.layout.list_shopping_product_entry_edit, _Parent, false);
                return new ViewHolder.ShoppingListEditProductViewHolder(view, mContext);
            case ViewType.SELECTED_MODE_VIEW:
                // TODO: implement! break;
            default:
                throw new IllegalStateException("Type: " + _ViewType + " is not defined as Viewtype.");
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder _ProductViewHolder, int _Position) {
        final ListEntryItemWrapper singleEntryItemWrapper = mListOfEntries.get(_Position);
        final ListEntry            singleEntry            = singleEntryItemWrapper.getListEntry();

        switch (_ProductViewHolder.getItemViewType()) {
            default:
            case ViewType.NORMAL_VIEW:
                ViewHolder.ShoppingListProductViewHolder viewHolder = (ViewHolder.ShoppingListProductViewHolder) _ProductViewHolder;
                viewHolder.init(singleEntry);
                break;

            case ViewType.EDIT_MODE_VIEW:
                ViewHolder.ShoppingListEditProductViewHolder viewHolderEdit = (ViewHolder.ShoppingListEditProductViewHolder) _ProductViewHolder;
                viewHolderEdit.init(singleEntry);
                break;
            case ViewType.SELECTED_MODE_VIEW:
                // TODO: do some stuff :D
                break;
        }
    }

    @Override
    public int getItemCount() {
        return mListOfEntries.size();
    }

    @Override
    public void addListEntry(String _ListEntryId) {
        ListEntry listEntry = ControllerFactory.getListController(mContext).getEntryById(_ListEntryId);
        mListOfEntries.add(new ListEntryItemWrapper(listEntry));
        Collections.sort(mListOfEntries, mCurrentComparator);
        // if here is a position like -1 there must be some strange effects going on.
        notifyItemInserted(getPositionForId(_ListEntryId));
    }

    @Override
    public void removeListEntry(String _ListEntryId) {
        int       positionToRemove = getPositionForId(_ListEntryId);
        if (positionToRemove < 0 || positionToRemove > mListOfEntries.size()) {
            Log.e(LOG_TAG, "Remove ListEntry from position " + positionToRemove + " is out of bounds");
            return;
        }
        mListOfEntries.remove(positionToRemove);
        notifyItemRemoved(positionToRemove);
    }

    @Override
    public void updateListEntry(ListEntry _ListEntry) {
        int       positionToUpdate = getPositionForId(_ListEntry.mUUID);
        if (positionToUpdate < 0 || positionToUpdate > mListOfEntries.size()) {
            Log.e(LOG_TAG, "Update ListEntry from position " + positionToUpdate + " is out of bounds");
            return;
        }
        mListOfEntries.set(positionToUpdate, new ListEntryItemWrapper(_ListEntry));

        Collections.sort(mListOfEntries, mCurrentComparator);
        int newPositionOfElement = getPositionForId(_ListEntry.mUUID);

        notifyItemChanged(positionToUpdate);
        notifyItemMoved(positionToUpdate, newPositionOfElement);
    }

    public ListEntry getItem(int _Position){
        return mListOfEntries.get(_Position).getListEntry();
    }

    @Override
    public long getItemId(int _Position) {
        return UUID.fromString(mListOfEntries.get(_Position).getListEntry().mUUID).
                getLeastSignificantBits();
    }

    @Override
    public void resetEditModeView() {
        int positionToUpdate = getPositionForId(mCurrentItemInEditMode.getListEntry().mUUID);
        if(positionToUpdate < 0){
            return;
        }

        mCurrentItemInEditMode.resetModeToNormalView();
        notifyItemChanged(positionToUpdate);
    }

    @Override
    public void setToEditMode(int _Position) {
        if (_Position < 0) {
            return;
        }
        mCurrentItemInEditMode = mListOfEntries.get(_Position);
        mCurrentItemInEditMode.setEditMode(true);
        notifyItemChanged(_Position);
    }

    @Override
    public void sortByComparator(Comparator<ListEntryItemWrapper> _Comparator) {
        mCurrentComparator = _Comparator;
        Collections.sort(mListOfEntries, _Comparator);
        notifyDataSetChanged();
    }

    @Override
    public int getPositionForId(String _Id) {
        int position = - 1;
        for (ListEntryItemWrapper listItem : mListOfEntries) {
            if (listItem.getListEntry().mUUID.equals(_Id)) {
                position = mListOfEntries.indexOf(listItem);
                break;
            }
        }
        return position;
    }
} public class AlphabeticalListEntryComparator implements Comparator<ListEntryItemWrapper> {

    private static AlphabeticalListEntryComparator sInstance;

    @Override
    public int compare(ListEntryItemWrapper _toCheck, ListEntryItemWrapper _baseEntry) {

        ListEntry toCheck = _toCheck.getListEntry();
        ListEntry baseEntry = _baseEntry.getListEntry();

        if(toCheck.mStruck && !baseEntry.mStruck){
            return 1;
        }else if(!toCheck.mStruck && baseEntry.mStruck){
            return -1;
        }
        return Collator.getInstance().compare(toCheck.mProduct.mName, baseEntry.mProduct.mName);
    }

    public static AlphabeticalListEntryComparator getInstance() {
        if (sInstance == null) {
            sInstance = new AlphabeticalListEntryComparator();
        }
        return sInstance;
    }
} public class PriorityListEntryComparator implements Comparator<ListEntryItemWrapper> {

    private static PriorityListEntryComparator sInstance;

    @Override
    public int compare(ListEntryItemWrapper _toCheck, ListEntryItemWrapper _baseEntry) {

        ListEntry toCheck = _toCheck.getListEntry();
        ListEntry baseEntry = _baseEntry.getListEntry();

        if(toCheck.mStruck && !baseEntry.mStruck){
            return 1;
        }else if(!toCheck.mStruck && baseEntry.mStruck){
            return -1;
        }

        if (toCheck.mPriority > baseEntry.mPriority) {
            return -1;
        }
        if (toCheck.mPriority < baseEntry.mPriority) {
            return 1;
        }
        return Collator.getInstance().compare(toCheck.mProduct.mName, baseEntry.mProduct.mName);
    }

    public static PriorityListEntryComparator getInstance() {
        if (sInstance == null) {
            sInstance = new PriorityListEntryComparator();
        }
        return sInstance;
    }
} public class OnRecyclerItemTouchListener implements RecyclerView.OnItemTouchListener, IOnRecyclerItemTouchEvents{

    public View mView;
    private final GestureDetector mGestureDetector;

    public OnRecyclerItemTouchListener(Context context, RecyclerView recyclerView){
        mGestureDetector = new GestureDetector(context, new GestureListener(this, recyclerView));
        mView   = recyclerView;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {

    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        // maybe here are some performance tweaks possible
        return mGestureDetector.onTouchEvent(e);
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean b) {

    }

    /**
     * Event fires if user flings from left to right.
     * @param childView the view of the affected action.
     * @param position the position in the recycleradapter.
     */
    public void onSwipeRight(View childView, int position) {}

    /**
     * Event fires if user flings from right to left.
     * @param childView the view of the affected action.
     * @param position the position in the recycleradapter.
     */
    public void onSwipeLeft(View childView, int position) {}
    /**
     * Event fires if user do a single tap on a item in the list.
     * @param childView the view of the affected action.
     * @param position the position in the recycleradapter.
     */
    public void onSingleTap(View childView, int position){}
    /**
     * Event fires if user do a LongPress on a item in the view..
     * @param _ChildView the view of the affected action.
     * @param _Position the position in the recycleradapter.
     */
    public void onLongPress(View _ChildView, int _Position){}



    private static final class GestureListener extends GestureDetector.SimpleOnGestureListener {

        private static final int SWIPE_THRESHOLD = 80;
        private static final int SWIPE_VELOCITY_THRESHOLD = 20;
        private static final float SWIPE_MAX_ANGLE = 3.1415f / 5;

        private OnRecyclerItemTouchListener mGestureListener;
        private RecyclerView mRecyclerView;

        /**
         * Creates a new instance of a GestureListener.
         * @param _OnGestureListener The listener, that listens to those events.
         * @param recyclerView the recyclerview attached to layout.
         */
        public GestureListener(OnRecyclerItemTouchListener _OnGestureListener, RecyclerView recyclerView){
            this.mGestureListener   = _OnGestureListener;
            this.mRecyclerView      = recyclerView;
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            View childView  = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
            int position    = mRecyclerView.getChildAdapterPosition(childView);

            mGestureListener.onSingleTap(childView, position);
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            super.onLongPress(e);
            View childView  = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
            int position    = mRecyclerView.getChildAdapterPosition(childView);

            mGestureListener.onLongPress(childView, position);
        }

        @Override
        public boolean onDown(MotionEvent e) {
            return false;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

            // boolean result = false;
            if(e1 == null || e2 == null) return false;

            float diffX = e2.getX() - e1.getX();

            if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                View childView  = mRecyclerView.findChildViewUnder(e1.getX(), e1.getY());
                int position    = mRecyclerView.getChildAdapterPosition(childView);
                if(position < 0){
                    return false;
                }

                float diffY = e2.getY() - e1.getY();
                double normY = diffY / Math.sqrt(diffX * diffX + diffY * diffY);
                double absMaxNormY = Math.sin((SWIPE_MAX_ANGLE / 2.0f));

                if (normY <= absMaxNormY && normY >= -absMaxNormY) {
                    if (diffX > 0) {
                        mGestureListener.onSwipeRight(childView, position);
                    } else {
                        mGestureListener.onSwipeLeft(childView, position);
                    }
                }
            }
            return false;
        }
    }
} public class PreferencesManager {

    private static String PREFERENCES_NAME = "shoppinglist_settings";


    // --------------------------------------------------------------------------------
    //region Keys
    /**
     * The key for the default category name. Used to store uncategorized ListEntries in this.
     */
    public static String KEY_DEFAULT_CATEGORY_ID = "default_category_id";
    //endregion

    // --------------------------------------------------------------------------------
    // singleton
    private static PreferencesManager mInstance;

    private SharedPreferences mSharedPreferences;

    /**
     * The initializer of an instance. Use this before anything else.
     *
     * @param _Context The context of the Activity where the preferences are saved.
     */
    public static void initializeInstance(Context _Context) {
        if (mInstance == null) {
            mInstance = new PreferencesManager(_Context);
        }
    }

    /**
     * The Constructor of PreferencesManager. Assigns the context.
     *
     * @param _Context the Context on which the preferences should be defined.
     */
    private PreferencesManager(Context _Context) {
        mSharedPreferences = _Context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
    }

    /**
     * Retrieve the instance of PreferencesManager.
     *
     * @return the instace of PreferencesManager.
     */
    public static PreferencesManager getInstance() {
        if (mInstance == null) {
            throw new IllegalStateException("Instance of PreferencesManager Singleton" + "" +
                    "was not initializedl. First call initializeInstance.");
        }
        return mInstance;
    }

    /**
     * Persists the given key value pair.
     *
     * @param _Key   the key of the value.
     * @param _Value the value that is assigned to the key.
     */
    public void setValue(String _Key, long _Value) {
        mSharedPreferences.edit()
                .putLong(_Key, _Value)
                .apply();
    }

    /**
     * Persists the given key value pair.
     *
     * @param _Key   the key of the value.
     * @param _Value the value that is assigned to the key.
     */
    public void setValue(String _Key, int _Value){
        mSharedPreferences.edit()
                .putInt(_Key, _Value)
                .apply();
    }

    /**
     * Persists the given key value pair.
     *
     * @param _Key   the key of the value.
     * @param _Value the value that is assigned to the key.
     */
    public void setValue(String _Key, String _Value) {
        mSharedPreferences.edit()
                .putString(_Key, _Value)
                .apply();
    }

    /**
     * Retrieves the long value of the given key.
     *
     * @param _Key the key for which the value should be returned.
     * @return if key exists the corresponding value of that key,  else -1L.
     */
    public long getLongValue(String _Key) {
        return mSharedPreferences.getLong(_Key, -1L);
    }

    /**
     * Retrieves the int value of the given key.
     *
     * @param _Key the key for which the value should be returned.
     * @return if key exists the corresponding value of that key,  else -1.
     */
    public int getIntValue(String _Key) {
        return mSharedPreferences.getInt(_Key, -1);
    }

    /**
     * Retrieves the String value of the given key.
     *
     * @param _Key the key for which the value should be returned.
     * @return if key exists the corresponding value of that key,  else null.
     */
    public String getStringValue(String _Key) {
        return mSharedPreferences.getString(_Key, null);
    }

    /**
     * Retrieves the assigned sharedPreferences object. Use it for special tasks.
     *
     * @return the sharedpreferences hold by the singleton.
     */
    public SharedPreferences getSharedPreferences() {
        return mSharedPreferences;
    }

} public class ViewUtils {

    /**
     * NUMBERS_AND_SEPARATOR is a workaround for a Bug in EditText's, existing since Android 1.5!
     * Accept local decimal separator and dot as decimal separator - for usability and compatibility
     * reasons.
     * {@see https://code.google.com/p/android/issues/detail?id=2626}
     */
    private static final String NUMBERS_AND_SEPARATOR = "0123456789." +
            DecimalFormatSymbols.getInstance().getDecimalSeparator();

    /**
     * Checks if the given EditText is filled with some text. If it is not filled then there
     * will be set a error message.
     *
     * @param _EditText the EditText that should be tested.
     * @return true, if filled, false if not.
     */
    public static boolean checkEditTextIsFilled(EditText _EditText) {
        if (_EditText.length() == 0
                || (_EditText.getText().toString().replaceAll("(\\s)*", "").length() == 0)) {

            _EditText.setError("Not filled");
            return false;
        }

        _EditText.setError(null);
        return true;
    }


    /**
     * Sets/unsets the Stroke fields for an view or removes them.
     *
     * @param _StrikeViews if true, all given view components are stroke. else they will be unstroke.
     * @param _Views       the list of views that should be stroke or unstroke.
     */
    public static void setStrokeView(boolean _StrikeViews, List<TextView> _Views) {
        if (_StrikeViews) {
            // element is striked
            for (TextView textView : _Views) {
                textView.setPaintFlags(textView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            }
        } else {
            // element is unstriked
            for (TextView textView : _Views) {
                textView.setPaintFlags(textView.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
            }
        }
    }

    /**
     * Retrieve a KeyListener that accepts decimal numbers and dots as separator. Additionally the
     * decimal separator of the current language is accepted.
     *
     * @return An instance of a DigitKeyListener with additional separator.
     */
    public static KeyListener getNumberListener() {
        return DigitsKeyListener.getInstance(NUMBERS_AND_SEPARATOR);
    }

    /**
     * Converts a float to string with current locale.
     *
     * @param _toConvert The number to be converted.
     * @return The converted number with at max 3 digits after separator.
     */
    public static String formatFloat(float _toConvert) {
        NumberFormat formatter = new DecimalFormat("#.###");
        return formatter.format(_toConvert);
    }

    /**
     * Parses a float from a string. The languages separator will be also accepted.
     *
     * @param _toConvert The String to parse.
     * @return Either the parsed number or {@code 0.0f} if the string could not be parsed.
     */
    public static float parseFloatFromLocal(String _toConvert) {
        String toConvert = "0" + _toConvert.
                replace('.', DecimalFormatSymbols.getInstance().getDecimalSeparator());
        NumberFormat formatter = DecimalFormat.getInstance();
        try {
            return formatter.parse(toConvert).floatValue();
        } catch (Exception _notUsed) {
            return 0.0f;
        }
    }

    /**
     * Replaces the current fragment and adds it to back-stack.
     *
     * @param _activity    The activity where fragment should be attached. Must be capable of handling
     *                     the FragmentManager.
     * @param _newFragment The new fragment to hang in. Can also be a dialog fragment.
     */
    public static void addFragment(Activity _activity, Fragment _newFragment) {
        FragmentManager fragmentManager = _activity.getFragmentManager();
        String canonicalName = _newFragment.getClass().getCanonicalName();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        if (_newFragment instanceof DialogFragment) {
            ((DialogFragment) _newFragment).show(transaction, canonicalName);
        } else {
            transaction.addToBackStack(canonicalName);
            transaction.replace(R.id.container, _newFragment, canonicalName);
            transaction.commit();
        }
    }

    /**
     * Removes a fragment from the activity, if attached.
     *
     * @param _activity    The activity to remove the Fragment from.
     * @param _oldFragment The Fragment to remove. Note: all Fragment on top on this will also be
     *                     removed.
     */
    public static void removeFragment(Activity _activity, Fragment _oldFragment) {
        FragmentManager fragmentManager = _activity.getFragmentManager();
        fragmentManager.popBackStack(_oldFragment.getClass().getCanonicalName(),
                FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

    /**
     * Validate the Input of the given EditText and retrieve its value.
     *
     * @param _Context  context of the app.
     * @param _EditText the EditText with the want data.
     * @return the inout string of the EditText field.
     */
    public static String validateAndGetResultEditText(Context _Context, EditText _EditText) {
        _EditText.setError(null);
        if (!ViewUtils.checkEditTextIsFilled(_EditText)) {
            _EditText.setError(_Context.getString(R.string.error_no_input));
            return null;
        }
        return _EditText.getText().toString();
    }

    /**
     * Hides the keyboard from screen.
     *
     * @param _Context  the current context.
     * @param _EditText the editText View with the current input focus.
     */
    public static void removeSoftKeyBoard(Context _Context, EditText _EditText) {
        InputMethodManager imm = (InputMethodManager) _Context.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(_EditText.getWindowToken(), 0);
    }

    /**
     * Show the {@link Snackbar} with the given message.
     *
     * @param _ParentView the current parent view.
     * @param _MessageId  the id of the message.
     * @param _Duration   the duration of showing the snackbar. {@link Snackbar#LENGTH_SHORT} or {@link Snackbar#LENGTH_LONG}.
     */
    public static void showSnackbar(View _ParentView, int _MessageId, int _Duration) {
        Snackbar.make(_ParentView, _MessageId, _Duration)
                .show();
    }

    /**
     * Show the {@link Snackbar} with the given message and a specified action.
     *
     * @param _ParentView     the current parent view.
     * @param _MessageId      the id of the message.
     * @param _Duration       the duration of showing the snackbar. {@link Snackbar#LENGTH_SHORT} or {@link Snackbar#LENGTH_LONG}.
     * @param _ActionStringId the id for the string that represents the string for the action to display.
     * @param _ClickListener  the click listener to react to an click on the action.
     */
    public static void showSnackbar(View _ParentView, int _MessageId, int _Duration,
                                    int _ActionStringId, View.OnClickListener _ClickListener) {
        Snackbar.make(_ParentView, _MessageId, _Duration)
                .setAction(_ActionStringId, _ClickListener)
                .show();
    }
}
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import org.noorganization.instalist.R;
import org.noorganization.instalist.model.ListEntry;
import org.noorganization.instalist.model.ShoppingList;
import org.noorganization.instalist.presenter.IListController;
import org.noorganization.instalist.presenter.event.ListItemChangedMessage;
import org.noorganization.instalist.presenter.implementation.ControllerFactory;
import org.noorganization.instalist.view.activity.MainShoppingListView;
import org.noorganization.instalist.view.customview.AmountPicker;
import org.noorganization.instalist.view.decoration.DividerItemListDecoration;
import org.noorganization.instalist.view.event.ActivityStateMessage;
import org.noorganization.instalist.view.event.ShoppingListOverviewFragmentActiveEvent;
import org.noorganization.instalist.view.event.ShoppingListSelectedMessage;
import org.noorganization.instalist.view.event.ToolbarChangeMessage;
import org.noorganization.instalist.view.interfaces.IBaseActivity;
import org.noorganization.instalist.view.interfaces.IFragment;
import org.noorganization.instalist.view.listadapter.ShoppingItemListAdapter;
import org.noorganization.instalist.view.sorting.shoppingList.AlphabeticalListEntryComparator;
import org.noorganization.instalist.view.sorting.shoppingList.PriorityListEntryComparator;
import org.noorganization.instalist.view.touchlistener.OnRecyclerItemTouchListener;
import org.noorganization.instalist.view.utils.PreferencesManager;
import org.noorganization.instalist.view.utils.ViewUtils;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import de.greenrobot.event.EventBus;
                    if (amountPicker == null) {
                        Log.e(LOG_TAG, "mAmountPicker is null.");
                        return true;
                    }

                    float value = amountPicker.getValue();
                    if (value == 0.0f) {
                        // TODO: some error messaging
                        return true;
                    }
                    entry.mAmount = value;
                    // entry.mUnit = unit;

                    ControllerFactory.getListController(mContext).addOrChangeItem(mCurrentShoppingList, entry.mProduct, value);
                    _Mode.finish();
                    break;
                case R.id.menu_cancel_action:
                    _Mode.finish();
                    break;
                case R.id.menu_delete_action:
                    ControllerFactory.getListController(mContext).removeItem(mListController.getEntryById(mListEntryId));
                    _Mode.finish();
                    break;
                default:
                    return false;
            }
            return true;
        }

        @Override
        public void onDestroyActionMode(ActionMode _Mode) {
            mShoppingItemListAdapter.resetEditModeView();
            mView.setSelected(false);
            mActionMode = null;
            mAddButton.setVisibility(View.VISIBLE);
        }

        /**
         * Gets the ListEntry by an id. If it is null then an @Link{NullPointerException} will be thrown.
         *
         * @param _Id the id of the ListEntry.
         * @return the ListEntry.
         */
        private ListEntry getListEntryById(String _Id) {
            ListEntry listEntry = ControllerFactory.getListController(mContext).getEntryById(_Id);
            if (listEntry == null) {
                Log.e(LOG_TAG, "ListEntry is not defined.");
                throw new NullPointerException("ListEntry is not defined.");
            }
            return listEntry;
        }
    }


    // --------------------------------------------------------------------------------------------


    public ShoppingListOverviewFragment() {
    }

    /**
     * Creates an instance of an ShoppingListOverviewFragment.
     *
     * @param _ListId id of the @Link{ShoppingList} that should be shown.
     * @return the new instance of this fragment.
     */
    public static ShoppingListOverviewFragment newInstance(String _ListId) {

        ShoppingListOverviewFragment fragment = new ShoppingListOverviewFragment();
        Bundle args = new Bundle();
        args.putString(MainShoppingListView.KEY_LISTID, _ListId);
        fragment.setArguments(args);
        return fragment;
    }

    // --------------------------------------------------------------------------------------------


    @Override
    protected void onAttachToContext(Context _Context) {
        mContext = _Context;

        try {
            mBaseActivityInterface = (IBaseActivity) getActivity();
        } catch (ClassCastException e) {
            throw new ClassCastException(getActivity().toString()
                    + " has no IBaseActivity interface attached.");
        }

        mListController = ControllerFactory.getListController(mContext);
    }

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

        setHasOptionsMenu(true);
        // get bundle args to get the listname that should be shown
        Bundle bundle = this.getArguments();

        mMapComperable = new WeakHashMap<>();
        mMapComperable.put(0, new AlphabeticalListEntryComparator());
        mMapComperable.put(1, new PriorityListEntryComparator());


        if (bundle == null) {
            return;
        }

        String listId = bundle.getString(MainShoppingListView.KEY_LISTID);
        mCurrentShoppingList = mListController.getListById(listId);

        // assign other listname if none is assigned
        if (mCurrentShoppingList == null) {
            List<ShoppingList> mShoppingLists = mListController.getAllLists();
            if (mShoppingLists.size() > 0) {
                mCurrentShoppingList = mShoppingLists.get(0);
                //mBaseActivityInterface.setToolbarTitle(mCurrentShoppingList.mName);
            }
        }
        EventBus.getDefault().post(new ShoppingListSelectedMessage(mCurrentShoppingList));