cw.kop.autobackground.sources.SourceListFragment.java Source code

Java tutorial

Introduction

Here is the source code for cw.kop.autobackground.sources.SourceListFragment.java

Source

/*
* Copyright (C) Winson Chiu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package cw.kop.autobackground.sources;

import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.Fragment;
import android.app.PendingIntent;
import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.widget.CardView;
import android.util.Log;
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.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Transformation;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.squareup.picasso.Cache;
import com.squareup.picasso.Picasso;

import org.json.JSONObject;

import java.lang.reflect.Field;

import cw.kop.autobackground.DialogFactory;
import cw.kop.autobackground.LiveWallpaperService;
import cw.kop.autobackground.MainActivity;
import cw.kop.autobackground.R;
import cw.kop.autobackground.files.FileHandler;
import cw.kop.autobackground.images.LocalImageFragment;
import cw.kop.autobackground.settings.AppSettings;

public class SourceListFragment extends Fragment implements AdapterView.OnItemClickListener, View.OnClickListener {

    public static final String ADD_ENTRY = "cw.kop.autobackground.SourceListFragment.ADD_ENTRY";
    public static final String SET_ENTRY = "cw.kop.autobackground.SourceListFragment.SET_ENTRY";

    private static final String TAG = SourceListFragment.class.getCanonicalName();
    private static final int SCROLL_ANIMATION_TIME = 150;
    private static final int INFO_ANIMATION_TIME = 250;
    private static final int ADD_ANIMATION_TIME = 350;
    private static final long EXIT_ANIMATION_TIME = 200l;

    private ListView sourceList;
    private SourceListAdapter listAdapter;
    private Context appContext;
    private Handler handler;
    private Button setButton;
    private ImageView addButtonBackground;
    private ImageView addButton;
    private Menu toolbarMenu;

    // Volatile variables to assure animations are reset properly
    private volatile boolean needsButtonReset = false;
    private volatile boolean needsListReset = false;

    // Hold screen dimensions to calculate animations
    private int screenHeight;
    private int screenWidth;

    /**
     * Receives DOWNLOAD_TERMINATED intent to reset download button icon and recount available images
     */
    private BroadcastReceiver sourceListReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {

            String action = intent.getAction();
            switch (action) {
            case SourceListFragment.ADD_ENTRY:
                Source addSource = new Source();

                addSource.setType(intent.getStringExtra("type"));
                addSource.setTitle(intent.getStringExtra("title"));
                addSource.setData(intent.getStringExtra("data"));
                addSource.setNum(intent.getIntExtra("num", 0));
                addSource.setUse(intent.getBooleanExtra("use", true));
                addSource.setPreview(intent.getBooleanExtra("preview", true));
                addSource.setUseTime(intent.getBooleanExtra("use_time", false));
                addSource.setTime(intent.getStringExtra("time"));

                addEntry(addSource);
                break;
            case SourceListFragment.SET_ENTRY:
                Source setSource = new Source();

                setSource.setType(intent.getStringExtra("type"));
                setSource.setTitle(intent.getStringExtra("title"));
                setSource.setData(intent.getStringExtra("data"));
                setSource.setNum(intent.getIntExtra("num", 0));
                setSource.setUse(intent.getBooleanExtra("use", true));
                setSource.setPreview(intent.getBooleanExtra("preview", true));
                setSource.setUseTime(intent.getBooleanExtra("use_time", false));
                setSource.setTime(intent.getStringExtra("time"));

                setEntry(intent.getIntExtra("position", -1), setSource);
                break;
            case FileHandler.DOWNLOAD_TERMINATED:
                new ImageCountTask().execute();
                break;
            default:
            }

        }
    };

    public SourceListFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        setHasOptionsMenu(true);
        super.onCreate(savedInstanceState);
        handler = new Handler();

        screenHeight = getResources().getDisplayMetrics().heightPixels;
        screenWidth = getResources().getDisplayMetrics().widthPixels;

        AppSettings.resetVer1_30();
        AppSettings.resetVer1_40();
        AppSettings.resetVer2_00();
        AppSettings.resetVer2_00_20();
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

        // Inflate menu and hold reference in toolbarMenu
        inflater.inflate(R.menu.source_list_menu, menu);
        super.onCreateOptionsMenu(menu, inflater);
        toolbarMenu = menu;

        // Sets correct colors of toolbar icons
        int colorFilterInt = AppSettings.getColorFilterInt(appContext);
        Drawable refreshIcon = getResources().getDrawable(R.drawable.ic_refresh_white_24dp);
        Drawable storageIcon = getResources().getDrawable(R.drawable.ic_sort_white_24dp);
        refreshIcon.setColorFilter(colorFilterInt, PorterDuff.Mode.MULTIPLY);
        storageIcon.setColorFilter(colorFilterInt, PorterDuff.Mode.MULTIPLY);
        menu.getItem(0).setIcon(refreshIcon);
        menu.getItem(2).setIcon(storageIcon);

        // Recounts images
        new ImageCountTask().execute();
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        appContext = activity;
    }

    @Override
    public void onDestroy() {

        // Attempt using Reflection to force clear Picasso cache to make sure previews are accurate
        try {
            Field clearCache = Class.forName("com.squareup.picasso.Picasso").getDeclaredField("cache");
            clearCache.setAccessible(true);
            Cache cache = (Cache) clearCache.get(Picasso.with(appContext));
            cache.clear();

        } catch (Exception e) {
            Log.d(TAG, "" + e);
        }
        super.onDestroy();
    }

    @Override
    public void onDetach() {
        appContext = null;
        super.onDetach();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_sources, container, false);

        final ImageView emptyArrow = (ImageView) view.findViewById(R.id.empty_arrow);
        TextView emptyText = (TextView) view.findViewById(R.id.empty_text);
        emptyText.setText("Try hitting the + and adding some sources");
        emptyText.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                emptyArrow.setVisibility(visibility);
            }
        });
        sourceList = (ListView) view.findViewById(R.id.source_list);
        sourceList.setEmptyView(emptyArrow);
        addButtonBackground = (ImageView) view.findViewById(R.id.floating_button);
        addButton = (ImageView) view.findViewById(R.id.floating_button_icon);
        addButton.setOnClickListener(this);
        resetAddButtonIcon();

        setButton = (Button) view.findViewById(R.id.set_button);
        setButton.setOnClickListener(this);

        final SourceListAdapter.CardClickListener listener = new SourceListAdapter.CardClickListener() {
            @Override
            public void onDeleteClick(final View view, final int index) {

                listAdapter.saveData();
                if (FileHandler.isDownloading) {
                    Toast.makeText(appContext, "Cannot delete while downloading", Toast.LENGTH_SHORT).show();
                    return;
                }

                Source item = listAdapter.getItem(index);
                String type = item.getType();
                if (type.equals(AppSettings.FOLDER)) {

                    DialogFactory.ActionDialogListener clickListener = new DialogFactory.ActionDialogListener() {

                        @Override
                        public void onClickRight(View v) {
                            listAdapter.removeItem(index);
                            new ImageCountTask().execute();
                            this.dismissDialog();
                        }
                    };

                    DialogFactory.showActionDialog(appContext, "", "Delete " + item.getTitle() + "?", clickListener,
                            -1, R.string.cancel_button, R.string.ok_button);

                } else {
                    DialogFactory.ActionDialogListener clickListener = new DialogFactory.ActionDialogListener() {

                        @Override
                        public void onClickMiddle(View v) {
                            this.dismissDialog();
                            listAdapter.removeItem(index);
                            new ImageCountTask().execute();
                        }

                        @Override
                        public void onClickRight(View v) {
                            Source source = listAdapter.getItem(index);
                            FileHandler.deleteBitmaps(appContext, source);
                            sendToast("Deleting " + source.getTitle() + " images");
                            listAdapter.removeItem(index);
                            new ImageCountTask().execute();
                            this.dismissDialog();
                        }

                    };

                    DialogFactory.showActionDialog(appContext, "Delete images along with this source?",
                            "This cannot be undone.", clickListener, R.string.cancel_button, R.string.no_button,
                            R.string.yes_button);
                }

            }

            @Override
            public void onViewImageClick(View view, int index) {
                showViewImageFragment(view, index);
            }

            @Override
            public void onEditClick(View view, int index) {
                startEditFragment(view, index);
            }

            @Override
            public void onExpandClick(View view, int position) {
                onItemClick(null, view, position, 0);
            }
        };

        if (listAdapter == null) {
            listAdapter = new SourceListAdapter(getActivity(), listener);
            for (int index = 0; index < AppSettings.getNumberSources(); index++) {

                Source source = AppSettings.getSource(index);

                listAdapter.addItem(source, false);
                Log.i(TAG, "Added: " + source.getTitle());
            }
        }
        sourceList.setAdapter(listAdapter);

        sourceList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                listAdapter.toggleActivated(position);
                int firstVisiblePosition = sourceList.getFirstVisiblePosition();
                View childView = sourceList.getChildAt(position - firstVisiblePosition);
                sourceList.getAdapter().getView(position, childView, sourceList);
                return true;
            }
        });

        sourceList.setOnItemClickListener(this);

        return view;
    }

    @Override
    public void onClick(final View v) {

        switch (v.getId()) {

        case R.id.set_button:
            setWallpaper();
            break;
        case R.id.floating_button_icon:
            final GradientDrawable circleDrawable = (GradientDrawable) getResources()
                    .getDrawable(R.drawable.floating_button_circle);
            final float scale = (float) ((Math.hypot(addButtonBackground.getX(), addButtonBackground.getY())
                    + addButtonBackground.getWidth()) / addButtonBackground.getWidth() * 2);

            Animation animation = new Animation() {

                private boolean needsFragment = true;
                private float pivot;

                @Override
                public void initialize(int width, int height, int parentWidth, int parentHeight) {
                    super.initialize(width, height, parentWidth, parentHeight);

                    pivot = resolveSize(RELATIVE_TO_SELF, 0.5f, width, parentWidth);
                }

                @Override
                protected void applyTransformation(float interpolatedTime, Transformation t) {

                    if (needsFragment && interpolatedTime >= 1) {
                        needsFragment = false;
                        showSourceAddFragment();
                    } else {
                        float scaleFactor = 1.0f + ((scale - 1.0f) * interpolatedTime);
                        t.getMatrix().setScale(scaleFactor, scaleFactor, pivot, pivot);
                    }
                }

                @Override
                public boolean willChangeBounds() {
                    return true;
                }

            };

            animation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    circleDrawable.setColor(getResources().getColor(R.color.ACCENT_OPAQUE));
                    addButtonBackground.setImageDrawable(circleDrawable);
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (needsButtonReset) {
                                addButton.setOnClickListener(SourceListFragment.this);
                                addButtonBackground.setScaleX(1.0f);
                                addButtonBackground.setScaleY(1.0f);
                                addButtonBackground.clearAnimation();
                                circleDrawable.setColor(getResources().getColor(R.color.ACCENT_OPAQUE));
                                addButtonBackground.setImageDrawable(circleDrawable);
                                addButton.setVisibility(View.VISIBLE);
                            }
                        }
                    }, 100);
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }

            });

            ValueAnimator buttonColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(),
                    getResources().getColor(R.color.ACCENT_OPAQUE),
                    getResources().getColor(AppSettings.getBackgroundColorResource()));
            buttonColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    circleDrawable.setColor((Integer) animation.getAnimatedValue());
                    addButtonBackground.setImageDrawable(circleDrawable);
                }

            });

            DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator();

            animation.setDuration(ADD_ANIMATION_TIME);
            buttonColorAnimation.setDuration((long) (ADD_ANIMATION_TIME * 0.9));
            buttonColorAnimation.setInterpolator(decelerateInterpolator);
            animation.setInterpolator(decelerateInterpolator);

            // Post a delayed Runnable to ensure reset even if animation is interrupted
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (needsButtonReset) {
                        addButtonBackground.setScaleX(1.0f);
                        addButtonBackground.setScaleY(1.0f);
                        addButtonBackground.clearAnimation();
                        circleDrawable.setColor(getResources().getColor(R.color.ACCENT_OPAQUE));
                        addButtonBackground.setImageDrawable(circleDrawable);
                        addButton.setVisibility(View.VISIBLE);
                        needsButtonReset = false;
                    }
                }
            }, (long) (ADD_ANIMATION_TIME * 1.1f));

            needsButtonReset = true;
            addButton.setVisibility(View.GONE);
            buttonColorAnimation.start();
            addButtonBackground.startAnimation(animation);
            break;
        default:
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
        case R.id.cycle_wallpaper:
            cycleWallpaper();
            sendToast("Cycling wallpaper...");
            break;
        case R.id.download_wallpaper:
            startDownload();
            break;
        case R.id.sort_sources:
            if (FileHandler.isDownloading) {
                sendToast("Cannot sort while downloading");
            } else {
                showSourceSortMenu();
            }
            break;
        }

        return true;
    }

    /**
     * Saves data in list and sends Intent to cycle wallpaper
     */
    private void cycleWallpaper() {
        listAdapter.saveData();
        Intent intent = new Intent();
        intent.setAction(LiveWallpaperService.CYCLE_IMAGE);
        intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
        appContext.sendBroadcast(intent);
    }

    /**
     * Starts (or stops) download and sets download icon appropriately
     */
    private void startDownload() {
        listAdapter.saveData();
        if (FileHandler.isDownloading) {

            DialogFactory.ActionDialogListener listener = new DialogFactory.ActionDialogListener() {

                @Override
                public void onClickRight(View v) {
                    FileHandler.cancel(appContext);
                    resetActionBarDownload();
                    dismissDialog();
                }
            };

            DialogFactory.showActionDialog(appContext, "", "Cancel download?", listener, -1, R.string.cancel_button,
                    R.string.ok_button);
        } else if (FileHandler.download(appContext)) {
            Drawable drawable = getResources().getDrawable(R.drawable.ic_cancel_white_24dp);
            drawable.setColorFilter(AppSettings.getColorFilterInt(appContext), PorterDuff.Mode.MULTIPLY);
            toolbarMenu.getItem(1).setIcon(drawable);

            if (AppSettings.resetOnManualDownload() && AppSettings.useTimer()
                    && AppSettings.getTimerDuration() > 0) {
                Intent intent = new Intent();
                intent.setAction(LiveWallpaperService.DOWNLOAD_WALLPAPER);
                intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
                PendingIntent pendingIntent = PendingIntent.getBroadcast(appContext, 0, intent, 0);
                AlarmManager alarmManager = (AlarmManager) appContext.getSystemService(Context.ALARM_SERVICE);
                alarmManager.cancel(pendingIntent);
                alarmManager.setInexactRepeating(AlarmManager.RTC,
                        System.currentTimeMillis() + AppSettings.getTimerDuration(), AppSettings.getTimerDuration(),
                        pendingIntent);
            }
        }
    }

    /**
     * Shows LocalImageFragment to view images
     *
     * @param view  source card which was selected
     * @param index position of source in listAdapter
     */
    private void showViewImageFragment(final View view, final int index) {
        sourceList.setOnItemClickListener(null);
        sourceList.setEnabled(false);

        listAdapter.saveData();
        Source item = listAdapter.getItem(index);
        String type = item.getType();
        String directory;
        if (type.equals(AppSettings.FOLDER)) {
            directory = item.getData().split(AppSettings.DATA_SPLITTER)[0];
        } else {
            directory = AppSettings.getDownloadPath() + "/" + item.getTitle() + " " + AppSettings.getImagePrefix();
        }

        Log.i(TAG, "Directory: " + directory);

        final RelativeLayout sourceContainer = (RelativeLayout) view.findViewById(R.id.source_container);
        final ImageView sourceImage = (ImageView) view.findViewById(R.id.source_image);
        final View imageOverlay = view.findViewById(R.id.source_image_overlay);
        final EditText sourceTitle = (EditText) view.findViewById(R.id.source_title);
        final ImageView deleteButton = (ImageView) view.findViewById(R.id.source_delete_button);
        final ImageView viewButton = (ImageView) view.findViewById(R.id.source_view_image_button);
        final ImageView editButton = (ImageView) view.findViewById(R.id.source_edit_button);
        final LinearLayout sourceExpandContainer = (LinearLayout) view.findViewById(R.id.source_expand_container);

        final float viewStartHeight = sourceContainer.getHeight();
        final float viewStartY = view.getY();
        final float overlayStartAlpha = imageOverlay.getAlpha();
        final float listHeight = sourceList.getHeight();
        Log.i(TAG, "listHeight: " + listHeight);
        Log.i(TAG, "viewStartHeight: " + viewStartHeight);

        final LocalImageFragment localImageFragment = new LocalImageFragment();
        Bundle arguments = new Bundle();
        arguments.putString("view_path", directory);
        localImageFragment.setArguments(arguments);

        Animation animation = new Animation() {

            private boolean needsFragment = true;

            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {

                if (needsFragment && interpolatedTime >= 1) {
                    needsFragment = false;
                    getFragmentManager().beginTransaction()
                            .add(R.id.content_frame, localImageFragment, "image_fragment").addToBackStack(null)
                            .setTransition(FragmentTransaction.TRANSIT_NONE).commit();
                }
                ViewGroup.LayoutParams params = sourceContainer.getLayoutParams();
                params.height = (int) (viewStartHeight + (listHeight - viewStartHeight) * interpolatedTime);
                sourceContainer.setLayoutParams(params);
                view.setY(viewStartY - interpolatedTime * viewStartY);
                deleteButton.setAlpha(1.0f - interpolatedTime);
                viewButton.setAlpha(1.0f - interpolatedTime);
                editButton.setAlpha(1.0f - interpolatedTime);
                sourceTitle.setAlpha(1.0f - interpolatedTime);
                imageOverlay.setAlpha(overlayStartAlpha - overlayStartAlpha * (1.0f - interpolatedTime));
                sourceExpandContainer.setAlpha(1.0f - interpolatedTime);
            }

            @Override
            public boolean willChangeBounds() {
                return true;
            }
        };

        animation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                if (needsListReset) {
                    Parcelable state = sourceList.onSaveInstanceState();
                    sourceList.setAdapter(null);
                    sourceList.setAdapter(listAdapter);
                    sourceList.onRestoreInstanceState(state);
                    sourceList.setOnItemClickListener(SourceListFragment.this);
                    sourceList.setEnabled(true);
                    needsListReset = false;
                }
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

        ValueAnimator cardColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(),
                AppSettings.getDialogColor(appContext),
                getResources().getColor(AppSettings.getBackgroundColorResource()));
        cardColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                sourceContainer.setBackgroundColor((Integer) animation.getAnimatedValue());
            }

        });

        DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(1.5f);

        animation.setDuration(INFO_ANIMATION_TIME);
        cardColorAnimation.setDuration(INFO_ANIMATION_TIME);

        animation.setInterpolator(decelerateInterpolator);
        cardColorAnimation.setInterpolator(decelerateInterpolator);

        needsListReset = true;
        cardColorAnimation.start();
        view.startAnimation(animation);

    }

    /**
     * Show SourceInfoFragment with position -1 to add new source
     */
    private void showSourceAddFragment() {
        final SourceInfoFragment sourceInfoFragment = new SourceInfoFragment();
        Bundle arguments = new Bundle();
        arguments.putInt("position", -1);
        arguments.putString("type", AppSettings.WEBSITE);
        arguments.putString("title", "");
        arguments.putString("data", "");
        arguments.putString("num", "");
        arguments.putBoolean("use", true);
        arguments.putBoolean("preview", true);
        arguments.putBoolean("use_time", false);
        arguments.putString("time", "00:00 - 00:00");
        sourceInfoFragment.setArguments(arguments);

        getFragmentManager().beginTransaction().add(R.id.content_frame, sourceInfoFragment, "source_info_fragment")
                .addToBackStack(null).setTransition(FragmentTransaction.TRANSIT_NONE).commit();

    }

    /**
     * Shows sort menu for sources in a dialog
     */
    private void showSourceSortMenu() {

        DialogFactory.ListDialogListener clickListener = new DialogFactory.ListDialogListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                switch (position) {
                case 0:
                    listAdapter.sortData("use");
                    break;
                case 1:
                    listAdapter.sortData("data");
                    break;
                case 2:
                    listAdapter.sortData("title");
                    break;
                case 3:
                    listAdapter.sortData("num");
                    break;
                default:
                }
                dismissDialog();
            }
        };

        DialogFactory.showListDialog(appContext, "Sort by:", clickListener, R.array.source_sort_menu);
    }

    /**
     * Adds source to listAdapter
     *
     * @param source source
     */
    public void addEntry(Source source) {
        if (!listAdapter.addItem(source, true)) {
            sendToast("Error: Title in use.\nPlease use a different title.");
        }

    }

    /**
     * Changes entry in listAdapter
     *
     * @param position index
     * @param source source
     */
    public void setEntry(int position, Source source) {
        if (!listAdapter.setItem(position, source)) {
            sendToast("Error: Title in use.\nPlease use a different title.");
        }
    }

    /**
     * Sets up sourceList behavior
     *
     * @param savedInstanceState
     */
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    protected void setWallpaper() {

        final Intent intent = new Intent();
        if (Build.VERSION.SDK_INT >= 16) {
            intent.setAction(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
            final String packageName = LiveWallpaperService.class.getPackage().getName();
            final String className = LiveWallpaperService.class.getCanonicalName();
            intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
                    new ComponentName(packageName, className));
        } else {
            intent.setAction(WallpaperManager.ACTION_LIVE_WALLPAPER_CHOOSER);
        }

        startActivityForResult(intent, 0);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onDestroyView() {
        sourceList.setAdapter(null);
        super.onDestroyView();
    }

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

        sourceList.setOnItemClickListener(this);
        new ImageCountTask().execute();

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(FileHandler.DOWNLOAD_TERMINATED);
        intentFilter.addAction(ADD_ENTRY);
        intentFilter.addAction(SET_ENTRY);
        LocalBroadcastManager.getInstance(appContext).registerReceiver(sourceListReceiver, intentFilter);

        if (isServiceRunning(LiveWallpaperService.class.getName())) {
            setButton.setVisibility(View.GONE);
        } else {
            setButton.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void onPause() {
        ((MainActivity) getActivity()).getSupportActionBar().show();
        listAdapter.saveData();
        LocalBroadcastManager.getInstance(appContext).unregisterReceiver(sourceListReceiver);
        super.onPause();
    }

    public void resetAddButtonIcon() {

        if (isAdded()) {
            Drawable addDrawable = getResources().getDrawable(R.drawable.ic_add_white_24dp);
            addDrawable.setColorFilter(AppSettings.getColorFilterInt(appContext), PorterDuff.Mode.MULTIPLY);
            addButton.setImageDrawable(addDrawable);
        }

    }

    public void resetActionBarDownload() {

        if (isAdded()) {
            if (toolbarMenu != null) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Drawable drawable = getResources().getDrawable(R.drawable.ic_file_download_white_24dp);
                        drawable.setColorFilter(AppSettings.getColorFilterInt(appContext),
                                PorterDuff.Mode.MULTIPLY);
                        toolbarMenu.getItem(1).setIcon(drawable);
                    }
                });
            }
        }
    }

    private boolean isServiceRunning(final String className) {
        final ActivityManager manager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE);
        for (final ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (className.equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {

        View expandedView = view.findViewById(R.id.source_expand_container);
        if (expandedView.isShown()) {
            expandedView.setVisibility(View.GONE);
        } else {
            expandedView.setVisibility(View.VISIBLE);
            sourceList.smoothScrollToPositionFromTop(position, (int) (sourceList.getHeight() / 2
                    - view.getHeight() / 2 - addButtonBackground.getHeight() * 1.5), SCROLL_ANIMATION_TIME);
        }

    }

    private void startEditFragment(final View view, final int position) {
        sourceList.setOnItemClickListener(null);
        sourceList.setEnabled(false);
        listAdapter.saveData();

        Source dataItem = listAdapter.getItem(position);
        final SourceInfoFragment sourceInfoFragment = new SourceInfoFragment();
        sourceInfoFragment.setImageDrawable(((ImageView) view.findViewById(R.id.source_image)).getDrawable());
        Bundle arguments = new Bundle();
        arguments.putInt("position", position);
        arguments.putString("type", dataItem.getType());
        arguments.putString("title", dataItem.getTitle());
        arguments.putString("data", dataItem.getData());
        arguments.putInt("num", dataItem.getNum());
        arguments.putBoolean("use", dataItem.isUse());
        arguments.putBoolean("preview", dataItem.isPreview());
        String imageFileName = dataItem.getImageFile().getAbsolutePath();
        if (imageFileName != null && imageFileName.length() > 0) {
            arguments.putString("image", imageFileName);
        } else {
            arguments.putString("image", "");
        }

        arguments.putBoolean("use_time", dataItem.isUseTime());
        arguments.putString("time", dataItem.getTime());

        sourceInfoFragment.setArguments(arguments);

        final RelativeLayout sourceContainer = (RelativeLayout) view.findViewById(R.id.source_container);
        final CardView sourceCard = (CardView) view.findViewById(R.id.source_card);
        final View imageOverlay = view.findViewById(R.id.source_image_overlay);
        final EditText sourceTitle = (EditText) view.findViewById(R.id.source_title);
        final ImageView deleteButton = (ImageView) view.findViewById(R.id.source_delete_button);
        final ImageView viewButton = (ImageView) view.findViewById(R.id.source_view_image_button);
        final ImageView editButton = (ImageView) view.findViewById(R.id.source_edit_button);
        final LinearLayout sourceExpandContainer = (LinearLayout) view.findViewById(R.id.source_expand_container);

        final float cardStartShadow = sourceCard.getPaddingLeft();
        final float viewStartHeight = sourceContainer.getHeight();
        final float viewStartY = view.getY();
        final int viewStartPadding = view.getPaddingLeft();
        final float textStartX = sourceTitle.getX();
        final float textStartY = sourceTitle.getY();
        final float textTranslationY = sourceTitle.getHeight(); /*+ TypedValue.applyDimension(
                                                                TypedValue.COMPLEX_UNIT_DIP,
                                                                8,
                                                                getResources().getDisplayMetrics());*/

        Animation animation = new Animation() {

            private boolean needsFragment = true;

            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {

                if (needsFragment && interpolatedTime >= 1) {
                    needsFragment = false;
                    getFragmentManager().beginTransaction()
                            .add(R.id.content_frame, sourceInfoFragment, "source_info_fragment")
                            .addToBackStack(null).setTransition(FragmentTransaction.TRANSIT_NONE).commit();
                }
                int newPadding = Math.round(viewStartPadding * (1 - interpolatedTime));
                int newShadowPadding = (int) (cardStartShadow * (1.0f - interpolatedTime));
                sourceCard.setShadowPadding(newShadowPadding, 0, newShadowPadding, 0);
                ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).topMargin = newShadowPadding;
                ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).bottomMargin = newShadowPadding;
                ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).leftMargin = newShadowPadding;
                ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).rightMargin = newShadowPadding;
                view.setPadding(newPadding, 0, newPadding, 0);
                view.setY(viewStartY - interpolatedTime * viewStartY);
                ViewGroup.LayoutParams params = sourceContainer.getLayoutParams();
                params.height = (int) (viewStartHeight + (screenHeight - viewStartHeight) * interpolatedTime);
                sourceContainer.setLayoutParams(params);
                sourceTitle.setY(textStartY + interpolatedTime * textTranslationY);
                sourceTitle.setX(textStartX + viewStartPadding - newPadding);
                deleteButton.setAlpha(1.0f - interpolatedTime);
                viewButton.setAlpha(1.0f - interpolatedTime);
                editButton.setAlpha(1.0f - interpolatedTime);
                sourceExpandContainer.setAlpha(1.0f - interpolatedTime);
            }

            @Override
            public boolean willChangeBounds() {
                return true;
            }
        };

        animation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                if (needsListReset) {
                    Parcelable state = sourceList.onSaveInstanceState();
                    sourceList.setAdapter(null);
                    sourceList.setAdapter(listAdapter);
                    sourceList.onRestoreInstanceState(state);
                    sourceList.setOnItemClickListener(SourceListFragment.this);
                    sourceList.setEnabled(true);
                    needsListReset = false;
                }
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

        ValueAnimator cardColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(),
                AppSettings.getDialogColor(appContext),
                getResources().getColor(AppSettings.getBackgroundColorResource()));
        cardColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                sourceContainer.setBackgroundColor((Integer) animation.getAnimatedValue());
            }

        });

        ValueAnimator titleColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(),
                sourceTitle.getCurrentTextColor(), getResources().getColor(R.color.BLUE_OPAQUE));
        titleColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                sourceTitle.setTextColor((Integer) animation.getAnimatedValue());
            }

        });

        ValueAnimator titleShadowAlphaAnimation = ValueAnimator.ofObject(new ArgbEvaluator(),
                AppSettings.getColorFilterInt(appContext), getResources().getColor(android.R.color.transparent));
        titleShadowAlphaAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                sourceTitle.setShadowLayer(4, 0, 0, (Integer) animation.getAnimatedValue());
            }
        });

        ValueAnimator imageOverlayAlphaAnimation = ValueAnimator.ofFloat(imageOverlay.getAlpha(), 0f);
        imageOverlayAlphaAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                imageOverlay.setAlpha((Float) animation.getAnimatedValue());
            }
        });

        int transitionTime = INFO_ANIMATION_TIME;

        DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(1.5f);

        animation.setDuration(transitionTime);
        cardColorAnimation.setDuration(transitionTime);
        titleColorAnimation.setDuration(transitionTime);
        titleShadowAlphaAnimation.setDuration(transitionTime);

        animation.setInterpolator(decelerateInterpolator);
        cardColorAnimation.setInterpolator(decelerateInterpolator);
        titleColorAnimation.setInterpolator(decelerateInterpolator);
        titleShadowAlphaAnimation.setInterpolator(decelerateInterpolator);

        if (imageOverlay.getAlpha() > 0) {
            imageOverlayAlphaAnimation.start();
        }

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (needsListReset) {
                    Parcelable state = sourceList.onSaveInstanceState();
                    sourceList.setAdapter(null);
                    sourceList.setAdapter(listAdapter);
                    sourceList.onRestoreInstanceState(state);
                    sourceList.setOnItemClickListener(SourceListFragment.this);
                    sourceList.setEnabled(true);
                    needsListReset = false;
                }
            }
        }, (long) (transitionTime * 1.1f));

        needsListReset = true;
        view.startAnimation(animation);
        cardColorAnimation.start();
        titleColorAnimation.start();
        titleShadowAlphaAnimation.start();
    }

    private void sendToast(String toast) {

        if (AppSettings.useToast()) {
            Toast.makeText(appContext, toast, Toast.LENGTH_SHORT).show();
        }

    }

    class ImageCountTask extends AsyncTask<Void, String, String> {
        @Override
        protected String doInBackground(Void... params) {
            return listAdapter.checkSources();
        }

        @Override
        protected void onPostExecute(String sourceState) {

            Log.i("SLA", "ImageCountTask onPostExecute");

            listAdapter.updateNum();

            if (isAdded()) {

                resetAddButtonIcon();

                if (toolbarMenu != null) {
                    Drawable drawable = FileHandler.isDownloading
                            ? getResources().getDrawable(R.drawable.ic_cancel_white_24dp)
                            : getResources().getDrawable(R.drawable.ic_file_download_white_24dp);
                    drawable.setColorFilter(AppSettings.getColorFilterInt(appContext), PorterDuff.Mode.MULTIPLY);
                    toolbarMenu.getItem(1).setIcon(drawable);
                }

            }

            //            noImageText.setVisibility(sourceState.equals(SourceListAdapter.OKAY) ?
            //                    View.GONE :
            //                    View.VISIBLE);
            //
            //            switch (sourceState) {
            //
            //                case SourceListAdapter.NO_SOURCES:
            //                    noImageText.setText("Please add a source");
            //                    Drawable addDrawable = getResources().getDrawable(R.drawable.floating_button_white);
            //                    addDrawable.setColorFilter(getResources().getColor(R.color.ALERT_TEXT),
            //                            PorterDuff.Mode.MULTIPLY);
            //                    addButtonBackground.setImageDrawable(addDrawable);
            //                    break;
            //                case SourceListAdapter.NO_ACTIVE_SOURCES:
            //                    noImageText.setText("No active sources");
            //                    break;
            //                case SourceListAdapter.NEED_DOWNLOAD:
            //                    noImageText.setText("No downloaded images");
            //                    if (!FileHandler.isDownloading && toolbarMenu != null) {
            //                        Drawable downloadDrawable = getResources().getDrawable(R.drawable.ic_file_download_white_24dp).mutate();
            //                        downloadDrawable.setColorFilter(getResources().getColor(R.color.ALERT_TEXT),
            //                                PorterDuff.Mode.MULTIPLY);
            //                        toolbarMenu.getItem(1).setIcon(downloadDrawable);
            //                    }
            //                    break;
            //                case SourceListAdapter.OKAY:
            //                    break;
            //
            //            }

        }
    }

}