<commit_before>package im.actor.sdk.controllers.conversation.messages;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.ChatLinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;

import java.io.IOException;

import fr.castorflex.android.circularprogressbar.CircularProgressBar;
import im.actor.core.entity.Message;
import im.actor.core.entity.Peer;
import im.actor.core.viewmodel.ConversationVM;
import im.actor.sdk.ActorSDK;
import im.actor.sdk.R;
import im.actor.sdk.controllers.conversation.messages.content.AudioHolder;
import im.actor.sdk.controllers.conversation.messages.content.AbsMessageViewHolder;
import im.actor.sdk.controllers.conversation.messages.content.preprocessor.ChatListProcessor;
import im.actor.sdk.controllers.DisplayListFragment;
import im.actor.sdk.controllers.settings.BaseActorSettingsFragment;
import im.actor.sdk.util.Screen;
import im.actor.runtime.android.view.BindedListAdapter;
import im.actor.runtime.generic.mvvm.BindedDisplayList;

import static im.actor.sdk.util.ActorSDKMessenger.messenger;

public abstract class MessagesFragment extends DisplayListFragment<Message, AbsMessageViewHolder> {

    private final boolean isPrimaryMode;

    protected Peer peer;
    protected ConversationVM conversationVM;

    protected ChatLinearLayoutManager layoutManager;
    protected MessagesAdapter messagesAdapter;
    protected CircularProgressBar progressView;
    private long firstUnread = -1;
    private boolean isUnreadLoaded = false;


    //
    // Constructor and getters
    //
    public MessagesFragment(boolean isPrimaryMode) {
        this.isPrimaryMode = isPrimaryMode;
        setUnbindOnPause(true);
    }

    public Peer getPeer() {
        return peer;
    }

    public ConversationVM getConversationVM() {
        return conversationVM;
    }

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

        //
        // Loading arguments
        //
        try {
            peer = Peer.fromBytes(getArguments().getByteArray("EXTRA_PEER"));
            conversationVM = messenger().getConversationVM(peer);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //
        // Display List
        //
        BindedDisplayList<Message> displayList = onCreateDisplayList();
        if (isPrimaryMode) {
            displayList.setLinearLayoutCallback(b -> {
                if (layoutManager != null) {
                    layoutManager.setStackFromEnd(b);
                }
            });
        }


        //
        // Main View
        //
        View res = inflate(inflater, container, R.layout.fragment_messages, displayList);
        progressView = (CircularProgressBar) res.findViewById(R.id.loadingProgress);
        progressView.setIndeterminate(true);
        progressView.setVisibility(View.INVISIBLE);

        //
        // Loading background
        //
        Drawable background;
        int[] backgrounds = ActorSDK.sharedActor().style.getDefaultBackgrouds();
        String selectedWallpaper = messenger().getSelectedWallpaper();
        if (selectedWallpaper != null) {
            background = getResources().getDrawable(backgrounds[0]);
            if (selectedWallpaper.startsWith("local:")) {
                for (int i = 1; i < backgrounds.length; i++) {
                    if (getResources().getResourceEntryName(backgrounds[i]).equals(selectedWallpaper.replaceAll("local:", ""))) {
                        background = getResources().getDrawable(backgrounds[i]);
                    }
                }
            } else {
                background = Drawable.createFromPath(BaseActorSettingsFragment.getWallpaperFile());
            }
        } else {
            background = getResources().getDrawable(backgrounds[0]);
        }
        ((ImageView) res.findViewById(R.id.chatBackgroundView)).setImageDrawable(background);


        //
        // List Padding
        //
        View footer = new View(getActivity());
        footer.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, Screen.dp(8)));
        addHeaderView(footer); // Add Footer as Header because of reverse layout

        View header = new View(getActivity());
        header.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, Screen.dp(64)));
        addFooterView(header); // Add Header as Footer because of reverse layout


        //
        // Init unread message index if available
        //
        recalculateUnreadMessageIfNeeded();

        return res;
    }

    //
    // Configure RecyclerView
    //
    @Override
    protected BindedListAdapter<Message, AbsMessageViewHolder> onCreateAdapter(BindedDisplayList<Message> displayList, Activity activity) {
        messagesAdapter = new MessagesAdapter(displayList, this, activity);
        if (firstUnread != -1 && messagesAdapter.getFirstUnread() == -1) {
            messagesAdapter.setFirstUnread(firstUnread);
        }
        return messagesAdapter;
    }

    @Override
    protected void configureRecyclerView(RecyclerView recyclerView) {
        layoutManager = new ChatLinearLayoutManager(getActivity(), ChatLinearLayoutManager.VERTICAL, true);
        layoutManager.setStackFromEnd(false);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(layoutManager);
    }

    protected BindedDisplayList<Message> onCreateDisplayList() {
        BindedDisplayList<Message> displayList = messenger().getMessageDisplayList(peer);
        if (displayList.getListProcessor() == null) {
            displayList.setListProcessor(new ChatListProcessor(peer, this.getContext()));
        }
        return displayList;
    }


    //
    // Unread Messages
    //
    private void recalculateUnreadMessageIfNeeded() {

        // Scroll to unread only in primary mode
        if (!isPrimaryMode) {
            return;
        }

        BindedDisplayList<Message> list = getDisplayList();
        firstUnread = conversationVM.getLastMessageDate();

        // Do not scroll to unread twice
        if (isUnreadLoaded) {
            return;
        }

        // Ignore if list is not loaded
        if (list.getSize() == 0) {
            return;
        }

        // If List is not empty: mark as loaded
        isUnreadLoaded = true;<commit_msg>fix(android): prevent double scroll to unread<commit_after>package im.actor.sdk.controllers.conversation.messages;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.ChatLinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;

import java.io.IOException;

import fr.castorflex.android.circularprogressbar.CircularProgressBar;
import im.actor.core.entity.Message;
import im.actor.core.entity.Peer;
import im.actor.core.viewmodel.ConversationVM;
import im.actor.runtime.Log;
import im.actor.sdk.ActorSDK;
import im.actor.sdk.R;
import im.actor.sdk.controllers.conversation.messages.content.AudioHolder;
import im.actor.sdk.controllers.conversation.messages.content.AbsMessageViewHolder;
import im.actor.sdk.controllers.conversation.messages.content.preprocessor.ChatListProcessor;
import im.actor.sdk.controllers.DisplayListFragment;
import im.actor.sdk.controllers.settings.BaseActorSettingsFragment;
import im.actor.sdk.util.Screen;
import im.actor.runtime.android.view.BindedListAdapter;
import im.actor.runtime.generic.mvvm.BindedDisplayList;

import static im.actor.sdk.util.ActorSDKMessenger.messenger;

public abstract class MessagesFragment extends DisplayListFragment<Message, AbsMessageViewHolder> {

    private final boolean isPrimaryMode;

    protected Peer peer;
    protected ConversationVM conversationVM;

    protected ChatLinearLayoutManager layoutManager;
    protected MessagesAdapter messagesAdapter;
    protected CircularProgressBar progressView;
    private long firstUnread = -1;
    private boolean isUnreadLoaded = false;


    //
    // Constructor and getters
    //
    public MessagesFragment(boolean isPrimaryMode) {
        this.isPrimaryMode = isPrimaryMode;
        setUnbindOnPause(true);
    }

    public Peer getPeer() {
        return peer;
    }

    public ConversationVM getConversationVM() {
        return conversationVM;
    }

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

        //
        // Loading arguments
        //
        try {
            peer = Peer.fromBytes(getArguments().getByteArray("EXTRA_PEER"));
            conversationVM = messenger().getConversationVM(peer);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //
        // Display List
        //
        BindedDisplayList<Message> displayList = onCreateDisplayList();
        if (isPrimaryMode) {
            displayList.setLinearLayoutCallback(b -> {
                if (layoutManager != null) {
                    layoutManager.setStackFromEnd(b);
                }
            });
        }


        //
        // Main View
        //
        View res = inflate(inflater, container, R.layout.fragment_messages, displayList);
        progressView = (CircularProgressBar) res.findViewById(R.id.loadingProgress);
        progressView.setIndeterminate(true);
        progressView.setVisibility(View.INVISIBLE);

        //
        // Loading background
        //
        Drawable background;
        int[] backgrounds = ActorSDK.sharedActor().style.getDefaultBackgrouds();
        String selectedWallpaper = messenger().getSelectedWallpaper();
        if (selectedWallpaper != null) {
            background = getResources().getDrawable(backgrounds[0]);
            if (selectedWallpaper.startsWith("local:")) {
                for (int i = 1; i < backgrounds.length; i++) {
                    if (getResources().getResourceEntryName(backgrounds[i]).equals(selectedWallpaper.replaceAll("local:", ""))) {
                        background = getResources().getDrawable(backgrounds[i]);
                    }
                }
            } else {
                background = Drawable.createFromPath(BaseActorSettingsFragment.getWallpaperFile());
            }
        } else {
            background = getResources().getDrawable(backgrounds[0]);
        }
        ((ImageView) res.findViewById(R.id.chatBackgroundView)).setImageDrawable(background);


        //
        // List Padding
        //
        View footer = new View(getActivity());
        footer.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, Screen.dp(8)));
        addHeaderView(footer); // Add Footer as Header because of reverse layout

        View header = new View(getActivity());
        header.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, Screen.dp(64)));
        addFooterView(header); // Add Header as Footer because of reverse layout


        //
        // Init unread message index if available
        //
        recalculateUnreadMessageIfNeeded();

        return res;
    }

    //
    // Configure RecyclerView
    //
    @Override
    protected BindedListAdapter<Message, AbsMessageViewHolder> onCreateAdapter(BindedDisplayList<Message> displayList, Activity activity) {
        messagesAdapter = new MessagesAdapter(displayList, this, activity);
        if (firstUnread != -1 && messagesAdapter.getFirstUnread() == -1) {
            messagesAdapter.setFirstUnread(firstUnread);
        }
        return messagesAdapter;
    }

    @Override
    protected void configureRecyclerView(RecyclerView recyclerView) {
        layoutManager = new ChatLinearLayoutManager(getActivity(), ChatLinearLayoutManager.VERTICAL, true);
        layoutManager.setStackFromEnd(false);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(layoutManager);
    }

    protected BindedDisplayList<Message> onCreateDisplayList() {
        BindedDisplayList<Message> displayList = messenger().getMessageDisplayList(peer);
        if (displayList.getListProcessor() == null) {
            displayList.setListProcessor(new ChatListProcessor(peer, this.getContext()));
        }
        return displayList;
    }


    //
    // Unread Messages
    //
    private void recalculateUnreadMessageIfNeeded() {

        Log.d("READ_DEBUG", "trying to scroll to unread");

        // Scroll to unread only in primary mode
        if (!isPrimaryMode) {
            return;
        }

        BindedDisplayList<Message> list = getDisplayList();
        if (firstUnread == -1) {
            firstUnread = conversationVM.getLastMessageDate();
        }

        // Do not scroll to unread twice
        if (isUnreadLoaded) {
            return;
        }

        // Ignore if list is not loaded
        if (list.getSize() == 0) {
            return;
        }

        // If List is not empty: mark as loaded
        isUnreadLoaded = true;
{'fraction_non_alphanumeric': 0.09625865370452202, 'fraction_numerical': 0.0018412137280895567, 'mean_word_length': 2.722313596491228, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4561554', 'n_tokens_mistral': 3653, 'n_tokens_neox': 3484, 'n_words': 691}