This commit is contained in:
Paul Schaub 2019-06-03 01:16:49 +02:00
parent 35d7a7c473
commit 308ca9c467
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
36 changed files with 823 additions and 113 deletions

View File

@ -77,10 +77,6 @@ dependencies {
transitive = true transitive = true
} }
/*
architecture components for database and lifecycle management
*/
// ViewModel and LiveData // ViewModel and LiveData
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion" implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycleVersion" annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycleVersion"
@ -89,6 +85,10 @@ dependencies {
implementation "com.google.dagger:dagger:$daggerVersion" implementation "com.google.dagger:dagger:$daggerVersion"
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion" annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
// ButterKnife for View Binding
implementation "com.jakewharton:butterknife:$butterKnifeVersion"
annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnifeVersion"
// support libraries // support libraries
implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.google.android.material:material:1.0.0' implementation 'com.google.android.material:material:1.0.0'
@ -96,6 +96,7 @@ dependencies {
implementation 'androidx.vectordrawable:vectordrawable:1.0.1' implementation 'androidx.vectordrawable:vectordrawable:1.0.1'
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:runner:1.1.1'

View File

@ -39,6 +39,7 @@
<activity <activity
android:name=".ui.login.LoginActivity" android:name=".ui.login.LoginActivity"
android:label="@string/title_activity_login" /> android:label="@string/title_activity_login" />
<activity android:name=".ui.login.AccountsActivity" />
<service android:name=".service.XmppStartedService" /> <service android:name=".service.XmppStartedService" />
</application> </application>

View File

@ -10,6 +10,8 @@ import org.mercury_im.messenger.ui.chat.ChatActivity;
import org.mercury_im.messenger.ui.chat.ChatInputFragment; import org.mercury_im.messenger.ui.chat.ChatInputFragment;
import org.mercury_im.messenger.ui.chat.ChatInputViewModel; import org.mercury_im.messenger.ui.chat.ChatInputViewModel;
import org.mercury_im.messenger.ui.chat.ChatViewModel; import org.mercury_im.messenger.ui.chat.ChatViewModel;
import org.mercury_im.messenger.ui.login.AccountsActivity;
import org.mercury_im.messenger.ui.login.AccountsViewModel;
import org.mercury_im.messenger.ui.login.LoginActivity; import org.mercury_im.messenger.ui.login.LoginActivity;
import org.mercury_im.messenger.ui.login.LoginViewModel; import org.mercury_im.messenger.ui.login.LoginViewModel;
import org.mercury_im.messenger.ui.roster.RosterViewModel; import org.mercury_im.messenger.ui.roster.RosterViewModel;
@ -27,6 +29,7 @@ public interface AppComponent {
void inject(MercuryImApplication mercuryImApplication); void inject(MercuryImApplication mercuryImApplication);
// Views // Views
void inject(MainActivity mainActivity); void inject(MainActivity mainActivity);
@ -35,8 +38,11 @@ public interface AppComponent {
void inject(ChatActivity chatActivity); void inject(ChatActivity chatActivity);
void inject(AccountsActivity accountsActivity);
void inject(ChatInputFragment chatInputFragment); void inject(ChatInputFragment chatInputFragment);
// ViewModels // ViewModels
void inject(RosterViewModel rosterViewModel); void inject(RosterViewModel rosterViewModel);
@ -47,6 +53,9 @@ public interface AppComponent {
void inject(LoginViewModel loginViewModel); void inject(LoginViewModel loginViewModel);
void inject(AccountsViewModel accountsViewModel);
// Services // Services
void inject(XmppStartedService service); void inject(XmppStartedService service);

View File

@ -19,6 +19,7 @@ import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
import org.mercury_im.messenger.persistence.repository.AccountRepository; import org.mercury_im.messenger.persistence.repository.AccountRepository;
import org.mercury_im.messenger.persistence.repository.ContactRepository; import org.mercury_im.messenger.persistence.repository.ContactRepository;
import org.mercury_im.messenger.ui.chat.ChatActivity; import org.mercury_im.messenger.ui.chat.ChatActivity;
import org.mercury_im.messenger.ui.login.AccountsActivity;
import org.mercury_im.messenger.ui.login.LoginActivity; import org.mercury_im.messenger.ui.login.LoginActivity;
import org.mercury_im.messenger.ui.settings.SettingsActivity; import org.mercury_im.messenger.ui.settings.SettingsActivity;
@ -79,6 +80,10 @@ public class MainActivity extends AppCompatActivity {
case R.id.action_chat: case R.id.action_chat:
startActivity(new Intent(getApplicationContext(), ChatActivity.class)); startActivity(new Intent(getApplicationContext(), ChatActivity.class));
return true; return true;
case R.id.action_accounts:
startActivity(new Intent(getApplicationContext(), AccountsActivity.class));
return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);

View File

@ -2,6 +2,8 @@ package org.mercury_im.messenger.ui.chat;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -24,6 +26,8 @@ public class ChatInputFragment extends Fragment implements View.OnClickListener
private ChatInputViewModel mViewModel; private ChatInputViewModel mViewModel;
private OnChatInputActionListener actionListener;
public static ChatInputFragment newInstance() { public static ChatInputFragment newInstance() {
return new ChatInputFragment(); return new ChatInputFragment();
} }
@ -42,7 +46,7 @@ public class ChatInputFragment extends Fragment implements View.OnClickListener
return view; return view;
} }
@Override @Override2
public void onActivityCreated(@Nullable Bundle savedInstanceState) { public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(ChatInputViewModel.class); mViewModel = ViewModelProviders.of(this).get(ChatInputViewModel.class);
@ -58,19 +62,50 @@ public class ChatInputFragment extends Fragment implements View.OnClickListener
}); });
} }
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnChatInputActionListener) {
this.actionListener = (OnChatInputActionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnListFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
this.actionListener = null;
}
@Override @Override
public void onClick(View view) { public void onClick(View view) {
switch (view.getId()) { switch (view.getId()) {
// Add media // Add media
case R.id.chat_field__button_attachment: case R.id.chat_field__button_attachment:
if (actionListener != null) {
actionListener.onButtonAddAttachementClicked();
}
Toast.makeText(getContext(), R.string.not_yet_implemented, Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), R.string.not_yet_implemented, Toast.LENGTH_SHORT).show();
break; break;
// Send message // Send message
case R.id.chat_field__button_send: case R.id.chat_field__button_send:
if (actionListener != null) {
actionListener.onComposingBodySend(textInput.getText().toString());
}
textInput.setText(null); textInput.setText(null);
Toast.makeText(getContext(), "Send message clicked", Toast.LENGTH_SHORT).show();
break; break;
} }
} }
public interface OnChatInputActionListener {
void onButtonAddAttachementClicked();
void onComposingBodyChanged(String body);
void onComposingBodySend(String body);
}
} }

View File

@ -0,0 +1,47 @@
package org.mercury_im.messenger.ui.login;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Toast;
import androidx.fragment.app.FragmentActivity;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.persistence.model.AccountModel;
import org.mercury_im.messenger.persistence.repository.AccountRepository;
import javax.inject.Inject;
public class AccountsActivity extends FragmentActivity implements AccountsFragment.OnListFragmentInteractionListener {
@Inject
AccountRepository accountRepository;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_accounts);
MercuryImApplication.getApplication().getAppComponent().inject(this);
}
@Override
public void onListFragmentInteraction(AccountModel item) {
View dialogView = LayoutInflater.from(this).inflate(R.layout.dialog_account_details, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setView(dialogView)
.setTitle(item.getJid())
.setPositiveButton("Save", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
builder.create().show();
}
}

View File

@ -0,0 +1,104 @@
package org.mercury_im.messenger.ui.login;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.persistence.model.AccountModel;
/**
* A fragment representing a list of Items.
* <p/>
* Activities containing this fragment MUST implement the {@link OnListFragmentInteractionListener}
* interface.
*/
public class AccountsFragment extends Fragment {
private OnListFragmentInteractionListener mListener;
AccountsViewModel viewModel;
private AccountsRecyclerViewAdapter adapter;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public AccountsFragment() {
}
// TODO: Customize parameter initialization
@SuppressWarnings("unused")
public static AccountsFragment newInstance() {
AccountsFragment fragment = new AccountsFragment();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(MercuryImApplication.TAG, "AccountsFragment.onCreateView");
View view = inflater.inflate(R.layout.fragment_account_list, container, false);
viewModel = ViewModelProviders.of(this).get(AccountsViewModel.class);
// Set the adapter
if (view instanceof RecyclerView) {
Context context = view.getContext();
RecyclerView recyclerView = (RecyclerView) view;
recyclerView.setLayoutManager(new LinearLayoutManager(context));
this.adapter = new AccountsRecyclerViewAdapter(viewModel.getAccounts().getValue(), mListener);
viewModel.getAccounts().observe(this, roomAccountModels -> adapter.setValues(roomAccountModels));
recyclerView.setAdapter(adapter);
}
return view;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnListFragmentInteractionListener) {
mListener = (OnListFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnListFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnListFragmentInteractionListener {
// TODO: Update argument type and name
void onListFragmentInteraction(AccountModel item);
}
}

View File

@ -0,0 +1,87 @@
package org.mercury_im.messenger.ui.login;
import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Switch;
import android.widget.TextView;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.persistence.model.AccountModel;
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
import org.mercury_im.messenger.ui.login.AccountsFragment.OnListFragmentInteractionListener;
import java.util.ArrayList;
import java.util.List;
import de.hdodenhof.circleimageview.CircleImageView;
public class AccountsRecyclerViewAdapter extends RecyclerView.Adapter<AccountsRecyclerViewAdapter.ViewHolder> {
private final List<RoomAccountModel> mValues;
private final OnListFragmentInteractionListener mListener;
public AccountsRecyclerViewAdapter(List<RoomAccountModel> items, OnListFragmentInteractionListener listener) {
mValues = items != null ? items : new ArrayList<>();
mListener = listener;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_view_item_account, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
AccountModel account = mValues.get(position);
holder.jid.setText(account.getJid());
holder.enabled.setChecked(account.getEnabled());
holder.accountModel = account;
holder.mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (null != mListener) {
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mListener.onListFragmentInteraction(holder.accountModel);
}
}
});
}
public void setValues(List<RoomAccountModel> values) {
this.mValues.clear();
if (values != null) {
mValues.addAll(values);
}
notifyDataSetChanged();
}
@Override
public int getItemCount() {
Log.d(MercuryImApplication.TAG, "Accounts Item Count: " + mValues.size());
return mValues.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public AccountModel accountModel;
public final View mView;
public final CircleImageView avatar;
public final TextView jid;
public final Switch enabled;
public ViewHolder(View view) {
super(view);
mView = view;
avatar = view.findViewById(R.id.avatar_account);
jid = view.findViewById(R.id.text_account_jid);
enabled = view.findViewById(R.id.switch_account_enabled);
}
}
}

View File

@ -0,0 +1,31 @@
package org.mercury_im.messenger.ui.login;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.persistence.repository.AccountRepository;
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
import java.util.List;
import javax.inject.Inject;
public class AccountsViewModel extends ViewModel {
@Inject
AccountRepository repository;
private LiveData<List<RoomAccountModel>> accounts;
@Inject
public AccountsViewModel() {
super();
MercuryImApplication.getApplication().getAppComponent().inject(this);
accounts = repository.getAllAccountsLive();
}
public LiveData<List<RoomAccountModel>> getAccounts() {
return accounts;
}
}

View File

@ -0,0 +1,21 @@
package org.mercury_im.messenger.ui.login;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
public class AddAccountDialog extends AlertDialog {
protected AddAccountDialog(@NonNull Context context, int themeResId) {
super(context, themeResId);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}

View File

@ -5,6 +5,8 @@ import androidx.lifecycle.ViewModelProviders;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
@ -25,6 +27,9 @@ import org.mercury_im.messenger.service.XmppStartedService;
import javax.inject.Inject; import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
/** /**
* A login screen that offers login via email/password. * A login screen that offers login via email/password.
*/ */
@ -34,10 +39,11 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito
AccountRepository accountRepository; AccountRepository accountRepository;
// UI references. // UI references.
@BindView(R.id.jid)
private AutoCompleteTextView mJidView; private AutoCompleteTextView mJidView;
@BindView(R.id.password)
private EditText mPasswordView; private EditText mPasswordView;
private View mProgressView;
private View mLoginFormView;
private LoginViewModel viewModel; private LoginViewModel viewModel;
@ -49,8 +55,7 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito
MercuryImApplication.getApplication().getAppComponent().inject(this); MercuryImApplication.getApplication().getAppComponent().inject(this);
// Set up the login form. // Set up the login form.
mJidView = findViewById(R.id.jid); ButterKnife.bind(this);
mPasswordView = findViewById(R.id.password);
viewModel = ViewModelProviders.of(this).get(LoginViewModel.class); viewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
displayCredentials(viewModel.getAccount()); displayCredentials(viewModel.getAccount());
@ -65,9 +70,6 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito
loginDetailsEntered(); loginDetailsEntered();
} }
}); });
mLoginFormView = findViewById(R.id.login_form);
mProgressView = findViewById(R.id.login_progress);
} }
private void displayCredentials(LiveData<? extends AccountModel> account) { private void displayCredentials(LiveData<? extends AccountModel> account) {
@ -86,6 +88,7 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito
}); });
} }
// TODO: Move to ViewModel
private void loginDetailsEntered() { private void loginDetailsEntered() {
boolean loginIntact = true; boolean loginIntact = true;
String jidInput = mJidView.getText().toString(); String jidInput = mJidView.getText().toString();
@ -112,8 +115,8 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito
accountModel.setJid(jid); accountModel.setJid(jid);
accountModel.setPassword(password); accountModel.setPassword(password);
long id = accountRepository.insertAccount(accountModel); long id = accountRepository.insertAccount(accountModel);
Log.d(MercuryImApplication.TAG, "LoginActivity.loginDetailsEntered: Account " + id + " inserted.");
attemptLogin(jid, password, id); attemptLogin(jid, password, id);
} }
} }

View File

@ -0,0 +1,30 @@
package org.mercury_im.messenger.ui.roster;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
import org.mercury_im.messenger.persistence.room.repository.IContactRepository;
import javax.inject.Inject;
public class RosterItemViewModel extends AndroidViewModel {
@Inject
IContactRepository contactRepository;
private LiveData<RoomContactModel> contact;
@Inject
public RosterItemViewModel(@NonNull Application application) {
super(application);
}
public RosterItemViewModel setContactId(long id) {
this.contact = contactRepository.getRosterEntry(id);
return this;
}
}

View File

@ -12,8 +12,11 @@ import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
import java.util.List; import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class RosterRecyclerViewAdapter public class RosterRecyclerViewAdapter
extends RecyclerView.Adapter<RosterRecyclerViewAdapter.RecyclerViewHolder> { extends RecyclerView.Adapter<RosterRecyclerViewAdapter.AbstractRosterItem> {
private List<RoomContactModel> entryModelList; private List<RoomContactModel> entryModelList;
@ -23,17 +26,28 @@ public class RosterRecyclerViewAdapter
@NonNull @NonNull
@Override @Override
public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public AbstractRosterItem onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new RecyclerViewHolder(LayoutInflater.from(parent.getContext()) // switch (viewType) {
.inflate(R.layout.recycler_view_item_roster_entry, parent, false)); // case RosterItemViewHolder.TYPE:
return new RosterItemViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_view_item_roster_entry, parent, false));
// default:
// return new RosterItemViewHolder(LayoutInflater.from(parent.getContext())
// .inflate(R.layout.recycler_view_item_roster_entry, parent, false));
// }
} }
@Override @Override
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) { public void onBindViewHolder(@NonNull AbstractRosterItem holder, int position) {
RoomContactModel model = entryModelList.get(position); RoomContactModel model = entryModelList.get(position);
holder.jidView.setText(model.getJid().toString()); // switch (holder.getItemViewType()) {
holder.nicknameView.setText(model.getNickname()); // case RosterItemViewHolder.TYPE:
holder.itemView.setTag(model); RosterItemViewHolder rosterItem = (RosterItemViewHolder) holder;
rosterItem.jidView.setText(model.getJid().toString());
rosterItem.nicknameView.setText(model.getNickname());
rosterItem.itemView.setTag(model);
// break;
// }
} }
@Override @Override
@ -46,15 +60,31 @@ public class RosterRecyclerViewAdapter
notifyDataSetChanged(); notifyDataSetChanged();
} }
public class RecyclerViewHolder extends RecyclerView.ViewHolder { public abstract class AbstractRosterItem extends RecyclerView.ViewHolder {
private TextView jidView; public AbstractRosterItem(@NonNull View itemView) {
private TextView nicknameView;
public RecyclerViewHolder(View itemView) {
super(itemView); super(itemView);
this.jidView = itemView.findViewById(R.id.roster_entry__jid); }
this.nicknameView = itemView.findViewById(R.id.roster_entry__nickname);
abstract void bind(RosterViewModel viewModel);
}
public class RosterItemViewHolder extends AbstractRosterItem {
@BindView(R.id.roster_entry__jid)
TextView jidView;
@BindView(R.id.roster_entry__nickname)
TextView nicknameView;
public RosterItemViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(itemView);
}
@Override
void bind(RosterViewModel viewModel) {
// viewModel.getRosterEntryList().observe();
} }
} }
} }

View File

@ -0,0 +1,9 @@
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fragment"
android:name="org.mercury_im.messenger.ui.login.AccountsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:layout="@layout/fragment_account_list" />

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/input_layout_jid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp">
<EditText
android:id="@+id/input_jid"
android:inputType="textEmailAddress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_jid"
tools:text="alice@wonderland.lit" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/input_layout_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp">
<EditText
android:id="@+id/input_password"
android:inputType="textPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_password"
tools:text="swordfish"
/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list"
android:name="org.mercury_im.messenger.ui.login.AccountsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context="org.mercury_im.messenger.ui.login.AccountsFragment"
tools:listitem="@layout/fragment_account" />

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="66dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/avatar_account"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/aldrin" />
<TextView
android:id="@+id/text_account_jid"
style="@style/TextAppearance.AppCompat.Large"
android:layout_width="291dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/switch_account_enabled"
app:layout_constraintStart_toEndOf="@+id/avatar_account"
app:layout_constraintTop_toTopOf="parent"
tools:text="buzz@jabber.nasa.gov" />
<Switch
android:id="@+id/switch_account_enabled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,56 +1,63 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto" <data>
xmlns:tools="http://schemas.android.com/tools" <variable
android:layout_width="match_parent" name="viewmodel"
android:layout_height="wrap_content"> type="org.mercury_im.messenger.ui.roster.RosterViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<de.hdodenhof.circleimageview.CircleImageView <de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/roster_entry__avatar" android:id="@+id/roster_entry__avatar"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="50dp" android:layout_height="50dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
android:src="@drawable/aldrin" android:src="@drawable/aldrin"
tools:src="@drawable/aldrin" tools:src="@drawable/aldrin"
tools:srcCompat="@drawable/aldrin" /> tools:srcCompat="@drawable/aldrin" />
<TextView <TextView
android:id="@+id/roster_entry__nickname" android:id="@+id/roster_entry__nickname"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:text="@tools:sample/full_names" android:text="@{viewmodel.rosterEntryList."
android:textSize="20sp" tools:text="@tools:sample/full_names"
android:textColor="@android:color/black" android:textSize="20sp"
app:layout_constraintTop_toTopOf="@+id/roster_entry__avatar" android:textColor="@android:color/black"
app:layout_constraintStart_toEndOf="@+id/roster_entry__avatar" app:layout_constraintTop_toTopOf="@+id/roster_entry__avatar"
android:layout_marginStart="8dp" app:layout_constraintStart_toEndOf="@+id/roster_entry__avatar"
android:layout_marginBottom="8dp" android:layout_marginStart="8dp"
app:layout_constraintBottom_toTopOf="@+id/roster_entry__jid" /> android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/roster_entry__jid" />
<TextView <TextView
android:id="@+id/roster_entry__jid" android:id="@+id/roster_entry__jid"
android:layout_width="285dp" android:layout_width="285dp"
android:layout_height="16dp" android:layout_height="16dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="@+id/roster_entry__avatar" app:layout_constraintBottom_toBottomOf="@+id/roster_entry__avatar"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.050" app:layout_constraintHorizontal_bias="0.050"
app:layout_constraintStart_toEndOf="@+id/roster_entry__avatar" app:layout_constraintStart_toEndOf="@+id/roster_entry__avatar"
tools:text="@tools:sample/lorem[4:10]" /> tools:text="@tools:sample/lorem[4:10]" />
<TextView <TextView
android:id="@+id/roster_entry__date" android:id="@+id/roster_entry__date"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/roster_entry__avatar" app:layout_constraintTop_toTopOf="@+id/roster_entry__avatar"
tools:text="@tools:sample/date/hhmm" /> tools:text="@tools:sample/date/hhmm" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -19,4 +19,10 @@
android:orderInCategory="120" android:orderInCategory="120"
android:title="Chat" android:title="Chat"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/action_accounts"
android:orderInCategory="130"
android:title="Accounts"
app:showAsAction="never" />
</menu> </menu>

View File

@ -3,4 +3,5 @@
<dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="fab_margin">16dp</dimen> <dimen name="fab_margin">16dp</dimen>
<dimen name="text_margin">16dp</dimen>
</resources> </resources>

View File

@ -42,8 +42,8 @@ dependencies {
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
androidTestImplementation "androidx.test:core:1.2.0-beta01" androidTestImplementation "androidx.test:core:1.2.0"
androidTestImplementation 'androidx.test.ext:junit:1.1.1-beta01' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
// Room // Room
api "androidx.room:room-runtime:$roomVersion" api "androidx.room:room-runtime:$roomVersion"

View File

@ -2,11 +2,11 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 1, "version": 1,
"identityHash": "378204e8bb2f9f4c8bf432291835718c", "identityHash": "8cbb04481870b8e1320677566696f9ad",
"entities": [ "entities": [
{ {
"tableName": "RoomContactModel", "tableName": "RoomContactModel",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `jid` TEXT NOT NULL, `rosterName` TEXT, `nickname` TEXT, PRIMARY KEY(`accountId`, `jid`), FOREIGN KEY(`accountId`) REFERENCES `accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `jid` TEXT NOT NULL, `rosterName` TEXT, `nickname` TEXT, `avatarFile` TEXT, PRIMARY KEY(`accountId`, `jid`), FOREIGN KEY(`accountId`) REFERENCES `accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`accountId`, `jid`) REFERENCES `entities`(`accountId`, `jid`) ON UPDATE NO ACTION ON DELETE RESTRICT )",
"fields": [ "fields": [
{ {
"fieldPath": "accountId", "fieldPath": "accountId",
@ -31,6 +31,12 @@
"columnName": "nickname", "columnName": "nickname",
"affinity": "TEXT", "affinity": "TEXT",
"notNull": false "notNull": false
},
{
"fieldPath": "avatarFile",
"columnName": "avatarFile",
"affinity": "TEXT",
"notNull": false
} }
], ],
"primaryKey": { "primaryKey": {
@ -62,6 +68,19 @@
"referencedColumns": [ "referencedColumns": [
"id" "id"
] ]
},
{
"table": "entities",
"onDelete": "RESTRICT",
"onUpdate": "NO ACTION",
"columns": [
"accountId",
"jid"
],
"referencedColumns": [
"accountId",
"jid"
]
} }
] ]
}, },
@ -100,7 +119,16 @@
], ],
"autoGenerate": true "autoGenerate": true
}, },
"indices": [], "indices": [
{
"name": "index_accounts_id",
"unique": false,
"columnNames": [
"id"
],
"createSql": "CREATE INDEX `index_accounts_id` ON `${TABLE_NAME}` (`id`)"
}
],
"foreignKeys": [] "foreignKeys": []
}, },
{ {
@ -150,7 +178,71 @@
], ],
"autoGenerate": true "autoGenerate": true
}, },
"indices": [], "indices": [
{
"name": "index_messages_id",
"unique": false,
"columnNames": [
"id"
],
"createSql": "CREATE INDEX `index_messages_id` ON `${TABLE_NAME}` (`id`)"
}
],
"foreignKeys": [
{
"table": "accounts",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"accountId"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "entities",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `jid` TEXT NOT NULL, `avatarFile` TEXT, PRIMARY KEY(`accountId`, `jid`), FOREIGN KEY(`accountId`) REFERENCES `accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "accountId",
"columnName": "accountId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "jid",
"columnName": "jid",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "avatarFile",
"columnName": "avatarFile",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"accountId",
"jid"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_entities_accountId_jid",
"unique": true,
"columnNames": [
"accountId",
"jid"
],
"createSql": "CREATE UNIQUE INDEX `index_entities_accountId_jid` ON `${TABLE_NAME}` (`accountId`, `jid`)"
}
],
"foreignKeys": [ "foreignKeys": [
{ {
"table": "accounts", "table": "accounts",
@ -169,7 +261,7 @@
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"378204e8bb2f9f4c8bf432291835718c\")" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"8cbb04481870b8e1320677566696f9ad\")"
] ]
} }
} }

View File

@ -12,8 +12,14 @@ import org.mercury_im.messenger.persistence.room.dao.ContactDao;
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel; import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
import org.mercury_im.messenger.persistence.room.model.RoomContactModel; import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
import org.mercury_im.messenger.persistence.room.model.RoomMessageModel; import org.mercury_im.messenger.persistence.room.model.RoomMessageModel;
import org.mercury_im.messenger.persistence.room.model.RoomXmppIdentityModel;
@Database(entities = {RoomContactModel.class, RoomAccountModel.class, RoomMessageModel.class}, version = 1) @Database(entities = {
RoomContactModel.class,
RoomAccountModel.class,
RoomMessageModel.class,
RoomXmppIdentityModel.class},
version = 1)
public abstract class AppDatabase extends RoomDatabase { public abstract class AppDatabase extends RoomDatabase {
private static final String DB_NAME = "mercury_db"; private static final String DB_NAME = "mercury_db";

View File

@ -5,20 +5,22 @@ import androidx.room.Dao;
import androidx.room.Query; import androidx.room.Query;
import androidx.room.TypeConverters; import androidx.room.TypeConverters;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.EntityFullJid; import org.jxmpp.jid.EntityFullJid;
import org.mercury_im.messenger.persistence.room.model.RoomMessageModel; import org.mercury_im.messenger.persistence.room.model.RoomMessageModel;
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
import org.mercury_im.messenger.persistence.room.type_converter.EntityFullJidConverter; import org.mercury_im.messenger.persistence.room.type_converter.EntityFullJidConverter;
import java.util.List; import java.util.List;
@Dao @Dao
@TypeConverters(EntityFullJidConverter.class) @TypeConverters(EntityBareJidConverter.class)
public interface MessageDao extends BaseDao<RoomMessageModel> { public interface MessageDao extends BaseDao<RoomMessageModel> {
@Query("SELECT * FROM messages WHERE accountId=:accountId ORDER BY sendDate DESC") @Query("SELECT * FROM messages WHERE accountId=:accountId ORDER BY sendDate DESC")
LiveData<List<RoomMessageModel>> getAllMessagesOf(long accountId); LiveData<List<RoomMessageModel>> getAllMessagesOf(long accountId);
@Query("SELECT * FROM messages WHERE accountId=:accountId AND `from`=:sender ORDER BY sendDate DESC") @Query("SELECT * FROM messages WHERE accountId=:accountId AND `from`=:sender ORDER BY sendDate DESC")
LiveData<List<RoomMessageModel>> getAllMessagesFrom(long accountId, EntityFullJid sender); LiveData<List<RoomMessageModel>> getAllMessagesFrom(long accountId, EntityBareJid sender);
} }

View File

@ -3,6 +3,7 @@ package org.mercury_im.messenger.persistence.room.model;
import androidx.room.ColumnInfo; import androidx.room.ColumnInfo;
import androidx.room.Entity; import androidx.room.Entity;
import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import androidx.room.TypeConverters; import androidx.room.TypeConverters;
@ -10,7 +11,7 @@ import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.persistence.model.AccountModel; import org.mercury_im.messenger.persistence.model.AccountModel;
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter; import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
@Entity(tableName = "accounts") @Entity(tableName = "accounts", indices = {@Index("id")})
public class RoomAccountModel implements AccountModel { public class RoomAccountModel implements AccountModel {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)

View File

@ -1,23 +1,30 @@
package org.mercury_im.messenger.persistence.room.model; package org.mercury_im.messenger.persistence.room.model;
import androidx.lifecycle.LiveData;
import androidx.paging.PagedList;
import androidx.room.Entity; import androidx.room.Entity;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.persistence.model.ChatModel; import org.mercury_im.messenger.persistence.model.ChatModel;
import org.mercury_im.messenger.persistence.model.ContactModel;
import org.mercury_im.messenger.persistence.model.MessageModel;
@Entity @Entity
public class RoomChatModel implements ChatModel { public class RoomChatModel implements ChatModel {
@Override @Override
public LiveData<ContactModel> getContact() { public EntityBareJid getJid() {
return null; return null;
} }
@Override @Override
public LiveData<PagedList<MessageModel>> getMessages() { public void setJid(EntityBareJid jid) {
return null;
}
@Override
public long getAccountId() {
return 0;
}
@Override
public void setAccountId() {
} }
} }

View File

@ -10,6 +10,7 @@ import androidx.room.TypeConverters;
import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.persistence.model.ContactModel; import org.mercury_im.messenger.persistence.model.ContactModel;
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter; import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
import org.mercury_im.messenger.persistence.room.type_converter.FileConverter;
import java.io.File; import java.io.File;
@ -39,6 +40,7 @@ public class RoomContactModel implements ContactModel {
private String nickname; private String nickname;
@TypeConverters(FileConverter.class)
private File avatarFile; private File avatarFile;
public RoomContactModel(@NonNull EntityBareJid jid, public RoomContactModel(@NonNull EntityBareJid jid,
@ -90,7 +92,6 @@ public class RoomContactModel implements ContactModel {
this.accountId = accountId; this.accountId = accountId;
} }
@Override
public File getAvatarFile() { public File getAvatarFile() {
return avatarFile; return avatarFile;
} }

View File

@ -2,21 +2,22 @@ package org.mercury_im.messenger.persistence.room.model;
import androidx.room.Entity; import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import androidx.room.TypeConverter;
import androidx.room.TypeConverters; import androidx.room.TypeConverters;
import org.jxmpp.jid.EntityFullJid; import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.persistence.model.MessageModel; import org.mercury_im.messenger.persistence.model.MessageModel;
import org.mercury_im.messenger.persistence.room.type_converter.DateConverter; import org.mercury_im.messenger.persistence.room.type_converter.DateConverter;
import org.mercury_im.messenger.persistence.room.type_converter.EntityFullJidConverter; import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
import java.util.Date; import java.util.Date;
import static androidx.room.ForeignKey.CASCADE; import static androidx.room.ForeignKey.CASCADE;
@Entity(tableName = "messages", foreignKeys = @ForeignKey(entity = RoomAccountModel.class, @Entity(tableName = "messages", foreignKeys = @ForeignKey(entity = RoomAccountModel.class,
parentColumns = "id", childColumns = "accountId", onDelete = CASCADE)) parentColumns = "id", childColumns = "accountId", onDelete = CASCADE),
indices = {@Index("id")})
public class RoomMessageModel implements MessageModel { public class RoomMessageModel implements MessageModel {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
@ -29,11 +30,11 @@ public class RoomMessageModel implements MessageModel {
@TypeConverters(DateConverter.class) @TypeConverters(DateConverter.class)
private Date sendDate; private Date sendDate;
@TypeConverters(EntityFullJidConverter.class) @TypeConverters(EntityBareJidConverter.class)
private EntityFullJid from; private EntityBareJid from;
@TypeConverters(EntityFullJidConverter.class) @TypeConverters(EntityBareJidConverter.class)
private EntityFullJid to; private EntityBareJid to;
public RoomMessageModel() { public RoomMessageModel() {
@ -80,22 +81,22 @@ public class RoomMessageModel implements MessageModel {
} }
@Override @Override
public EntityFullJid getFrom() { public EntityBareJid getFrom() {
return from; return from;
} }
@Override @Override
public void setFrom(EntityFullJid sender) { public void setFrom(EntityBareJid sender) {
this.from = sender; this.from = sender;
} }
@Override @Override
public EntityFullJid getTo() { public EntityBareJid getTo() {
return to; return to;
} }
@Override @Override
public void setTo(EntityFullJid recipient) { public void setTo(EntityBareJid recipient) {
this.to = recipient; this.to = recipient;
} }
} }

View File

@ -6,9 +6,12 @@ import androidx.annotation.NonNull;
import androidx.room.Entity; import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.TypeConverters;
import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.persistence.model.XmppIdentityModel; import org.mercury_im.messenger.persistence.model.XmppIdentityModel;
import org.mercury_im.messenger.persistence.room.type_converter.EntityBareJidConverter;
import org.mercury_im.messenger.persistence.room.type_converter.FileConverter;
import java.io.File; import java.io.File;
@ -24,8 +27,11 @@ public class RoomXmppIdentityModel implements XmppIdentityModel {
protected long accountId; protected long accountId;
@NonNull
@TypeConverters(EntityBareJidConverter.class)
protected EntityBareJid jid; protected EntityBareJid jid;
@TypeConverters(FileConverter.class)
protected File avatarFile; protected File avatarFile;
@NonNull @NonNull

View File

@ -1,7 +1,27 @@
package org.mercury_im.messenger.persistence.room.repository; package org.mercury_im.messenger.persistence.room.repository;
import androidx.lifecycle.LiveData;
import org.mercury_im.messenger.persistence.model.ChatModel;
import org.mercury_im.messenger.persistence.model.XmppIdentityModel;
import org.mercury_im.messenger.persistence.repository.ChatRepository; import org.mercury_im.messenger.persistence.repository.ChatRepository;
import java.util.List;
public class IChatRepository implements ChatRepository { public class IChatRepository implements ChatRepository {
@Override
public LiveData<List<ChatModel>> getAllChats() {
return null;
}
@Override
public void getChatWith(XmppIdentityModel identity) {
}
@Override
public void closeChat(ChatModel chat) {
}
} }

View File

@ -26,5 +26,10 @@ public class IContactRepository implements ContactRepository<RoomContactModel> {
contactDao.insert(rosterEntryModel); contactDao.insert(rosterEntryModel);
} }
@Override
public LiveData<RoomContactModel> getRosterEntry(long id) {
return null;
}
} }

View File

@ -29,7 +29,12 @@ public class IMessageRepository implements MessageRepository<RoomMessageModel> {
} }
@Override @Override
public LiveData<List<RoomMessageModel>> getAllMessagesFrom(long accountId, EntityFullJid contact) { public LiveData<List<RoomMessageModel>> getAllMessagesFrom(long accountId, EntityBareJid contact) {
return messageDao.getAllMessagesFrom(accountId, contact); return messageDao.getAllMessagesFrom(accountId, contact);
} }
@Override
public LiveData<List<RoomMessageModel>> findMessageByQuery(String query) {
return null;
}
} }

View File

@ -0,0 +1,18 @@
package org.mercury_im.messenger.persistence.room.type_converter;
import androidx.room.TypeConverter;
import java.io.File;
public class FileConverter {
@TypeConverter
public static String toString(File file) {
return file.getAbsolutePath();
}
@TypeConverter
public static File toFile(String string) {
return new File(string);
}
}

View File

@ -2,6 +2,8 @@ package org.mercury_im.messenger.persistence.model;
import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.EntityBareJid;
import java.io.File;
public interface ContactModel { public interface ContactModel {
long getAccountId(); long getAccountId();
@ -19,4 +21,8 @@ public interface ContactModel {
String getNickname(); String getNickname();
void setNickname(String nickname); void setNickname(String nickname);
File getAvatarFile();
void setAvatarFile(File file);
} }

View File

@ -11,4 +11,6 @@ public interface ContactRepository<E extends ContactModel> {
LiveData<List<E>> getAllRosterEntries(); LiveData<List<E>> getAllRosterEntries();
void updateOrInsertRosterEntry(E rosterEntryModel); void updateOrInsertRosterEntry(E rosterEntryModel);
LiveData<E> getRosterEntry(long id);
} }

View File

@ -37,7 +37,7 @@ ext {
// Architecture Components // Architecture Components
lifecycleVersion = "2.0.0" lifecycleVersion = "2.0.0"
roomVersion = "2.1.0-beta01" roomVersion = "2.1.0-rc01"
pagingVersion = "2.1.0" pagingVersion = "2.1.0"
// Dagger 2 // Dagger 2
@ -45,4 +45,7 @@ ext {
// Android Support Library // Android Support Library
supportLibVersion = "28.0.0" supportLibVersion = "28.0.0"
// Butter Knife
butterKnifeVersion = "10.1.0"
} }