de.kuschku.quasseldroid_ng.ui.chat.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for de.kuschku.quasseldroid_ng.ui.chat.MainActivity.java

Source

/*
 * QuasselDroid - Quassel client for Android
 * Copyright (C) 2016 Janne Koschinski
 * Copyright (C) 2016 Ken Brge Viktil
 * Copyright (C) 2016 Magnus Fjell
 * Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.kuschku.quasseldroid_ng.ui.chat;

import android.app.SearchManager;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.AppCompatEditText;
import android.support.v7.widget.AppCompatSpinner;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.Toast;

import com.afollestad.materialdialogs.MaterialDialog;
import com.jakewharton.rxbinding.support.v7.widget.RxSearchView;

import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import butterknife.Bind;
import butterknife.ButterKnife;
import de.kuschku.libquassel.client.Client;
import de.kuschku.libquassel.events.BufferChangeEvent;
import de.kuschku.libquassel.events.ConnectionChangeEvent;
import de.kuschku.libquassel.events.CoreSetupRequiredEvent;
import de.kuschku.libquassel.events.GeneralErrorEvent;
import de.kuschku.libquassel.events.LoginRequireEvent;
import de.kuschku.libquassel.events.UnknownCertificateEvent;
import de.kuschku.libquassel.functions.types.HandshakeFunction;
import de.kuschku.libquassel.localtypes.buffers.Buffer;
import de.kuschku.libquassel.localtypes.buffers.ChannelBuffer;
import de.kuschku.libquassel.localtypes.buffers.QueryBuffer;
import de.kuschku.libquassel.message.Message;
import de.kuschku.libquassel.objects.types.CoreSetupData;
import de.kuschku.libquassel.objects.types.SetupData;
import de.kuschku.libquassel.primitives.types.QVariant;
import de.kuschku.libquassel.syncables.types.interfaces.QBacklogManager;
import de.kuschku.libquassel.syncables.types.interfaces.QIrcChannel;
import de.kuschku.libquassel.syncables.types.interfaces.QIrcUser;
import de.kuschku.quasseldroid_ng.R;
import de.kuschku.quasseldroid_ng.service.ClientBackgroundThread;
import de.kuschku.quasseldroid_ng.ui.chat.dialogs.CoreInfoDialogBuilder;
import de.kuschku.quasseldroid_ng.ui.chat.drawer.ActionModeHandler;
import de.kuschku.quasseldroid_ng.ui.chat.drawer.BufferViewConfigAdapter;
import de.kuschku.quasseldroid_ng.ui.chat.fragment.ChatFragment;
import de.kuschku.quasseldroid_ng.ui.chat.fragment.LoadingFragment;
import de.kuschku.quasseldroid_ng.ui.chat.nicklist.NickListAdapter;
import de.kuschku.quasseldroid_ng.ui.chat.util.Status;
import de.kuschku.quasseldroid_ng.ui.coresettings.aliases.AliasListActivity;
import de.kuschku.quasseldroid_ng.ui.coresettings.chatlist.ChatListListActivity;
import de.kuschku.quasseldroid_ng.ui.coresettings.identity.IdentityListActivity;
import de.kuschku.quasseldroid_ng.ui.coresettings.ignore.IgnoreListActivity;
import de.kuschku.quasseldroid_ng.ui.coresettings.network.NetworkListActivity;
import de.kuschku.quasseldroid_ng.ui.settings.SettingsActivity;
import de.kuschku.quasseldroid_ng.ui.setup.CoreSetupActivity;
import de.kuschku.util.CompatibilityUtils;
import de.kuschku.util.accounts.Account;
import de.kuschku.util.accounts.AccountManager;
import de.kuschku.util.annotationbind.AutoBinder;
import de.kuschku.util.certificates.CertificateUtils;
import de.kuschku.util.certificates.SQLiteCertificateManager;
import de.kuschku.util.observables.callbacks.ElementCallback;
import de.kuschku.util.servicebound.BoundActivity;
import de.kuschku.util.ui.DividerItemDecoration;
import de.kuschku.util.ui.MenuTint;
import rx.android.schedulers.AndroidSchedulers;

import static de.kuschku.util.AndroidAssert.assertNotNull;

public class MainActivity extends BoundActivity {
    public static final int REQUEST_CODE_CORESETUP = 1;
    /**
     * This object encapsulates the current status of the activity  opened bufferview, for example
     */
    private final Status status = new Status();

    /**
     * Host layout for content fragment, for example showing a loader or the chat
     */
    @Bind(R.id.chatList)
    RecyclerView chatList;

    @Bind(R.id.nickList)
    RecyclerView nickList;

    @Bind(R.id.chatListSpinner)
    AppCompatSpinner chatListSpinner;

    @Bind(R.id.chatListToolbar)
    Toolbar chatListToolbar;

    @Nullable
    @Bind(R.id.drawer_layout)
    DrawerLayout drawerLayout;

    /**
     * Main ActionBar
     */
    @Bind(R.id.toolbar)
    Toolbar toolbar;

    private AccountManager manager;

    private ToolbarWrapper toolbarWrapper;

    private BufferViewConfigAdapter chatListAdapter;
    private Fragment currentFragment;

    private Bundle coreSetupResult;
    private boolean coreSetupCancelled;
    private CoreInfoDialogBuilder coreInfoDialogBuilder;
    private NickListAdapter nickListAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        toolbarWrapper = new ToolbarWrapper(toolbar);
        toolbarWrapper.setOnClickListener(v -> {
            if (context.client() != null) {
                int id = context.client().backlogManager().open();
                Buffer buffer = context.client().bufferManager().buffer(id);
                if (buffer instanceof ChannelBuffer) {
                    Intent intent = new Intent(this, ChannelDetailActivity.class);
                    intent.putExtra("buffer", id);
                    startActivity(intent);
                }
            }
        });
        setSupportActionBar(toolbar);
        chatListAdapter = BufferViewConfigAdapter.of(context);
        chatListAdapter.setBufferClickListener(buffer -> {
            if (context.client() != null) {
                context.client().backlogManager().open(buffer.getInfo().id);
                if (drawerLayout != null)
                    drawerLayout.closeDrawer(GravityCompat.START);
            }
        });
        chatListAdapter.setActionModeHandler(new ActionModeHandler(this, R.id.cab_stub));
        chatListAdapter.setRecyclerView(chatList);
        chatList.setItemAnimator(new DefaultItemAnimator());
        chatList.setLayoutManager(new LinearLayoutManager(this));
        chatList.setAdapter(chatListAdapter);

        coreInfoDialogBuilder = new CoreInfoDialogBuilder(this);

        chatListToolbar.inflateMenu(R.menu.chatlist);
        MenuTint.colorIcons(chatListToolbar.getMenu(),
                AutoBinder.obtainColor(R.attr.colorFill, chatListToolbar.getContext().getTheme()));
        chatListToolbar.setOnMenuItemClickListener(item -> {
            switch (item.getItemId()) {
            case R.id.action_show_all: {
                item.setChecked(chatListAdapter.toggleShowAll());
            }
                break;
            case R.id.action_manage_chat_lists: {
                startActivity(new Intent(this, ChatListListActivity.class));
            }
            }
            return false;
        });

        DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawerLayout != null) {
            ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar,
                    R.string.material_drawer_open, R.string.material_drawer_close);
            toggle.syncState();
            drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
        }

        replaceFragment(new LoadingFragment());

        if (savedInstanceState != null)
            status.onRestoreInstanceState(savedInstanceState);

        manager = new AccountManager(this);

        nickListAdapter = new NickListAdapter(context);
        nickList.setAdapter(nickListAdapter);
        nickList.setLayoutManager(new LinearLayoutManager(this));
        nickList.setItemAnimator(new DefaultItemAnimator());
        nickList.addItemDecoration(new DividerItemDecoration(this));

        setStatusBar();
    }

    private void setStatusBar() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Window window = getWindow();
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(getResources().getColor(android.R.color.transparent));

            nickList.setPadding(0, CompatibilityUtils.getStatusBarHeight(this), 0, 0);

            View viewById = findViewById(R.id.statusBarBackground);
            ViewGroup.LayoutParams layoutParams = viewById.getLayoutParams();
            layoutParams.height = CompatibilityUtils.getStatusBarHeight(this);
            viewById.setLayoutParams(layoutParams);
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (context.client() != null) {
            context.client().backlogManager().setOpen(-1);
            context.client().backlogStorage().markBufferUnused(context.client().backlogManager().open());
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (context.client() != null)
            context.client().backlogManager().open(status.bufferId);
    }

    private void replaceFragment(Fragment fragment) {
        try {
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            this.currentFragment = fragment;
            transaction.replace(R.id.content_host, fragment);
            transaction.commit();
        } catch (IllegalStateException ignored) {
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        assertNotNull(outState);

        super.onSaveInstanceState(outState);
        status.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        assertNotNull(savedInstanceState);

        super.onRestoreInstanceState(savedInstanceState);
        status.onRestoreInstanceState(savedInstanceState);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.chat, menu);
        final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
        SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        RxSearchView.queryTextChanges(searchView).debounce(400, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread()).subscribe(charSequence -> {
                    if (context.client() != null
                            && context.client().connectionStatus() == ConnectionChangeEvent.Status.CONNECTED)
                        context.client().backlogStorage().getFilter(context.client().backlogManager().open())
                                .setQuery(charSequence);
                });
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    protected void onDestroy() {
        chatListAdapter.selectConfig(-1);
        toolbarWrapper.setOnClickListener(null);
        chatListAdapter.setBufferClickListener(null);
        chatListSpinner.setOnItemSelectedListener(null);
        chatListToolbar.setOnMenuItemClickListener(null);
        super.onDestroy();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_hide_events:
            displayFilterDialog();
            return true;
        case R.id.action_reauth:
            reauth();
            return true;
        case R.id.action_settings:
            startActivity(new Intent(this, SettingsActivity.class));
            return true;
        case R.id.action_identities:
            startActivity(new Intent(this, IdentityListActivity.class));
            return true;
        case R.id.action_networks:
            startActivity(new Intent(this, NetworkListActivity.class));
            return true;
        case R.id.action_ignorelist:
            startActivity(new Intent(this, IgnoreListActivity.class));
            return true;
        case R.id.action_aliaslist:
            startActivity(new Intent(this, AliasListActivity.class));
            return true;
        case R.id.action_coreinfo:
            if (context.client() != null && context.client().coreInfo() != null)
                coreInfoDialogBuilder.build(manager.account(context.settings().preferenceLastAccount.get()),
                        context.client().coreInfo(), context.client().certificateChain()).show();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    private void reauth() {
        context.settings().preferenceLastAccount.set("");
        stopConnection();
        finish();
    }

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void onEventMainThread(ConnectionChangeEvent event) {
        onConnectionChange(event.status);
    }

    public void onConnectionChange(ConnectionChangeEvent.Status status) {
        if (status == ConnectionChangeEvent.Status.CONNECTED) {
            replaceFragment(new ChatFragment());
            connected();
        } else if (status == ConnectionChangeEvent.Status.DISCONNECTED) {
            Toast.makeText(getApplication(), context.themeUtil().translations.statusDisconnected, Toast.LENGTH_LONG)
                    .show();
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventMainThread(GeneralErrorEvent event) {
        Toast.makeText(getApplication(), event.exception.getClass().getSimpleName() + ": " + event.debugInfo,
                Toast.LENGTH_LONG).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void onEventMainThread(BufferChangeEvent event) {
        Client client = context.client();
        if (client != null) {
            QBacklogManager backlogManager = client.backlogManager();
            int id = backlogManager.open();
            status.bufferId = id;
            updateBuffer(id);
            chatListAdapter.setOpen(id);
        }
    }

    private void updateBuffer(int id) {
        nickListAdapter.setChannel(null);
        updateTitleAndSubtitle(id);
    }

    private void updateTitleAndSubtitle(int id) {
        Client client = context.client();
        if (client != null) {
            Buffer buffer = client.bufferManager().buffer(id);
            if (buffer != null) {
                toolbarWrapper.setTitle(buffer.getName());
                if (buffer instanceof QueryBuffer) {
                    QIrcUser user = ((QueryBuffer) buffer).getUser();
                    if (user == null) {
                        toolbarWrapper.setSubtitle(null);
                    } else {
                        toolbarWrapper.setSubtitle(user.realName());
                    }
                } else if (buffer instanceof ChannelBuffer) {
                    QIrcChannel channel = ((ChannelBuffer) buffer).getChannel();
                    nickListAdapter.setChannel(channel);
                    if (channel == null) {
                        toolbarWrapper.setSubtitle(null);
                    } else {
                        toolbarWrapper.setSubtitle(context.deserializer().formatString(channel.topic()));
                    }
                } else {
                    toolbarWrapper.setSubtitle(null);
                }
            }
        }
    }

    /*
    private void updateBufferViewConfigs() {
    assertNotNull(context.client().bufferViewManager());
    List<QBufferViewConfig> bufferViews = context.client().bufferViewManager().bufferViewConfigs();
    accountHeader.clear();
    for (QBufferViewConfig viewConfig : bufferViews) {
        if (viewConfig != null) {
            if (status.bufferViewConfigId == -1) {
                status.bufferViewConfigId = viewConfig.bufferViewId();
            }
            accountHeader.addProfiles(
                    new ProfileDrawerItem()
                            .withName(viewConfig.bufferViewName())
                            .withIdentifier(viewConfig.bufferViewId())
            );
        }
    }
    accountHeader.setActiveProfile(status.bufferViewConfigId, true);
    }
    */

    @Override
    public void onBackPressed() {
        if ((currentFragment instanceof ChatFragment && ((ChatFragment) currentFragment).onBackPressed())) {
            return;
        }
        super.onBackPressed();
    }

    protected void reconnect() {
        binder.stopBackgroundThread();
        connectToServer(manager.account(context.settings().preferenceLastAccount.get()));
    }

    @Override
    protected void onConnectToThread(@Nullable ClientBackgroundThread thread) {
        super.onConnectToThread(thread);
        if (thread == null) {
            Account account = manager.account(context.settings().preferenceLastAccount.get());
            if (account != null) {
                connectToServer(account);
            } else {
                setResult(RESULT_CANCELED);
                finish();
            }
        } else {
            if (context.client() != null
                    && context.client().connectionStatus() == ConnectionChangeEvent.Status.CONNECTED) {
                connected();
            }
        }
    }

    private void connected() {
        if (drawerLayout != null)
            drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);

        context.client().bufferManager().bufferIds().addCallback(new ElementCallback<Integer>() {
            @Override
            public void notifyItemInserted(Integer element) {

            }

            @Override
            public void notifyItemRemoved(Integer element) {

            }

            @Override
            public void notifyItemChanged(Integer element) {
                if (element == context.client().backlogManager().open())
                    updateTitleAndSubtitle(element);
            }
        });
        context.client().backlogManager().open(status.bufferId);
        if (context.client().bufferViewManager() != null) {
            chatListSpinner.setAdapter(new BufferViewConfigSpinnerAdapter(context.client().bufferViewManager()));
            chatListSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                    chatListAdapter.selectConfig((int) id);
                    status.bufferViewConfigId = (int) id;
                }

                @Override
                public void onNothingSelected(AdapterView<?> parent) {
                    chatListAdapter.selectConfig(-1);
                }
            });
        }
        updateBuffer(context.client().backlogManager().open());
        chatListSpinner.setSelection(chatListAdapter.indexOf(status.bufferViewConfigId));
    }

    // FIXME: Fix this ugly hack
    public void displayFilterDialog() {
        if (context.client() != null) {
            List<Integer> filterSettings = Arrays.asList(Message.Type.Join.value, Message.Type.Part.value,
                    Message.Type.Quit.value, Message.Type.Nick.value, Message.Type.Mode.value,
                    Message.Type.Topic.value);
            int[] filterSettingsInts = new int[filterSettings.size()];
            for (int i = 0; i < filterSettingsInts.length; i++) {
                filterSettingsInts[i] = filterSettings.get(i);
            }

            int bufferId = context.client().backlogManager().open();
            int oldFilters = context.client().bufferSyncer().getFilters(bufferId);
            List<Integer> oldFiltersList = new ArrayList<>();
            for (int type : filterSettings) {
                if ((type & oldFilters) != 0)
                    oldFiltersList.add(filterSettings.indexOf(type));
            }
            Integer[] selectedIndices = oldFiltersList.toArray(new Integer[oldFiltersList.size()]);
            new MaterialDialog.Builder(this)
                    .items("Joins", "Parts", "Quits", "Nick Changes", "Mode Changes", "Topic Changes")
                    .itemsIds(filterSettingsInts)
                    .itemsCallbackMultiChoice(selectedIndices, (dialog, which, text) -> false)
                    .positiveText("Select").negativeText("Cancel").onPositive((dialog, which) -> {
                        int filters = 0x00000000;
                        if (dialog.getSelectedIndices() != null)
                            for (int i : dialog.getSelectedIndices()) {
                                int settingsid = filterSettings.get(i);
                                filters |= settingsid;
                                if (settingsid == Message.Type.Quit.value)
                                    filters |= Message.Type.NetsplitQuit.value;
                                else if (settingsid == Message.Type.Join.value)
                                    filters |= Message.Type.NetsplitJoin.value;
                            }
                        context.client().bufferSyncer().setFilters(bufferId, filters);
                    }).negativeColor(context.themeUtil().res.colorForeground)
                    .backgroundColor(context.themeUtil().res.colorBackgroundCard)
                    .contentColor(context.themeUtil().res.colorForeground).build().show();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
        case REQUEST_CODE_CORESETUP: {
            if (resultCode == RESULT_OK) {
                coreSetupResult = data.getExtras();
            } else {
                coreSetupCancelled = true;
            }
        }
            break;
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void onEventMainThread(@NonNull UnknownCertificateEvent event) {
        new MaterialDialog.Builder(this)
                .content(context.themeUtil().translations.warningCertificate + "\n"
                        + CertificateUtils.certificateToFingerprint(event.certificate, ""))
                .title("Unknown Certificate").onPositive((dialog, which) -> {
                    new SQLiteCertificateManager(this).addCertificate(event.certificate, event.address);
                    reconnect();
                }).negativeColor(context.themeUtil().res.colorForeground).positiveText("Yes").negativeText("No")
                .backgroundColor(context.themeUtil().res.colorBackgroundCard)
                .contentColor(context.themeUtil().res.colorForeground).build().show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void onEventMainThread(CoreSetupRequiredEvent event) {
        if (coreSetupCancelled) {
            finish();
        } else if (coreSetupResult != null) {
            context.provider().event.removeStickyEvent(CoreSetupRequiredEvent.class);

            Account account = manager.account(context.settings().preferenceLastAccount.get());
            Bundle config = coreSetupResult.getBundle("config");
            Map<String, QVariant> configData = new HashMap<>();
            for (String key : config.keySet()) {
                configData.put(key, new QVariant<>(config.get(key)));
            }
            context.provider().dispatch(new HandshakeFunction(new CoreSetupData(new SetupData(account.user,
                    account.pass, coreSetupResult.getString("selectedBackend"), configData))));
        } else {
            Intent intent = new Intent(getApplicationContext(), CoreSetupActivity.class);
            intent.putExtra("storageBackends", context.client().core().getStorageBackendsAsBundle());
            startActivityForResult(intent, REQUEST_CODE_CORESETUP);
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void onEventMainThread(LoginRequireEvent event) {
        if (event.failedLast) {
            new MaterialDialog.Builder(this).title(R.string.titleLogin).customView(R.layout.dialog_login, false)
                    .onPositive((dialog1, which) -> {
                        View parent = dialog1.getCustomView();
                        assertNotNull(parent);
                        AppCompatEditText usernameField = (AppCompatEditText) parent.findViewById(R.id.username);
                        AppCompatEditText passwordField = (AppCompatEditText) parent.findViewById(R.id.password);
                        String username = usernameField.getText().toString();
                        String password = passwordField.getText().toString();

                        Account account = manager.account(context.settings().preferenceLastAccount.get());
                        manager.update(account.withLoginData(username, password));
                    }).cancelListener(dialog1 -> finish()).negativeColor(context.themeUtil().res.colorForeground)
                    .positiveText(R.string.actionLogin).negativeText(R.string.actionCancel)
                    .backgroundColor(context.themeUtil().res.colorBackgroundCard)
                    .contentColor(context.themeUtil().res.colorForeground).build().show();
        }
    }
}