@@ -0,0 +1,41 @@
package at.renehollander.chat.fragments;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

import at.renehollander.chat.Application;
import at.renehollander.chat.R;
import at.renehollander.chat.adapter.ChatRoomListListAdapter;
import at.renehollander.chat.model.ChatRoom;

public class ChatRoomListFragment extends CustomFragment {

private ListView chatRooms;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_chatroomlist, container, false);
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);

getActivity().setTitle(getResources().getString(R.string.chatrooms_fragment_title));
chatRooms = (ListView) findViewById(R.id.listView);

chatRooms.setAdapter(new ChatRoomListListAdapter(getActivity(), ((Application) getActivity().getApplication()).getChatrooms()));
chatRooms.setOnItemClickListener((adapterView, view2, position, id) -> {
ChatRoomFragment crf = new ChatRoomFragment();
Bundle bundle = new Bundle();
bundle.putCharSequence("room", ((ChatRoom) chatRooms.getAdapter().getItem(position)).getName());
crf.setArguments(bundle);
replace(R.id.fragment_container, crf);
});
}

}
@@ -0,0 +1,20 @@
package at.renehollander.chat.fragments;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.View;

public abstract class CustomFragment extends Fragment {

public View findViewById(int id) {
return getActivity().findViewById(id);
}

public void replace(int id, Fragment newFragment) {
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(id, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}

}
@@ -1,15 +1,16 @@
package at.renehollander.chat.activities;
package at.renehollander.chat.fragments;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
@@ -22,7 +23,7 @@
/**
* A login screen that offers login via email/password.
*/
public class LoginActivity extends AppCompatActivity {
public class LoginFragment extends CustomFragment {

// UI references.
private AutoCompleteTextView mEmailView;
@@ -31,9 +32,22 @@ public class LoginActivity extends AppCompatActivity {
private View mLoginFormView;

@Override
protected void onCreate(Bundle savedInstanceState) {
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
setHasOptionsMenu(true);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_login, container, false);
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);

getActivity().setTitle(getResources().getString(R.string.login_fragment_title));

// Set up the login form.
mEmailView = (AutoCompleteTextView) findViewById(R.id.email);

@@ -47,10 +61,10 @@ protected void onCreate(Bundle savedInstanceState) {
});

Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
mEmailSignInButton.setOnClickListener(view -> attemptLogin());
mEmailSignInButton.setOnClickListener(btn -> attemptLogin());

Button mGoToRegisterButton = (Button) findViewById(R.id.go_to_register_button);
mGoToRegisterButton.setOnClickListener(view -> startActivity(new Intent(this, RegisterActivity.class)));
mGoToRegisterButton.setOnClickListener(btn -> replace(R.id.fragment_container, new RegisterFragment()));

mLoginFormView = findViewById(R.id.login_form);
mProgressView = findViewById(R.id.login_progress);
@@ -101,18 +115,18 @@ private void attemptLogin() {
showProgress(true);

// try to log in and display an error or information dialog
((Application) getApplication()).login(email, password, (err, res) -> {
((Application) getActivity().getApplication()).login(email, password, (err, res) -> {
showProgress(false);
if (err == null) {
if (res != null) {
Util.messageDialogRunLater(this, "Success", "You successfully logged in!");
Util.messageDialogRunLater(getActivity(), "Success", "You successfully logged in!");
Log.d("login", "Successfull login. Recieved token " + res);
} else {
Util.messageDialogRunLater(this, "Error", "Wrong email and or password!");
Util.messageDialogRunLater(getActivity(), "Error", "Wrong email and or password!");
Log.e("login", "Error logging in");
}
} else {
Util.messageDialogRunLater(this, "Error", "An error occured while logging in: " + err.getMessage());
Util.messageDialogRunLater(getActivity(), "Error", "An error occured while logging in: " + err.getMessage());
Log.e("login", "Error logging in", err);
}
});
@@ -1,15 +1,16 @@
package at.renehollander.chat.activities;
package at.renehollander.chat.fragments;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
@@ -22,7 +23,7 @@
/**
* A register screen that offers register via email/password.
*/
public class RegisterActivity extends AppCompatActivity {
public class RegisterFragment extends CustomFragment {

// UI references.
private AutoCompleteTextView mEmailView;
@@ -32,10 +33,17 @@ public class RegisterActivity extends AppCompatActivity {
private View mRegisterFormView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_register, container, false);
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Set up the register form.

getActivity().setTitle(R.string.register_fragment_title);

mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
mUsernameView = (AutoCompleteTextView) findViewById(R.id.username);

@@ -49,10 +57,10 @@ protected void onCreate(Bundle savedInstanceState) {
});

Button mEmailSignInButton = (Button) findViewById(R.id.email_register_button);
mEmailSignInButton.setOnClickListener(view -> attemptRegister());
mEmailSignInButton.setOnClickListener(btn -> attemptRegister());

Button mGoToLoginButton = (Button) findViewById(R.id.go_to_login_button);
mGoToLoginButton.setOnClickListener(view -> startActivity(new Intent(this, LoginActivity.class)));
mGoToLoginButton.setOnClickListener(btn -> replace(R.id.fragment_container, new LoginFragment()));

mRegisterFormView = findViewById(R.id.register_form);
mProgressView = findViewById(R.id.register_progress);
@@ -111,19 +119,19 @@ private void attemptRegister() {
showProgress(true);

// try to log in and display an error or information dialog
((Application) getApplication()).register(email, username, password, (err, res) -> {
((Application) getActivity().getApplication()).register(email, username, password, (err, res) -> {
showProgress(false);
if (err == null) {
if (res) {
Util.messageDialogRunLater(this, "Success", "You successfully registered!");
Util.messageDialogRunLater(getActivity(), "Success", "You successfully registered!");
Log.d("register", "Successfull register");
startActivity(new Intent(this, LoginActivity.class));
replace(R.id.fragment_container, new LoginFragment());
} else {
Util.messageDialogRunLater(this, "Error", "Email already in use!");
Util.messageDialogRunLater(getActivity(), "Error", "Email already in use!");
Log.e("register", "Email already in use!");
}
} else {
Util.messageDialogRunLater(this, "Error", "An error occured while registering: " + err.getMessage());
Util.messageDialogRunLater(getActivity(), "Error", "An error occured while registering: " + err.getMessage());
Log.e("register", "Error registering", err);
}
});
@@ -0,0 +1,32 @@
package at.renehollander.chat.model;

import android.databinding.ObservableArrayList;

import java.util.List;

public class ChatRoom {

private String name;
private ObservableArrayList<Message> messages;

public ChatRoom(String name, ObservableArrayList<Message> messages) {
this.name = name;
this.messages = messages;
}

public String getName() {
return name;
}

public ObservableArrayList<Message> getMessages() {
return messages;
}

@Override
public String toString() {
return "ChatRoom{" +
"name='" + name + '\'' +
", messages=" + messages +
'}';
}
}
@@ -0,0 +1,55 @@
package at.renehollander.chat.model;

import java.util.Date;

public class Message {

public static enum Flag {
SENT, RECIEVED;
}

private Flag flag;
private String room;
private String user;
private Date date;
private String text;

public Message(Flag flag, String room, String user, Date date, String text) {
this.flag = flag;
this.room = room;
this.user = user;
this.date = date;
this.text = text;
}

public Flag getFlag() {
return flag;
}

public String getRoom() {
return room;
}

public String getUser() {
return user;
}

public Date getDate() {
return date;
}

public String getText() {
return text;
}

@Override
public String toString() {
return "Message{" +
"flag=" + flag +
", room='" + room + '\'' +
", user='" + user + '\'' +
", date=" + date +
", text='" + text + '\'' +
'}';
}
}
@@ -0,0 +1,40 @@
package at.renehollander.chat.util;

import android.databinding.ObservableArrayList;
import android.widget.BaseAdapter;

import at.renehollander.chat.model.ChatRoom;

public class ObservableListChangeListener extends ObservableArrayList.OnListChangedCallback<ObservableArrayList<ChatRoom>> {

private final BaseAdapter adapter;

public ObservableListChangeListener(BaseAdapter adapter) {
this.adapter = adapter;
}

@Override
public void onChanged(ObservableArrayList<ChatRoom> chatRooms) {
adapter.notifyDataSetChanged();
}

@Override
public void onItemRangeChanged(ObservableArrayList<ChatRoom> chatRooms, int i, int i1) {
adapter.notifyDataSetChanged();
}

@Override
public void onItemRangeInserted(ObservableArrayList<ChatRoom> chatRooms, int i, int i1) {
adapter.notifyDataSetChanged();
}

@Override
public void onItemRangeMoved(ObservableArrayList<ChatRoom> chatRooms, int i, int i1, int i2) {
adapter.notifyDataSetChanged();
}

@Override
public void onItemRangeRemoved(ObservableArrayList<ChatRoom> chatRooms, int i, int i1) {
adapter.notifyDataSetChanged();
}
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/message_recieved_color" />

<!--<padding-->
<!--android:left="1dp"-->
<!--android:right="1dp"-->
<!--android:top="1dp" />-->

<corners android:radius="@dimen/rounded_corner_radius" />
</shape>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/message_sent_color" />

<!--<padding-->
<!--android:left="1dp"-->
<!--android:right="1dp"-->
<!--android:top="1dp" />-->

<corners android:radius="@dimen/rounded_corner_radius" />
</shape>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="@color/icon_color"
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z" />
</vector>
@@ -0,0 +1,4 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
@@ -0,0 +1,22 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="8dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="8dp">

<TextView
android:id="@+id/header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22sp"/>

<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />


</LinearLayout>
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="48dip"
android:divider="@null"
android:background="@color/messages_background"
android:showDividers="none"
android:stackFromBottom="true"
android:transcriptMode="alwaysScroll" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dip"
android:layout_alignParentBottom="true"
android:layout_margin="0dp"
android:background="#FFFFFF"
android:orientation="horizontal"
android:padding="0dp">

<EditText
android:id="@+id/newmsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_weight="10"
android:hint="Send a message" />

<ImageButton
android:id="@+id/newmsgsend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="#FFFFFF"
android:src="@drawable/ic_send_black"

/>
</LinearLayout>

</RelativeLayout>
@@ -0,0 +1,12 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">

<ListView
android:id="@+id/listView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

</LinearLayout>
@@ -1,14 +1,12 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".RegisterActivity">
android:paddingTop="@dimen/activity_vertical_margin">

<!-- Login progress -->
<ProgressBar
@@ -7,8 +7,7 @@
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="at.renehollander.chat.activities.RegisterActivity">
android:paddingTop="@dimen/activity_vertical_margin">

<!-- Register progress -->
<ProgressBar
@@ -0,0 +1,18 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="left"
android:orientation="vertical"
android:padding="4dp">

<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_recieved_rounded_corner"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:paddingLeft="8dp"
android:paddingRight="8dp" />

</LinearLayout>
@@ -0,0 +1,18 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="right"
android:orientation="vertical"
android:padding="4dp">

<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_sent_rounded_corner"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:paddingLeft="8dp"
android:paddingRight="8dp" />

</LinearLayout>
@@ -3,4 +3,8 @@
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="message_sent_color">#d4d4d4</color>
<color name="message_recieved_color">#31c1ff</color>
<color name="messages_background">#e9e9e9</color>
<color name="icon_color">#FF757575</color>
</resources>
@@ -2,4 +2,5 @@
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="rounded_corner_radius">10dp</dimen>
</resources>
@@ -12,4 +12,7 @@
<string name="action_go_to_register">Not yet registered?</string>
<string name="action_register">Register</string>
<string name="action_go_to_login">Already registered? Login</string>
<string name="login_fragment_title">Login</string>
<string name="register_fragment_title">Register</string>
<string name="chatrooms_fragment_title">Chatrooms</string>
</resources>
@@ -8,4 +8,13 @@
<item name="colorAccent">@color/colorAccent</item>
</style>

<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>

<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

</resources>
@@ -1,5 +1,6 @@
package at.renehollander.mobileapp.configuration;

import at.renehollander.mobileapp.endpoint.TestEndpoint;
import at.renehollander.mobileapp.endpoint.UserLoginEndpoint;
import at.renehollander.mobileapp.endpoint.UserRegisterEndpoint;
import org.glassfish.jersey.jackson.JacksonFeature;
@@ -12,6 +13,7 @@ public class JerseyConfiguration extends ResourceConfig {
public JerseyConfiguration() {
this.register(UserRegisterEndpoint.class);
this.register(UserLoginEndpoint.class);
this.register(TestEndpoint.class);
this.register(JacksonFeature.class);
}
}
@@ -0,0 +1,28 @@
package at.renehollander.mobileapp.endpoint;

import at.renehollander.mobileapp.handler.ChatHandler;
import at.renehollander.mobileapp.util.Maps;
import org.springframework.beans.factory.annotation.Autowired;

import javax.inject.Named;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import java.util.Date;

@Named
@Path("/test")
public class TestEndpoint {

@Autowired
private ChatHandler chatHandler;

@GET
public Response get() {
System.out.println("here");
chatHandler.onChat(null, Maps.of("room", "Room 1", "user", "Rene8888", "date", new Date(), "text", "hellooooooo"));
chatHandler.onChat(null, Maps.of("room", "Room 2", "user", "Rene8888", "date", new Date(), "text", "hellooooooo"));
return Response.status(200).build();
}

}
@@ -2,6 +2,7 @@

import at.renehollander.mobileapp.annotation.Event;
import at.renehollander.mobileapp.annotation.SocketIO;
import at.renehollander.mobileapp.util.Maps;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
@@ -10,24 +11,64 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

@SocketIO(port = 8081)
public class ChatHandler implements ConnectListener, DisconnectListener {

private static final Logger LOG = LoggerFactory.getLogger(ChatHandler.class);

private SocketIOServer server;

private Map<String, Map<String, Object>> chatrooms = new HashMap<>();

private void init() {
{
List<Map<String, Object>> messageList = new ArrayList<>();
messageList.add(Maps.of("room", "Room 1", "user", "Rene8888", "date", new Date(), "text", "Hello World!"));
messageList.add(Maps.of("room", "Room 1", "user", "Paul1032", "date", new Date(), "text", "Hi!"));
messageList.add(Maps.of("room", "Room 1", "user", "Rene8888", "date", new Date(), "text", "fock off m8"));
messageList.add(Maps.of("room", "Room 1", "user", "Rene8888", "date", new Date(), "text", "you gucci fam?"));
messageList.add(Maps.of("room", "Room 1", "user", "Paul1032", "date", new Date(), "text", "sure you faggot"));
chatrooms.put("Room 1", Maps.of("name", "Room 1", "messages", messageList));
}
{
List<Map<String, Object>> messageList = new ArrayList<>();
messageList.add(Maps.of("room", "Room 2", "user", "Paul1032", "date", new Date(), "text", "itz workening!"));
messageList.add(Maps.of("room", "Room 2", "user", "Rene8888", "date", new Date(), "text", "yiss!"));
messageList.add(Maps.of("room", "Room 2", "user", "Rene8888", "date", new Date(), "text", "but its shit m9"));
messageList.add(Maps.of("room", "Room 2", "user", "Paul1032", "date", new Date(), "text", "it is\nmultiline"));
messageList.add(Maps.of("room", "Room 2", "user", "Rene8888", "date", new Date(), "text", "thats nice"));
chatrooms.put("Room 2", Maps.of("name", "Room 2", "messages", messageList));
}
}

@Override
public void onConnect(SocketIOClient client) {
LOG.info("Client " + client + " connected!");
}

@Event("chat")
public void onChat(SocketIOClient client, String data, AckRequest ackSender) {
LOG.info("Client " + client + " sent " + data);
@Event("message")
public void onChat(SocketIOClient client, Map<String, Object> data) {
String roomid = (String) data.get("room");
List<Object> messages;
if (!chatrooms.containsKey(roomid)) {
messages = new ArrayList<>();
Map<String, Object> roomObj = new HashMap<>();
roomObj.put("name", roomid);
roomObj.put("messages", messages);
chatrooms.put("room", roomObj);
} else {
messages = (List<Object>) chatrooms.get(roomid).get("messages");
}
messages.add(data);
server.getBroadcastOperations().sendEvent("message", data);
LOG.info(String.valueOf(data));
}

@Event("get_rooms")
public void onGetRooms(SocketIOClient client, Object ignore, AckRequest ackSender) {
ackSender.sendAckData(chatrooms);
}

@Override