com.ruesga.rview.fragments.SetAccountStatusDialogFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.ruesga.rview.fragments.SetAccountStatusDialogFragment.java

Source

/*
 * Copyright (C) 2016 Jorge Ruesga
 *
 * 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 com.ruesga.rview.fragments;

import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.annotation.Keep;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;

import com.ruesga.rview.BaseActivity;
import com.ruesga.rview.R;
import com.ruesga.rview.databinding.SetAccountStatusDialogBinding;
import com.ruesga.rview.gerrit.GerritApi;
import com.ruesga.rview.gerrit.model.AccountStatusInput;
import com.ruesga.rview.misc.EmojiHelper;
import com.ruesga.rview.misc.ExceptionHelper;
import com.ruesga.rview.misc.ModelHelper;
import com.ruesga.rview.misc.SerializationManager;
import com.ruesga.rview.model.Account;
import com.ruesga.rview.preferences.Preferences;
import com.ruesga.rview.services.AccountStatusFetcherService;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import me.tatarka.rxloader2.RxLoader1;
import me.tatarka.rxloader2.RxLoaderManager;
import me.tatarka.rxloader2.RxLoaderManagerCompat;
import me.tatarka.rxloader2.RxLoaderObserver;
import me.tatarka.rxloader2.safe.SafeObservable;

public class SetAccountStatusDialogFragment extends RevealDialogFragment {

    public static final String TAG = "SetAccountStatus";

    private static final String STATE_MODEL = "state:model";
    private static final String STATE_ORIGINAL_STATUS = "state:original";

    @Keep
    public static class Model {
        public String description;
        public String status;
        public boolean isSuggestion;
    }

    @Keep
    public static class EventHandlers {
        private SetAccountStatusDialogFragment mFragment;

        public EventHandlers(SetAccountStatusDialogFragment fragment) {
            mFragment = fragment;
        }

        public void onClearPressed(View v) {
            mFragment.onClearPressed();
        }
    }

    public static SetAccountStatusDialogFragment newInstance() {
        return new SetAccountStatusDialogFragment();
    }

    private RxLoader1<String, String> mSetAccountStateLoader;

    private final RxLoaderObserver<String> mSetAccountStateObserver = new RxLoaderObserver<String>() {
        @Override
        public void onNext(String status) {
            mAccount.mAccount.status = status;
            Preferences.addOrUpdateAccount(getActivity(), mAccount);

            Intent i = new Intent(AccountStatusFetcherService.ACCOUNT_STATUS_FETCHER_ACTION);
            i.putExtra(AccountStatusFetcherService.EXTRA_ACCOUNT, mAccount.getAccountHash());
            LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(i);
            dismiss();
        }

        @Override
        public void onError(Throwable error) {
            ((BaseActivity) getActivity()).showToast(ExceptionHelper.exceptionToMessage(getActivity(), TAG, error));
            dismiss();
        }
    };

    private final TextWatcher mTextWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }

        @Override
        public void afterTextChanged(Editable s) {
            String newDescription = s.toString();
            String newStatus = EmojiHelper.getSuggestedEmojiFromDescription(getActivity(), newDescription);
            if (TextUtils.isEmpty(newDescription)) {
                newStatus = null;
            }

            mModel.status = newStatus;
            mModel.isSuggestion = EmojiHelper.isSuggestedEmojiStatus(getActivity(), newStatus);
            mBinding.setModel(mModel);
        }
    };

    private SetAccountStatusDialogBinding mBinding;
    private Model mModel = new Model();
    private EventHandlers mEventHandlers;
    private Account mAccount;

    private String mOriginalStatus;

    public SetAccountStatusDialogFragment() {
        mEventHandlers = new EventHandlers(this);
    }

    @Override
    public void buildDialog(AlertDialog.Builder builder, Bundle savedInstanceState) {
        LayoutInflater inflater = LayoutInflater.from(builder.getContext());
        mBinding = DataBindingUtil.inflate(inflater, R.layout.set_account_status_dialog, null, true);
        mBinding.status.addTextChangedListener(mTextWatcher);
        mBinding.suggestions.listenTo(this::updateModel);
        mBinding.setModel(mModel);
        mBinding.setHandlers(mEventHandlers);

        builder.setTitle(R.string.account_status_dialog_title).setView(mBinding.getRoot())
                .setNegativeButton(R.string.action_cancel, null).setPositiveButton(R.string.action_set, null);
        startLoadersWithValidContext(savedInstanceState);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putString(STATE_MODEL, SerializationManager.getInstance().toJson(mModel));
        outState.putString(STATE_ORIGINAL_STATUS, mOriginalStatus);
        super.onSaveInstanceState(outState);
    }

    @Override
    public void setupDialog(Dialog dialog, int style) {
        super.setupDialog(dialog, style);

        dialog.setOnShowListener(dialog1 -> {
            Button button = ((AlertDialog) dialog1).getButton(AlertDialog.BUTTON_POSITIVE);
            button.setOnClickListener(v -> performAccountStateChanged());
        });
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        startLoadersWithValidContext(savedInstanceState);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mBinding.status.removeTextChangedListener(mTextWatcher);
        mBinding.unbind();
    }

    @SuppressWarnings("ConstantConditions")
    private void startLoadersWithValidContext(Bundle savedInstanceState) {
        if (getActivity() == null && mBinding != null) {
            return;
        }

        if (mAccount == null) {
            mAccount = Preferences.getAccount(getActivity());
            if (savedInstanceState != null) {
                mOriginalStatus = savedInstanceState.getString(STATE_ORIGINAL_STATUS);
                mModel = SerializationManager.getInstance().fromJson(savedInstanceState.getString(STATE_MODEL),
                        Model.class);
                mBinding.setModel(mModel);
            } else {
                mOriginalStatus = EmojiHelper.getSuggestedDescriptionFromEmoji(getActivity(),
                        mAccount.mAccount.status);
                updateModel(mAccount.mAccount.status);
            }

            // Fetch or join current loader
            RxLoaderManager loaderManager = RxLoaderManagerCompat.get(this);
            mSetAccountStateLoader = loaderManager.create("set", this::setAccountState, mSetAccountStateObserver);
        }
    }

    private void performAccountStateChanged() {
        if (TextUtils.equals(mModel.description, mOriginalStatus)) {
            dismiss();
            return;
        }

        mSetAccountStateLoader.clear();
        mSetAccountStateLoader.restart(mModel.description);
    }

    private void updateModel(String status) {
        mModel.description = EmojiHelper.getSuggestedDescriptionFromEmoji(getActivity(), status);
        mModel.status = status;
        mModel.isSuggestion = EmojiHelper.isSuggestedEmojiStatus(getActivity(), status);
        mBinding.setModel(mModel);
    }

    @SuppressWarnings("ConstantConditions")
    private Observable<String> setAccountState(final String status) {
        final Context ctx = getActivity();
        final GerritApi api = ModelHelper.getGerritApi(ctx);
        return SafeObservable.fromNullCallable(() -> {
            AccountStatusInput input = new AccountStatusInput();
            input.status = status;
            if (!TextUtils.isEmpty(status)) {
                input.status = EmojiHelper.getSuggestedEmojiFromDescription(getActivity(), status);
            }
            api.setAccountStatus(GerritApi.SELF_ACCOUNT, input).blockingFirst();
            return input.status;
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
    }

    private void onClearPressed() {
        mModel.description = null;
        mModel.status = null;
        mModel.isSuggestion = false;
        mBinding.setModel(mModel);
    }
}