Skip to content

Instantly share code, notes, and snippets.

@arnaud33200
Created September 26, 2019 16:55
Show Gist options
  • Save arnaud33200/4b863e98d60b80145cda7fd350967ba3 to your computer and use it in GitHub Desktop.
Save arnaud33200/4b863e98d60b80145cda7fd350967ba3 to your computer and use it in GitHub Desktop.
package com.skrumble.ally.fragments.chat;
import android.os.Handler;
import com.skrumble.ally.helpers.DataHelper;
import com.skrumble.ally.libraries.state_machine.FSMEvent;
import com.skrumble.ally.libraries.state_machine.Guard;
import com.skrumble.ally.libraries.state_machine.OnStateEntryListener;
import com.skrumble.ally.libraries.state_machine.StateImplEvent;
import com.skrumble.ally.models.chat.Chat;
import org.statefulj.fsm.RetryException;
import org.statefulj.fsm.TooBusyException;
import org.statefulj.fsm.model.Action;
import org.statefulj.fsm.model.State;
import org.statefulj.persistence.memory.MemoryPersisterImpl;
import java.util.LinkedList;
import java.util.List;
/**
* Created by akashpatel on 2018-02-13.
*/
public class ChatMessagesStateMachine {
// EVENTS
public final static String STATE_MACHINE_MESSAGES__EVENT_NEW_INCOMING_MESSAGE = "STATE_MACHINE_MESSAGES__EVENT_NEW_INCOMING_MESSAGE";
public final static String STATE_MACHINE_MESSAGES__EVENT_NEW_OUTGOING_MESSAGE = "STATE_MACHINE_MESSAGES__EVENT_NEW_OUTGOING_MESSAGE";
public final static String STATE_MACHINE_MESSAGES__EVENT_SCROLLED_TO_TOP = "STATE_MACHINE_MESSAGES__EVENT_SCROLLED_TO_TOP";
public final static String STATE_MACHINE_MESSAGES__EVENT_SCROLLED_TO_BOTTOM = "STATE_MACHINE_MESSAGES__EVENT_SCROLLED_TO_BOTTOM";
public final static String STATE_MACHINE_MESSAGES__EVENT_FETCH_NO_LOCAL_START = "STATE_MACHINE_MESSAGES__EVENT_FETCH_NO_LOCAL_START";
public final static String STATE_MACHINE_MESSAGES__EVENT_FETCH_HAS_LOCAL_START = "STATE_MACHINE_MESSAGES__EVENT_FETCH_HAS_LOCAL_START";
public final static String STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_MESSAGE = "STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_MESSAGE";
public final static String STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_NEXT = "STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_NEXT";
public final static String STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_PREVIOUS = "STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_PREVIOUS";
public final static String STATE_MACHINE_MESSAGES__EVENT_SCROLL_MESSAGE_NOT_LOADED = "STATE_MACHINE_MESSAGES__EVENT_SCROLL_MESSAGE_NOT_LOADED";
private FSMEvent<ChatState> fsm;
private ChatState chatState;
private ChatMessagesFragment chatMessagesFragment;
public ChatMessagesStateMachine(final ChatMessagesFragment chatMessagesFragment, Chat mChat) {
this.chatMessagesFragment = chatMessagesFragment;
// STATES
/* 0 */
StateImplEvent<ChatState> stateInitial = new StateImplEvent<ChatState>("StateInitial");
stateInitial.addOnStateChangedListener(new OnStateEntryListener() {
@Override
public void onEntry() {
chatMessagesFragment.mRecyclerView.setAlpha(0);
chatMessagesFragment.showCenterMessagesLoader(false);
}
});
/* 1 */
StateImplEvent<ChatState> stateNoLocalLoading = new StateImplEvent<ChatState>("StateLoading");
stateNoLocalLoading.addOnStateChangedListener(new OnStateEntryListener() {
@Override
public void onEntry() {
chatMessagesFragment.showCenterMessagesLoader(true);
chatMessagesFragment.mRecyclerView.setAlpha(0);
}
});
StateImplEvent<ChatState> stateLocalLoading = new StateImplEvent<ChatState>("StateLocalLoading");
stateLocalLoading.addOnStateChangedListener(new OnStateEntryListener() {
@Override
public void onEntry() {
chatMessagesFragment.showCenterMessagesLoader(false);
chatMessagesFragment.mRecyclerView.setAlpha(1.0f);
// chatMessagesFragment.scrollToBottom(false, true);
// chatMessagesFragment.fadeRecyclerViewIn();
chatMessagesFragment.showNextPageLoader(true);
}
});
/* 2 */
StateImplEvent<ChatState> stateMessagesList = new StateImplEvent<ChatState>("StateMessagesList");
stateMessagesList.addOnStateChangedListener(new OnStateEntryListener() {
@Override
public void onEntry() {
chatMessagesFragment.fadeRecyclerViewIn();
new Handler().postDelayed(() -> {
chatMessagesFragment.showCenterMessagesLoader(false);
chatMessagesFragment.showNextPageLoader(false);
},500);
}
});
Guard<ChatState> guardShouldLoadNextMessages = () -> {
boolean hasNext = chatMessagesFragment.hasNextPage() && chatMessagesFragment.chatHasMessage();
return hasNext;
};
Guard<ChatState> guardShouldLoadPreviousMessages = () -> {
boolean hasPrevious = chatMessagesFragment.hasPreviousPage() && chatMessagesFragment.chatHasMessage();
return hasPrevious;
};
Guard<ChatState> guardChatHasNoMessage = () -> !chatMessagesFragment.chatHasMessage();
ActionFetchPreviousMessage<ChatState> actionStartFetchPrevious = new ActionFetchPreviousMessage(true);
ActionFetchPreviousMessage<ChatState> actionStopFetchPrevious = new ActionFetchPreviousMessage(false);
ActionFetchNextMessage<ChatState> actionStartFetchNext = new ActionFetchNextMessage(true);
ActionFetchNextMessage<ChatState> actionStopFetchNext = new ActionFetchNextMessage(false);
// INIT
stateInitial.addTransition(STATE_MACHINE_MESSAGES__EVENT_FETCH_NO_LOCAL_START, stateNoLocalLoading);
stateInitial.addTransition(STATE_MACHINE_MESSAGES__EVENT_FETCH_HAS_LOCAL_START, stateLocalLoading);
stateInitial.addTransition(STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_MESSAGE, stateMessagesList);
// SERVER LOADING
stateNoLocalLoading.addTransition(STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_MESSAGE, stateMessagesList);
stateNoLocalLoading.addTransition(STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_NEXT, stateMessagesList);
stateNoLocalLoading.addTransition(STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_PREVIOUS, stateMessagesList);
// LOCAL LOADING
stateLocalLoading.addTransition(STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_MESSAGE, stateMessagesList);
stateLocalLoading.addTransition(STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_NEXT, stateMessagesList);
stateLocalLoading.addTransition(STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_PREVIOUS, stateMessagesList);
// scroll up
stateLocalLoading.addTransition(STATE_MACHINE_MESSAGES__EVENT_SCROLLED_TO_TOP, stateLocalLoading, actionStartFetchPrevious, guardShouldLoadPreviousMessages);
stateLocalLoading.addTransition(STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_PREVIOUS, stateLocalLoading, actionStopFetchPrevious);
// MESSAGE LIST
stateMessagesList.addTransition(STATE_MACHINE_MESSAGES__EVENT_FETCH_HAS_LOCAL_START, stateLocalLoading, guardChatHasNoMessage);
stateMessagesList.addTransition(STATE_MACHINE_MESSAGES__EVENT_SCROLL_MESSAGE_NOT_LOADED, stateInitial);
// scroll bottom
stateMessagesList.addTransition(STATE_MACHINE_MESSAGES__EVENT_SCROLLED_TO_BOTTOM, stateMessagesList, actionStartFetchNext, guardShouldLoadNextMessages);
stateMessagesList.addTransition(STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_NEXT, stateMessagesList, actionStopFetchNext);
// scroll up
stateMessagesList.addTransition(STATE_MACHINE_MESSAGES__EVENT_SCROLLED_TO_TOP, stateMessagesList, actionStartFetchPrevious, guardShouldLoadPreviousMessages);
stateMessagesList.addTransition(STATE_MACHINE_MESSAGES__EVENT_FINISH_LOAD_PREVIOUS, stateMessagesList, actionStopFetchPrevious);
List<State<ChatState>> states = new LinkedList<>();
states.add(stateInitial);
states.add(stateNoLocalLoading);
states.add(stateLocalLoading);
states.add(stateMessagesList);
StateImplEvent<ChatState> initState = stateInitial;
if (mChat != null && DataHelper.isStringEmpty(mChat.getId())) {
initState = stateInitial;
}
MemoryPersisterImpl<ChatState> persister = new MemoryPersisterImpl<>(states, initState);
this.chatState = new ChatState();
this.fsm = new FSMEvent<>("ChatMessagesStateMachine", persister, this.chatState);
}
public void sendEventToFSM(String event) {
try {
this.fsm.onEvent(this.chatState, event);
} catch (TooBusyException e) {
}
}
public String getCurrentStateName() {
if (this.fsm == null) return "StateInitial";
StateImplEvent<ChatState> state = (StateImplEvent<ChatState>) this.fsm.getCurrentState(chatState);
return state.getName();
}
public class ChatState {
@org.statefulj.persistence.annotations.State
String state;
public String getState() {
return state;
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// region STATE ACTION
private class ActionFetchPreviousMessage<T> implements Action<T> {
private final boolean start;
private ActionFetchPreviousMessage(boolean start) { this.start = start; }
public void execute(T stateful, String event, Object... args) throws RetryException {
if (start) {
chatMessagesFragment.showPreviousPageLoader(true);
chatMessagesFragment.loadPreviousPage();
}
else {
chatMessagesFragment.showPreviousPageLoader(false);
}
}
}
private class ActionFetchNextMessage<T> implements Action<T> {
private final boolean start;
private ActionFetchNextMessage(boolean start) { this.start = start; }
@Override
public void execute(T stateful, String event, Object... args) throws RetryException {
if (start) {
chatMessagesFragment.showNextPageLoader(true);
chatMessagesFragment.loadNextPage();
}
else {
chatMessagesFragment.showNextPageLoader(false);
}
}
}
// endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment