Temp commit

This commit is contained in:
Paul Schaub 2019-05-04 00:27:02 +02:00
parent cd2c9a97ed
commit 0d7884c674
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
52 changed files with 604 additions and 312 deletions

View file

@ -1,29 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
</code_scheme>
</component>

4
.idea/encodings.xml generated Normal file
View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>

6
.idea/gradle.xml generated
View file

@ -8,6 +8,12 @@
</compositeConfiguration>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>

37
.idea/misc.xml generated
View file

@ -5,7 +5,42 @@
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
</configurations>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="10">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="9">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View file

@ -2,16 +2,18 @@ apply plugin: 'com.android.application'
apply plugin: 'checkstyle'
android {
compileSdkVersion 27
compileSdkVersion 28
defaultConfig {
applicationId "org.olomono.messenger"
minSdkVersion 19
targetSdkVersion 27
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
@ -29,6 +31,10 @@ android {
sourceCompatibility 1.8
targetCompatibility 1.8
}
dataBinding {
enabled true
}
}
checkstyle {
@ -69,8 +75,8 @@ dependencies {
// architecture components for database and lifecycle management
implementation "android.arch.lifecycle:extensions:$archCompVersion"
implementation "android.arch.persistence.room:runtime:$archCompVersion"
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation "android.arch.lifecycle:extensions:$archCompVersion"
annotationProcessor "android.arch.lifecycle:compiler:$archCompVersion"
annotationProcessor "android.arch.persistence.room:compiler:$archCompVersion"

View file

@ -12,25 +12,28 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:name=".MessengerApplication">
<activity android:name=".ui.chat.ChatActivity">
</activity>
<activity
android:name=".ui.MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".view.MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".view.settings.SettingsActivity"
android:name=".ui.settings.SettingsActivity"
android:label="@string/title_activity_settings" />
<activity
android:name=".view.LoginActivity"
android:name=".ui.login.LoginActivity"
android:label="@string/title_activity_login" />
<service android:name=".service.XmppService" />

View file

@ -0,0 +1,37 @@
package org.olomono.messenger;
import android.app.Application;
import org.olomono.messenger.di.component.AppComponent;
import org.olomono.messenger.di.component.DaggerAppComponent;
import org.olomono.messenger.di.module.AppModule;
import org.olomono.messenger.di.module.RepositoryModule;
import org.olomono.messenger.di.module.RoomModule;
public class MessengerApplication extends Application {
private static MessengerApplication INSTANCE;
AppComponent appComponent;
public static MessengerApplication getApplication() {
return INSTANCE;
}
@Override
public void onCreate() {
super.onCreate();
INSTANCE = this;
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.roomModule(new RoomModule(this))
.repositoryModule(new RepositoryModule())
.build();
appComponent.inject(this);
}
public AppComponent getAppComponent() {
return appComponent;
}
}

View file

@ -1,35 +1,53 @@
package org.olomono.messenger.di.component;
import android.app.Application;
import org.olomono.messenger.MessengerApplication;
import org.olomono.messenger.di.module.AppModule;
import org.olomono.messenger.di.module.RepositoryModule;
import org.olomono.messenger.di.module.RoomModule;
import org.olomono.messenger.persistence.database.AppDatabase;
import org.olomono.messenger.persistence.database.dao.AccountDao;
import org.olomono.messenger.persistence.database.dao.RosterEntryDao;
import org.olomono.messenger.persistence.repository.account.AccountRepository;
import org.olomono.messenger.persistence.repository.RosterEntryRepository;
import org.olomono.messenger.view.MainActivity;
import org.olomono.messenger.service.XmppService;
import org.olomono.messenger.ui.MainActivity;
import org.olomono.messenger.ui.chat.ChatActivity;
import org.olomono.messenger.ui.chat.ChatInputFragment;
import org.olomono.messenger.ui.chat.ChatInputViewModel;
import org.olomono.messenger.ui.chat.ChatViewModel;
import org.olomono.messenger.ui.login.LoginActivity;
import org.olomono.messenger.ui.login.LoginViewModel;
import org.olomono.messenger.ui.roster.RosterFragment;
import org.olomono.messenger.ui.roster.RosterViewModel;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(dependencies = {}, modules = {AppModule.class, RoomModule.class})
@Component(dependencies = {}, modules = {AppModule.class, RoomModule.class, RepositoryModule.class})
public interface AppComponent {
// Application
void inject(MessengerApplication messengerApplication);
// Views
void inject(MainActivity mainActivity);
AccountDao accountDao();
void inject(LoginActivity loginActivity);
RosterEntryDao rosterEntryDao();
void inject(ChatActivity chatActivity);
AccountRepository accountRepository();
void inject(ChatInputFragment chatInputFragment);
RosterEntryRepository rosterEntryRepository();
// ViewModels
AppDatabase appDatabase();
void inject(RosterViewModel rosterViewModel);
Application application();
void inject(ChatViewModel chatViewModel);
void inject(ChatInputViewModel chatInputViewModel);
void inject(LoginViewModel loginViewModel);
// Services
void inject(XmppService service);
}

View file

@ -0,0 +1,4 @@
/**
* The Component specifies which classes can be injected from the module.
*/
package org.olomono.messenger.di.component;

View file

@ -1,6 +1,6 @@
package org.olomono.messenger.di.module;
import android.app.Application;
import org.olomono.messenger.MessengerApplication;
import javax.inject.Singleton;
@ -10,15 +10,15 @@ import dagger.Provides;
@Module
public class AppModule {
Application mApplication;
private MessengerApplication mApplication;
public AppModule(Application application) {
public AppModule(MessengerApplication application) {
this.mApplication = application;
}
@Provides
@Singleton
Application provideApplication() {
MessengerApplication provideApplication() {
return mApplication;
}
}

View file

@ -0,0 +1,29 @@
package org.olomono.messenger.di.module;
import org.olomono.messenger.persistence.database.dao.AccountDao;
import org.olomono.messenger.persistence.database.dao.RosterEntryDao;
import org.olomono.messenger.persistence.repository.account.AccountRepository;
import org.olomono.messenger.persistence.repository.account.AccountRepositoryImpl;
import org.olomono.messenger.persistence.repository.roster.RosterEntryRepository;
import org.olomono.messenger.persistence.repository.roster.RosterEntryRepositoryImpl;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class RepositoryModule {
@Singleton
@Provides
AccountRepository provideAccountRepository(AccountDao dao) {
return new AccountRepositoryImpl(dao);
}
@Singleton
@Provides
RosterEntryRepository provideRosterEntryRepository(RosterEntryDao dao) {
return new RosterEntryRepositoryImpl(dao);
}
}

View file

@ -1,26 +1,26 @@
package org.olomono.messenger.di.module;
import android.app.Application;
import org.olomono.messenger.MessengerApplication;
import org.olomono.messenger.persistence.database.AppDatabase;
import org.olomono.messenger.persistence.database.dao.AccountDao;
import org.olomono.messenger.persistence.database.dao.RosterEntryDao;
import org.olomono.messenger.persistence.repository.account.AccountRepository;
import org.olomono.messenger.persistence.repository.RosterEntryRepository;
import org.olomono.messenger.persistence.repository.account.AccountRepositoryImpl;
import org.olomono.messenger.persistence.repository.impl.RosterEntryRepositoryImpl;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
/**
* Provides the {@link AppDatabase}, DAOs and Repositories.
*/
@Module
public class RoomModule {
private AppDatabase mAppDatabase;
public RoomModule(Application application) {
@Inject
public RoomModule(MessengerApplication application) {
mAppDatabase = AppDatabase.getDatabase(application);
}
@ -32,14 +32,8 @@ public class RoomModule {
@Singleton
@Provides
AccountDao provideAccountDao(AppDatabase appDatabase) {
return appDatabase.accountDao();
}
@Singleton
@Provides
AccountRepository provideAccountRepository(AccountDao dao) {
return new AccountRepositoryImpl(dao);
AccountDao provideAccountDao() {
return mAppDatabase.accountDao();
}
@Singleton
@ -47,10 +41,4 @@ public class RoomModule {
RosterEntryDao provideRosterEntryDao() {
return mAppDatabase.rosterEntryDao();
}
@Singleton
@Provides
RosterEntryRepository provideRosterEntryRepository(RosterEntryDao dao) {
return new RosterEntryRepositoryImpl(dao);
}
}

View file

@ -0,0 +1,9 @@
/**
* Modules define the methods that return the objects youll need to inject in your classes.
* If a method is dependent on passing in a parameter, then you need to define an additional
* method that will return the object to be passed into the original method. The module will
* know which method to run in order to obtain the object being injected.
*
* @see <a href="https://android.jlelse.eu/the-simplest-dagger2-dependency-injection-sample-80a0eb60e33b">The Simples Dagger2 Dependency Injection Sample App</a>
*/
package org.olomono.messenger.di.module;

View file

@ -1,12 +0,0 @@
package org.olomono.messenger.persistence.database;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Executor {
public static void IOThread(Runnable runnable) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(runnable);
}
}

View file

@ -6,7 +6,10 @@ import android.arch.persistence.room.Delete;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.TypeConverters;
import android.arch.persistence.room.Update;
import android.support.annotation.WorkerThread;
import org.jxmpp.jid.EntityBareJid;
import org.olomono.messenger.persistence.database.model.AccountModel;
import org.olomono.messenger.persistence.database.type_converter.EntityBareJidConverter;
@ -16,6 +19,7 @@ import static android.arch.persistence.room.OnConflictStrategy.REPLACE;
@Dao
@TypeConverters(EntityBareJidConverter.class)
@WorkerThread
public interface AccountDao {
/**
@ -25,7 +29,7 @@ public interface AccountDao {
* @return live updating account list
*/
@Query("select * from AccountModel")
LiveData<List<AccountModel>> getAllAcounts();
LiveData<List<AccountModel>> getAllAccounts();
/**
* Return the {@link AccountModel Account} which is identified by the given id.
@ -34,11 +38,17 @@ public interface AccountDao {
* @return account or null
*/
@Query("select * from AccountModel where id = :id")
LiveData<AccountModel> getAccountById(String id);
LiveData<AccountModel> getAccountById(long id);
@Insert(onConflict = REPLACE)
@Query("select * from AccountModel where jid = :jid")
LiveData<AccountModel> getAccountByJid(EntityBareJid jid);
@Insert
void insertAccount(AccountModel account);
@Update
void updateAccount(AccountModel account);
@Delete
void deleteAccount(AccountModel account);
}

View file

@ -1,4 +1,4 @@
package org.olomono.messenger.persistence.repository.account;
package org.olomono.messenger.persistence.database.model;
import org.jxmpp.jid.EntityBareJid;

View file

@ -7,14 +7,13 @@ import android.arch.persistence.room.TypeConverters;
import org.jxmpp.jid.EntityBareJid;
import org.olomono.messenger.persistence.database.type_converter.EntityBareJidConverter;
import org.olomono.messenger.persistence.repository.account.Account;
@Entity
public class AccountModel implements Account {
@PrimaryKey
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
public int id;
public long id;
@TypeConverters(EntityBareJidConverter.class)
@ColumnInfo(name = "jid")

View file

@ -2,6 +2,7 @@ package org.olomono.messenger.persistence.database.model;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.ForeignKey;
import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import android.arch.persistence.room.TypeConverters;

View file

@ -8,7 +8,7 @@ import java.util.List;
public interface AccountRepository {
LiveData<AccountModel> getAccount(String accountId);
LiveData<AccountModel> getAccount(long accountId);
LiveData<List<AccountModel>> getAllAccounts();

View file

@ -1,6 +1,7 @@
package org.olomono.messenger.persistence.repository.account;
import android.arch.lifecycle.LiveData;
import android.os.AsyncTask;
import org.olomono.messenger.persistence.database.dao.AccountDao;
import org.olomono.messenger.persistence.database.model.AccountModel;
@ -19,17 +20,49 @@ public class AccountRepositoryImpl implements AccountRepository {
}
@Override
public LiveData<AccountModel> getAccount(String accountId) {
public LiveData<AccountModel> getAccount(long accountId) {
return accountDao.getAccountById(accountId);
}
@Override
public LiveData<List<AccountModel>> getAllAccounts() {
return accountDao.getAllAcounts();
return accountDao.getAllAccounts();
}
@Override
public void insertAccount(AccountModel accountModel) {
accountDao.insertAccount(accountModel);
InsertAsyncTask task = new InsertAsyncTask(accountDao);
task.execute(accountModel);
}
private static class InsertAsyncTask extends AsyncTask<AccountModel, Void, Void> {
private final AccountDao accountDao;
private InsertAsyncTask(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
protected Void doInBackground(AccountModel... accountModels) {
for (AccountModel accountModel : accountModels) {
accountDao.insertAccount(accountModel);
}
return null;
}
}
private static class QueryAsyncTask extends AsyncTask<Long, Void, LiveData<AccountModel>> {
private final AccountDao accountDao;
private QueryAsyncTask(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
protected LiveData<AccountModel> doInBackground(Long... longs) {
return accountDao.getAccountById(longs[0]);
}
}
}

View file

@ -1,22 +0,0 @@
package org.olomono.messenger.persistence.repository.impl;
import android.arch.lifecycle.LiveData;
import org.olomono.messenger.persistence.database.dao.RosterEntryDao;
import org.olomono.messenger.persistence.repository.RosterEntryRepository;
import org.olomono.messenger.view.viewmodel.RosterEntryListViewModel;
public class RosterEntryRepositoryImpl implements RosterEntryRepository {
private final RosterEntryDao rosterEntryDao;
public RosterEntryRepositoryImpl(RosterEntryDao dao) {
this.rosterEntryDao = dao;
}
@Override
public LiveData<RosterEntryListViewModel> getRosterEntries() {
// TODO
return null;
}
}

View file

@ -1,17 +1,19 @@
package org.olomono.messenger.persistence.repository;
package org.olomono.messenger.persistence.repository.roster;
import android.arch.lifecycle.LiveData;
import org.jivesoftware.smack.roster.RosterEntry;
import org.olomono.messenger.persistence.database.model.RosterEntryModel;
import org.olomono.messenger.view.viewmodel.RosterEntryListViewModel;
import org.olomono.messenger.ui.roster.RosterViewModel;
import java.util.List;
public interface RosterEntryRepository {
/**
* Return a {@link LiveData} object of a {@link RosterEntryListViewModel} which contains
* Return a {@link LiveData} object of a {@link RosterViewModel} which contains
* {@link RosterEntryModel} for all {@link RosterEntry RosterEntries} in the users roster.
* @return
*/
LiveData<RosterEntryListViewModel> getRosterEntries();
LiveData<List<RosterEntryModel>> getAllRosterEntries();
}

View file

@ -0,0 +1,26 @@
package org.olomono.messenger.persistence.repository.roster;
import android.arch.lifecycle.LiveData;
import org.olomono.messenger.persistence.database.dao.RosterEntryDao;
import org.olomono.messenger.persistence.database.model.RosterEntryModel;
import org.olomono.messenger.persistence.repository.roster.RosterEntryRepository;
import org.olomono.messenger.ui.roster.RosterViewModel;
import java.util.List;
public class RosterEntryRepositoryImpl implements RosterEntryRepository {
private final RosterEntryDao rosterEntryDao;
public RosterEntryRepositoryImpl(RosterEntryDao dao) {
this.rosterEntryDao = dao;
}
@Override
public LiveData<List<RosterEntryModel>> getAllRosterEntries() {
return rosterEntryDao.getAllRosterEntries();
}
}

View file

@ -0,0 +1,27 @@
package org.olomono.messenger.service;
import android.util.LongSparseArray;
import org.jivesoftware.smack.XMPPConnection;
public class XmppConnectionHolder {
private static XmppConnectionHolder INSTANCE;
private final LongSparseArray<XMPPConnection> connections = new LongSparseArray<>();
private XmppConnectionHolder() {
}
public static XmppConnectionHolder getInstance() {
if (INSTANCE == null) {
INSTANCE = new XmppConnectionHolder();
}
return INSTANCE;
}
public LongSparseArray<XMPPConnection> getConnections() {
return connections;
}
}

View file

@ -4,16 +4,25 @@ import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.LongSparseArray;
import android.util.SparseArray;
import org.jivesoftware.smack.XMPPConnection;
import org.olomono.messenger.MessengerApplication;
import org.olomono.messenger.persistence.database.AppDatabase;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import javax.inject.Inject;
public class XmppService extends Service {
private AppDatabase database;
@Inject
AppDatabase database;
private SparseArray<XMPPConnection> connections = new SparseArray<>();
private LongSparseArray<XMPPConnection> connections = new LongSparseArray<>();
@Nullable
@Override
@ -24,10 +33,10 @@ public class XmppService extends Service {
@Override
public void onCreate() {
super.onCreate();
this.database = AppDatabase.getDatabase(getApplicationContext());
MessengerApplication.getApplication().getAppComponent().inject(this);
}
public XMPPConnection getConnection(int accountId) {
public XMPPConnection getConnection(long accountId) {
return connections.get(accountId);
}

View file

@ -1,4 +1,4 @@
package org.olomono.messenger.view;
package org.olomono.messenger.ui;
import android.content.Intent;
import android.os.AsyncTask;
@ -11,6 +11,7 @@ import android.view.MenuItem;
import android.view.View;
import org.jxmpp.jid.impl.JidCreate;
import org.olomono.messenger.MessengerApplication;
import org.olomono.messenger.R;
import org.olomono.messenger.di.component.DaggerAppComponent;
import org.olomono.messenger.di.module.AppModule;
@ -19,8 +20,10 @@ import org.olomono.messenger.persistence.database.AppDatabase;
import org.olomono.messenger.persistence.database.model.AccountModel;
import org.olomono.messenger.persistence.database.model.RosterEntryModel;
import org.olomono.messenger.persistence.repository.account.AccountRepository;
import org.olomono.messenger.persistence.repository.RosterEntryRepository;
import org.olomono.messenger.view.settings.SettingsActivity;
import org.olomono.messenger.persistence.repository.roster.RosterEntryRepository;
import org.olomono.messenger.ui.chat.ChatActivity;
import org.olomono.messenger.ui.login.LoginActivity;
import org.olomono.messenger.ui.settings.SettingsActivity;
import java.util.List;
@ -41,11 +44,7 @@ public class MainActivity extends AppCompatActivity {
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DaggerAppComponent.builder()
.appModule(new AppModule(getApplication()))
.roomModule(new RoomModule(getApplication()))
.build()
.inject(this);
MessengerApplication.getApplication().getAppComponent().inject(this);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@ -54,6 +53,7 @@ public class MainActivity extends AppCompatActivity {
AccountModel account = new AccountModel();
account.setJid(JidCreate.entityBareFromOrThrowUnchecked("alice@wonderland.lit"));
account.setPassword("swordfish");
accountRepository.insertAccount(account);
}
});
@ -68,15 +68,20 @@ public class MainActivity extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
startActivity(new Intent(getApplicationContext(), SettingsActivity.class));
return true;
switch (id) {
case R.id.action_settings:
startActivity(new Intent(getApplicationContext(), SettingsActivity.class));
return true;
case R.id.action_login:
startActivity(new Intent(getApplicationContext(), LoginActivity.class));
return true;
case R.id.action_chat:
startActivity(new Intent(getApplicationContext(), ChatActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
@ -96,7 +101,7 @@ public class MainActivity extends AppCompatActivity {
@Override
protected Void doInBackground(Runnable... runnables) {
List<AccountModel> accounts = database.accountDao().getAllAcounts().getValue();
List<AccountModel> accounts = database.accountDao().getAllAccounts().getValue();
if (accounts == null || accounts.size() == 0) {
runnables[0].run();
}

View file

@ -13,7 +13,7 @@ public class ChatActivity extends AppCompatActivity {
setContentView(R.layout.activity_chat);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, ChatFragment.newInstance())
.replace(R.id.container, ChatInputFragment.newInstance())
.commitNow();
}
}

View file

@ -1,36 +0,0 @@
package org.olomono.messenger.ui.chat;
import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.olomono.messenger.R;
public class ChatFragment extends Fragment {
private ChatViewModel mViewModel;
public static ChatFragment newInstance() {
return new ChatFragment();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_chat, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(ChatViewModel.class);
// TODO: Use the ViewModel
}
}

View file

@ -0,0 +1,76 @@
package org.olomono.messenger.ui.chat;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;
import org.olomono.messenger.R;
public class ChatInputFragment extends Fragment implements View.OnClickListener {
private EditText textInput;
private FloatingActionButton addAttachement;
private ImageButton buttonSend;
private ChatInputViewModel mViewModel;
public static ChatInputFragment newInstance() {
return new ChatInputFragment();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_chat, container, false);
textInput = view.findViewById(R.id.chat_field__text_input);
addAttachement = view.findViewById(R.id.chat_field__fab_add);
buttonSend = view.findViewById(R.id.chat_field__button_send);
addAttachement.setOnClickListener(this);
buttonSend.setOnClickListener(this);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(ChatInputViewModel.class);
// observeViewModel(mViewModel);
}
private void observeViewModel(ChatInputViewModel viewModel) {
viewModel.getDraft().observe(ChatInputFragment.this, new Observer<String>() {
@Override
public void onChanged(@Nullable String draft) {
textInput.setText(draft);
}
});
}
@Override
public void onClick(View view) {
switch (view.getId()) {
// Add media
case R.id.chat_field__fab_add:
Toast.makeText(getContext(), R.string.not_yet_implemented, Toast.LENGTH_SHORT).show();
break;
// Send message
case R.id.chat_field__button_send:
textInput.setText(null);
Toast.makeText(getContext(), "Send message clicked", Toast.LENGTH_SHORT).show();
break;
}
}
}

View file

@ -0,0 +1,11 @@
package org.olomono.messenger.ui.chat;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;
public class ChatInputViewModel extends ViewModel {
public MutableLiveData<String> getDraft() {
return null;
}
}

View file

@ -2,6 +2,17 @@ package org.olomono.messenger.ui.chat;
import android.arch.lifecycle.ViewModel;
import org.jxmpp.jid.EntityBareJid;
import org.olomono.messenger.persistence.database.model.Account;
public class ChatViewModel extends ViewModel {
// TODO: Implement the ViewModel
private Account account;
private EntityBareJid contact;
public void init(Account account, EntityBareJid contact) {
this.account = account;
this.contact = contact;
}
}

View file

@ -1,4 +1,4 @@
package org.olomono.messenger.view;
package org.olomono.messenger.ui.login;
import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
@ -15,7 +15,7 @@ import android.widget.TextView;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.olomono.messenger.R;
import org.olomono.messenger.view.viewmodel.LoginViewModel;
import org.olomono.messenger.persistence.database.model.AccountModel;
/**
* A login screen that offers login via email/password.
@ -28,6 +28,8 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito
private View mProgressView;
private View mLoginFormView;
private LoginViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -37,7 +39,20 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito
mJidView = findViewById(R.id.jid);
mPasswordView = findViewById(R.id.password);
LoginViewModel viewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
viewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
viewModel.getAccount().observe(this, accountModel -> {
if (accountModel == null) {
return;
}
if (accountModel.getJid() != null) {
mJidView.setText(accountModel.getJid().toString());
}
if (accountModel.getPassword() != null) {
mPasswordView.setText(accountModel.getPassword());
}
});
mJidView.setOnEditorActionListener(this);
mPasswordView.setOnEditorActionListener(this);
@ -69,6 +84,8 @@ public class LoginActivity extends AppCompatActivity implements TextView.OnEdito
if (!isPasswordValid(password)) {
mPasswordView.setError(getResources().getString(R.string.error_invalid_password));
}
viewModel.login();
}
/**

View file

@ -0,0 +1,40 @@
package org.olomono.messenger.ui.login;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import org.olomono.messenger.persistence.database.model.AccountModel;
import org.olomono.messenger.persistence.repository.account.AccountRepository;
import javax.inject.Inject;
public class LoginViewModel extends ViewModel {
@Inject
AccountRepository accountRepository;
private MutableLiveData<AccountModel> account = new MutableLiveData<>();
public LoginViewModel() {
super();
init(new AccountModel());
}
public void init(@NonNull AccountModel account) {
this.account.setValue(account);
}
public MutableLiveData<AccountModel> getAccount() {
return account;
}
public void login() {
AccountModel account = getAccount().getValue();
if (account != null && account.getJid() != null && !TextUtils.isEmpty(account.getPassword())) {
accountRepository.insertAccount(account);
}
}
}

View file

@ -1,4 +1,4 @@
package org.olomono.messenger.view.roster;
package org.olomono.messenger.ui.roster;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
@ -10,23 +10,26 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.olomono.messenger.MessengerApplication;
import org.olomono.messenger.R;
import org.olomono.messenger.persistence.database.model.RosterEntryModel;
import org.olomono.messenger.view.viewmodel.RosterEntryListViewModel;
import org.olomono.messenger.persistence.repository.roster.RosterEntryRepository;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
/**
* A placeholder fragment containing a simple view.
*/
public class RosterEntryListFragment extends Fragment {
public class RosterFragment extends Fragment {
private RosterEntryListViewModel viewModel;
private RosterEntryListRecyclerViewAdapter recyclerViewAdapter;
private RosterViewModel rosterViewModel;
private RosterRecyclerViewAdapter recyclerViewAdapter;
private RecyclerView recyclerView;
public RosterEntryListFragment() {
public RosterFragment() {
}
@ -36,17 +39,24 @@ public class RosterEntryListFragment extends Fragment {
View view = inflater.inflate(R.layout.fragment_roster_entry_list, container, false);
recyclerView = view.findViewById(R.id.roster_entry_list__recycler_view);
recyclerViewAdapter = new RosterEntryListRecyclerViewAdapter(new ArrayList<>());
recyclerViewAdapter = new RosterRecyclerViewAdapter(new ArrayList<>());
recyclerView.setAdapter(recyclerViewAdapter);
viewModel = ViewModelProviders.of(this).get(RosterEntryListViewModel.class);
viewModel.getRosterEntryList().observe(RosterEntryListFragment.this, new Observer<List<RosterEntryModel>>() {
@Override
public void onChanged(@Nullable List<RosterEntryModel> rosterEntryModels) {
recyclerViewAdapter.addItems(rosterEntryModels);
}
});
rosterViewModel = ViewModelProviders.of(getActivity()).get(RosterViewModel.class);
observeViewModel(rosterViewModel);
return view;
}
private void observeViewModel(RosterViewModel viewModel) {
viewModel.getRosterEntryList().observe(this, new Observer<List<RosterEntryModel>>() {
@Override
public void onChanged(@Nullable List<RosterEntryModel> rosterEntries) {
if (rosterEntries == null) {
return;
}
recyclerViewAdapter.setItems(rosterEntries);
}
});
}
}

View file

@ -1,4 +1,4 @@
package org.olomono.messenger.view.roster;
package org.olomono.messenger.ui.roster;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
@ -12,12 +12,12 @@ import org.olomono.messenger.persistence.database.model.RosterEntryModel;
import java.util.List;
public class RosterEntryListRecyclerViewAdapter
extends RecyclerView.Adapter<RosterEntryListRecyclerViewAdapter.RecyclerViewHolder> {
public class RosterRecyclerViewAdapter
extends RecyclerView.Adapter<RosterRecyclerViewAdapter.RecyclerViewHolder> {
private List<RosterEntryModel> entryModelList;
public RosterEntryListRecyclerViewAdapter(List<RosterEntryModel> entryModelList) {
public RosterRecyclerViewAdapter(List<RosterEntryModel> entryModelList) {
this.entryModelList = entryModelList;
}
@ -41,7 +41,7 @@ public class RosterEntryListRecyclerViewAdapter
return entryModelList.size();
}
public void addItems(List<RosterEntryModel> rosterEntryModels) {
public void setItems(List<RosterEntryModel> rosterEntryModels) {
this.entryModelList = rosterEntryModels;
notifyDataSetChanged();
}

View file

@ -0,0 +1,33 @@
package org.olomono.messenger.ui.roster;
import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.support.annotation.NonNull;
import org.olomono.messenger.MessengerApplication;
import org.olomono.messenger.persistence.database.model.RosterEntryModel;
import org.olomono.messenger.persistence.repository.roster.RosterEntryRepository;
import java.util.List;
import javax.inject.Inject;
public class RosterViewModel extends AndroidViewModel {
@Inject
RosterEntryRepository rosterEntryRepository;
private final LiveData<List<RosterEntryModel>> rosterEntryList;
@Inject
public RosterViewModel(@NonNull Application application) {
super(application);
MessengerApplication.getApplication().getAppComponent().inject(this);
this.rosterEntryList = rosterEntryRepository.getAllRosterEntries();
}
public LiveData<List<RosterEntryModel>> getRosterEntryList() {
return rosterEntryList;
}
}

View file

@ -1,4 +1,4 @@
package org.olomono.messenger.view.settings;
package org.olomono.messenger.ui.settings;
import android.content.res.Configuration;
import android.os.Bundle;

View file

@ -1,4 +1,4 @@
package org.olomono.messenger.view.settings;
package org.olomono.messenger.ui.settings;
import android.annotation.TargetApi;
import android.content.Context;

View file

@ -1,25 +0,0 @@
package org.olomono.messenger.view.viewmodel;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;
public class LoginViewModel extends ViewModel {
public LoginViewModel() {
super();
}
public MutableLiveData<DisplayableCredentials> credentials;
void setJid(String jid) {
}
void setPassword(String password) {
}
static class DisplayableCredentials {
}
}

View file

@ -1,48 +0,0 @@
package org.olomono.messenger.view.viewmodel;
import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import org.olomono.messenger.persistence.database.AppDatabase;
import org.olomono.messenger.persistence.database.model.RosterEntryModel;
import java.util.List;
public class RosterEntryListViewModel extends AndroidViewModel {
private final LiveData<List<RosterEntryModel>> rosterEntryList;
private AppDatabase appDatabase;
public RosterEntryListViewModel(@NonNull Application application) {
super(application);
this.appDatabase = AppDatabase.getDatabase(this.getApplication());
this.rosterEntryList = appDatabase.rosterEntryDao().getAllRosterEntries();
}
public LiveData<List<RosterEntryModel>> getRosterEntryList() {
return rosterEntryList;
}
public void deleteItem(RosterEntryModel entry) {
new deleteAsyncTask(appDatabase).execute(entry);
}
private static class deleteAsyncTask extends AsyncTask<RosterEntryModel, Void, Void> {
private AppDatabase db;
deleteAsyncTask(AppDatabase appDatabase) {
this.db = appDatabase;
}
@Override
protected Void doInBackground(final RosterEntryModel... params) {
db.rosterEntryDao().deleteRosterEntry(params[0]);
return null;
}
}
}

View file

@ -9,7 +9,7 @@
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".view.LoginActivity">
tools:context=".ui.login.LoginActivity">
<!-- Login progress -->
<ProgressBar

View file

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.MainActivity">
tools:context=".ui.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"

View file

@ -2,7 +2,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fragment"
android:name="org.olomono.messenger.view.roster.RosterEntryListFragment"
android:name="org.olomono.messenger.ui.roster.RosterFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"

View file

@ -5,7 +5,7 @@
android:id="@+id/chat"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.chat.ChatFragment">
tools:context=".ui.chat.ChatInputFragment">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"

View file

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.roster.RosterEntryListFragment"
tools:context=".ui.roster.RosterFragment"
tools:showIn="@layout/activity_main">
<android.support.v7.widget.RecyclerView

View file

@ -8,13 +8,14 @@
android:background="@null">
<android.support.design.widget.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:id="@+id/chat_field__fab_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:scaleType="center"
app:fabSize="normal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -25,21 +26,21 @@
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:minHeight="48dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/floatingActionButton"
app:layout_constraintStart_toEndOf="@+id/chat_field__fab_add"
app:layout_constraintTop_toTopOf="parent"
card_view:cardCornerRadius="24dp"
card_view:cardCornerRadius="28dp"
card_view:cardElevation="6dp"
app:cardUseCompatPadding="true">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:minHeight="56dp">
<EditText
android:id="@+id/editText"
android:id="@+id/chat_field__text_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
@ -49,20 +50,21 @@
android:inputType="textMultiLine|textAutoCorrect"
android:maxLines="6"
card_view:layout_constraintBottom_toBottomOf="parent"
card_view:layout_constraintEnd_toStartOf="@+id/appCompatImageButton"
card_view:layout_constraintEnd_toStartOf="@+id/chat_field__button_send"
card_view:layout_constraintStart_toStartOf="parent"
card_view:layout_constraintTop_toTopOf="parent"
tools:text="Open Protocols!" />
<android.support.v7.widget.AppCompatImageButton
android:id="@+id/appCompatImageButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:id="@+id/chat_field__button_send"
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@null"
android:tint="@color/colorAccent"
android:tint="?attr/colorAccent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@drawable/ic_send_black_24dp"
card_view:layout_constraintBottom_toBottomOf="parent" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>

View file

@ -1,10 +1,22 @@
<menu 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"
tools:context="org.olomono.messenger.view.MainActivity">
tools:context="org.olomono.messenger.ui.MainActivity">
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
<item
android:id="@+id/action_login"
android:orderInCategory="110"
android:title="@string/title_activity_login"
app:showAsAction="never" />
<item
android:id="@+id/action_chat"
android:orderInCategory="120"
android:title="Chat"
app:showAsAction="never" />
</menu>

View file

@ -11,6 +11,7 @@
<string name="error_incorrect_password">This password is incorrect</string>
<string name="error_field_required">This field is required</string>
<string name="title_activity_settings">Settings</string>
<string name="not_yet_implemented">Not yet implemented!</string>
<!-- Strings related to Settings -->

View file

@ -3,17 +3,17 @@
<!-- These settings headers are only used on tablets. -->
<header
android:fragment="org.olomono.messenger.view.settings.SettingsActivity$GeneralPreferenceFragment"
android:fragment="org.olomono.messenger.ui.settings.SettingsActivity$GeneralPreferenceFragment"
android:icon="@drawable/ic_info_black_24dp"
android:title="@string/pref_header_general" />
<header
android:fragment="org.olomono.messenger.view.settings.SettingsActivity$NotificationPreferenceFragment"
android:fragment="org.olomono.messenger.ui.settings.SettingsActivity$NotificationPreferenceFragment"
android:icon="@drawable/ic_notifications_black_24dp"
android:title="@string/pref_header_notifications" />
<header
android:fragment="org.olomono.messenger.view.settings.SettingsActivity$DataSyncPreferenceFragment"
android:fragment="org.olomono.messenger.ui.settings.SettingsActivity$DataSyncPreferenceFragment"
android:icon="@drawable/ic_sync_black_24dp"
android:title="@string/pref_header_data_sync" />

View file

@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.android.tools.build:gradle:3.4.0'
// NOTE: Do not place your application dependencies here; they belong

View file

@ -1,6 +1,6 @@
#Fri Apr 05 00:34:49 CEST 2019
#Mon Apr 22 13:24:10 CEST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip

View file

@ -42,5 +42,5 @@ ext {
daggerVersion = "2.17"
// Android Support Library
supportLibVersion = "27.1.1"
supportLibVersion = "28.0.0"
}