Skip to content
Permalink
Browse files

implement rudimentary query view

a query view is list of emails (with collpased threads) with any sort of filter. a filter can for example be mailbox. however the same query view can potentially disply more complex queries (searches) as well.
  • Loading branch information...
iNPUTmice committed Mar 18, 2019
0 parents commit 2c1102dafbd414f064799cc0494241dc0ff67834
Showing with 3,421 additions and 0 deletions.
  1. +14 −0 .gitignore
  2. +1 −0 app/.gitignore
  3. +64 −0 app/build.gradle
  4. +21 −0 app/proguard-rules.pro
  5. +24 −0 app/src/main/AndroidManifest.xml
  6. BIN app/src/main/artwork/cover.png
  7. +29 −0 app/src/main/artwork/render.rb
  8. +12 −0 app/src/main/java/rs/ltt/android/Credentials.java
  9. +153 −0 app/src/main/java/rs/ltt/android/cache/DatabaseCache.java
  10. +52 −0 app/src/main/java/rs/ltt/android/database/Converters.java
  11. +68 −0 app/src/main/java/rs/ltt/android/database/LttrsDatabase.java
  12. +38 −0 app/src/main/java/rs/ltt/android/database/dao/AbstractEntityDao.java
  13. +90 −0 app/src/main/java/rs/ltt/android/database/dao/EmailDao.java
  14. +102 −0 app/src/main/java/rs/ltt/android/database/dao/MailboxDao.java
  15. +91 −0 app/src/main/java/rs/ltt/android/database/dao/QueryDao.java
  16. +50 −0 app/src/main/java/rs/ltt/android/database/dao/StateDao.java
  17. +76 −0 app/src/main/java/rs/ltt/android/database/dao/ThreadDao.java
  18. +6 −0 app/src/main/java/rs/ltt/android/entity/EmailAddressType.java
  19. +65 −0 app/src/main/java/rs/ltt/android/entity/EmailEmailAddressEntity.java
  20. +48 −0 app/src/main/java/rs/ltt/android/entity/EmailEntity.java
  21. +48 −0 app/src/main/java/rs/ltt/android/entity/EmailKeywordEntity.java
  22. +43 −0 app/src/main/java/rs/ltt/android/entity/EmailMailboxEntity.java
  23. +8 −0 app/src/main/java/rs/ltt/android/entity/EntityState.java
  24. +20 −0 app/src/main/java/rs/ltt/android/entity/EntityStateEntity.java
  25. +6 −0 app/src/main/java/rs/ltt/android/entity/EntityType.java
  26. +73 −0 app/src/main/java/rs/ltt/android/entity/MailboxEntity.java
  27. +88 −0 app/src/main/java/rs/ltt/android/entity/MailboxOverviewItem.java
  28. +11 −0 app/src/main/java/rs/ltt/android/entity/MailboxRightsEmbed.java
  29. +26 −0 app/src/main/java/rs/ltt/android/entity/QueryEntity.java
  30. +55 −0 app/src/main/java/rs/ltt/android/entity/QueryItemEntity.java
  31. +27 −0 app/src/main/java/rs/ltt/android/entity/ThreadEntity.java
  32. +40 −0 app/src/main/java/rs/ltt/android/entity/ThreadItemEntity.java
  33. +221 −0 app/src/main/java/rs/ltt/android/entity/ThreadOverviewItem.java
  34. +86 −0 app/src/main/java/rs/ltt/android/repository/QueryRepository.java
  35. +47 −0 app/src/main/java/rs/ltt/android/ui/AvatarDrawable.java
  36. +93 −0 app/src/main/java/rs/ltt/android/ui/MainActivity.java
  37. +118 −0 app/src/main/java/rs/ltt/android/ui/adapter/MailboxListAdapter.java
  38. +65 −0 app/src/main/java/rs/ltt/android/ui/adapter/ThreadOverviewAdapter.java
  39. +53 −0 app/src/main/java/rs/ltt/android/ui/fragment/AbstractMailboxQueryFragment.java
  40. +57 −0 app/src/main/java/rs/ltt/android/ui/fragment/AbstractQueryFragment.java
  41. +9 −0 app/src/main/java/rs/ltt/android/ui/fragment/MailboxQueryFragment.java
  42. +8 −0 app/src/main/java/rs/ltt/android/ui/fragment/MainMailboxQueryFragment.java
  43. +56 −0 app/src/main/java/rs/ltt/android/ui/model/AbstractQueryViewModel.java
  44. +27 −0 app/src/main/java/rs/ltt/android/ui/model/MailboxListViewModel.java
  45. +50 −0 app/src/main/java/rs/ltt/android/ui/model/MailboxQueryViewModel.java
  46. +24 −0 app/src/main/java/rs/ltt/android/ui/model/MailboxViewModelFactory.java
  47. +30 −0 app/src/main/java/rs/ltt/android/util/XEP0392Helper.java
  48. +28 −0 app/src/main/java/rs/ltt/android/worker/MuaWorker.java
  49. +51 −0 app/src/main/java/rs/ltt/android/worker/QueryRefreshWorker.java
  50. +27 −0 app/src/main/java/rs/ltt/android/worker/RefreshWorker.java
  51. BIN app/src/main/res/drawable-hdpi/cover.png
  52. BIN app/src/main/res/drawable-mdpi/cover.png
  53. +34 −0 app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  54. BIN app/src/main/res/drawable-xhdpi/cover.png
  55. BIN app/src/main/res/drawable-xxhdpi/cover.png
  56. BIN app/src/main/res/drawable-xxxhdpi/cover.png
  57. +9 −0 app/src/main/res/drawable/ic_archive_black_24dp.xml
  58. +9 −0 app/src/main/res/drawable/ic_delete_black_24dp.xml
  59. +9 −0 app/src/main/res/drawable/ic_drafts_black_24dp.xml
  60. +9 −0 app/src/main/res/drawable/ic_folder_black_24dp.xml
  61. +9 −0 app/src/main/res/drawable/ic_inbox_black_24dp.xml
  62. +170 −0 app/src/main/res/drawable/ic_launcher_background.xml
  63. +5 −0 app/src/main/res/drawable/ic_menu_black_24dp.xml
  64. +9 −0 app/src/main/res/drawable/ic_send_black_24dp.xml
  65. +12 −0 app/src/main/res/drawable/ic_star_black_24dp.xml
  66. +12 −0 app/src/main/res/drawable/ic_star_border_black_24dp.xml
  67. +50 −0 app/src/main/res/layout/activity_main.xml
  68. +36 −0 app/src/main/res/layout/fragment_thread_list.xml
  69. +62 −0 app/src/main/res/layout/mailbox_list_item.xml
  70. +103 −0 app/src/main/res/layout/thread_overview_item.xml
  71. +5 −0 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  72. +5 −0 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  73. BIN app/src/main/res/mipmap-hdpi/ic_launcher.png
  74. BIN app/src/main/res/mipmap-hdpi/ic_launcher_round.png
  75. BIN app/src/main/res/mipmap-mdpi/ic_launcher.png
  76. BIN app/src/main/res/mipmap-mdpi/ic_launcher_round.png
  77. BIN app/src/main/res/mipmap-xhdpi/ic_launcher.png
  78. BIN app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
  79. BIN app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  80. BIN app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  81. BIN app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  82. BIN app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  83. +39 −0 app/src/main/res/navigation/nav_graph.xml
  84. +11 −0 app/src/main/res/values/colors.xml
  85. +6 −0 app/src/main/res/values/strings.xml
  86. +12 −0 app/src/main/res/values/styles.xml
  87. +27 −0 build.gradle
  88. +16 −0 gradle.properties
  89. BIN gradle/wrapper/gradle-wrapper.jar
  90. +6 −0 gradle/wrapper/gradle-wrapper.properties
  91. +172 −0 gradlew
  92. +84 −0 gradlew.bat
  93. +1 −0 settings.gradle
@@ -0,0 +1,14 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.idea
@@ -0,0 +1 @@
/build
@@ -0,0 +1,64 @@
apply plugin: 'com.android.application'
apply plugin: "androidx.navigation.safeargs"


android {
compileSdkVersion 28
defaultConfig {
applicationId "rs.ltt.android"
minSdkVersion 17
targetSdkVersion 28
versionCode 1
versionName "0.1"

javaCompileOptions {
annotationProcessorOptions {
includeCompileClasspath false
}
}


compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}


}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

dataBinding {
enabled = true
}
}

dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0-alpha02'
implementation 'rs.ltt.jmap:jmap-mua:0.1.0'
implementation 'rs.ltt.jmap:jmap-common:0.1.0'

//room
implementation "android.arch.persistence.room:runtime:2.1.0-alpha04"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha02'
implementation 'androidx.recyclerview:recyclerview-selection:1.1.0-alpha01'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
implementation 'com.google.android.material:material:1.1.0-alpha04'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
annotationProcessor "android.arch.persistence.room:compiler:2.1.0-alpha04"
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0-alpha03'
implementation 'androidx.paging:paging-common:2.1.0'
implementation 'androidx.paging:paging-runtime:2.1.0'

implementation "androidx.navigation:navigation-fragment:2.0.0"
implementation "androidx.navigation:navigation-ui:2.0.0"
//work manager
implementation "androidx.work:work-runtime:2.0.0-rc01"

implementation 'org.hsluv:hsluv:0.2'
}
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="rs.ltt.android">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<activity android:name=".ui.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Binary file not shown.
@@ -0,0 +1,29 @@
#!/bin/env ruby

resolutions = {
'mdpi' => 1,
'hdpi' => 1.5,
'xhdpi' => 2,
'xxhdpi' => 3,
'xxxhdpi' => 4,
}

def execute_cmd(cmd)
puts cmd
system cmd
end

images = {
"cover.png" => ["cover.png", 304]
}

images.each do |source_filename, settings|

output_filename, base_size = settings

resolutions.each do |resolution, factor|
path = "../res/drawable-#{resolution}/#{output_filename}"
width = factor * base_size
execute_cmd "convert #{source_filename} -resize #{width} #{path}"
end
end
@@ -0,0 +1,12 @@
package rs.ltt.android;

public final class Credentials {

public static final String username = "";
public static final String password = "";

private Credentials() {

}

}
@@ -0,0 +1,153 @@
package rs.ltt.android.cache;

import android.util.Log;

import org.checkerframework.checker.nullness.compatqual.NonNullDecl;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import rs.ltt.android.database.LttrsDatabase;
import rs.ltt.android.entity.EntityStateEntity;
import rs.ltt.android.entity.EntityType;
import rs.ltt.android.entity.MailboxEntity;
import rs.ltt.jmap.common.entity.Email;
import rs.ltt.jmap.common.entity.IdentifiableSpecialMailbox;
import rs.ltt.jmap.common.entity.Identity;
import rs.ltt.jmap.common.entity.Mailbox;
import rs.ltt.jmap.common.entity.Thread;
import rs.ltt.jmap.common.entity.TypedState;
import rs.ltt.jmap.mua.cache.Cache;
import rs.ltt.jmap.mua.cache.CacheConflictException;
import rs.ltt.jmap.mua.cache.CacheReadException;
import rs.ltt.jmap.mua.cache.CacheWriteException;
import rs.ltt.jmap.mua.cache.Missing;
import rs.ltt.jmap.mua.cache.NotSynchronizedException;
import rs.ltt.jmap.mua.cache.ObjectsState;
import rs.ltt.jmap.mua.cache.QueryStateWrapper;
import rs.ltt.jmap.mua.cache.QueryUpdate;
import rs.ltt.jmap.mua.cache.Update;
import rs.ltt.jmap.mua.entity.QueryResultItem;

public class DatabaseCache implements Cache {


private final LttrsDatabase database;

public DatabaseCache(LttrsDatabase database) {
this.database = database;
}

@Override
public String getIdentityState() {
return null;
}

@Override
public String getMailboxState() {
return database.mailboxDao().getState(EntityType.MAILBOX);
}

@NonNullDecl
@Override
public QueryStateWrapper getQueryState(@NullableDecl String query) {
return database.stateDao().getQueryStateWrapper(query);
}

@NonNullDecl
@Override
public ObjectsState getObjectsState() {
return database.stateDao().getObjectsState();
}

@Override
public void setMailboxes(TypedState<Mailbox> mailboxTypedState, Mailbox[] mailboxes) {
final List<MailboxEntity> mailboxEntities = new ArrayList<>();
for (Mailbox mailbox : mailboxes) {
mailboxEntities.add(MailboxEntity.of(mailbox));
}
final EntityStateEntity entityState = new EntityStateEntity(EntityType.MAILBOX, mailboxTypedState.getState());
database.mailboxDao().set(mailboxEntities, entityState);
}

@Override
public void updateMailboxes(Update<Mailbox> update, String[] updatedProperties) throws CacheWriteException, CacheConflictException {
try {
database.mailboxDao().update(update, updatedProperties);
} catch (IllegalArgumentException e) {
throw new CacheWriteException(e);
}
}

@Override
public Collection<? extends IdentifiableSpecialMailbox> getSpecialMailboxes() throws NotSynchronizedException {
return database.mailboxDao().getSpecialMailboxes();
}

@Override
public void setThreads(TypedState<Thread> threadTypedState, Thread[] threads) {
final EntityStateEntity entityState = new EntityStateEntity(EntityType.THREAD, threadTypedState.getState());
database.threadDao().set(threads, entityState);
Log.d("lttrs", "saving " + threads.length + " threads");
}

@Override
public void addThreads(TypedState<Thread> threadTypedState, Thread[] threads) throws CacheConflictException {
database.threadDao().add(threadTypedState, threads);
Log.d("lttrs", "setting " + threads.length + " threads");
}

@Override
public void updateThreads(Update<Thread> update) throws CacheWriteException {
database.threadDao().update(update);
Log.d("lttrs", "updated some threads");
}

@Override
public void setEmails(TypedState<Email> emailTypedState, Email[] emails) {
database.emailDao().set(emails, new EntityStateEntity(EntityType.EMAIL, emailTypedState.getState()));
Log.d("lttrs", "setting " + emails.length + " emails");
}

@Override
public void addEmails(TypedState<Email> emailTypedState, Email[] emails) throws CacheConflictException {
database.emailDao().add(emailTypedState, emails);
Log.d("lttrs", "adding " + emails.length + " emails");
}

@Override
public void updateEmails(Update<Email> update, String[] updatedProperties) throws CacheWriteException {
database.emailDao().updateEmails(update, updatedProperties);
}

@Override
public void setIdentities(TypedState<Identity> identityTypedState, Identity[] identities) {

}

@Override
public void updateIdentities(Update<Identity> update) throws CacheWriteException {

}

@Override
public void setQueryResult(String queryString, TypedState<Email> queryState, QueryResultItem[] items, TypedState<Email> emailTypedState) {
database.queryDao().set(queryString, queryState.getState(), items, emailTypedState);
Log.d("lttrs", "setting query result for query string '" + queryString + "'");
}

@Override
public void updateQueryResults(String queryString, QueryUpdate<Email, QueryResultItem> queryUpdate, TypedState<Email> emailTypedState) throws CacheWriteException, CacheConflictException {
Log.d("lttrs", "updating query results "+queryUpdate);
database.queryDao().updateQueryResults(queryString, queryUpdate, emailTypedState);
}

@Override
public Missing getMissing(String query) throws CacheReadException {
Missing missing = database.threadDao().getMissing(query);
Log.d("lttrs", "cache reported " + missing.threadIds.size() + " missing threads");
return missing;
}
}
@@ -0,0 +1,52 @@
package rs.ltt.android.database;

import java.util.Date;

import androidx.room.TypeConverter;
import rs.ltt.android.entity.EmailAddressType;
import rs.ltt.android.entity.EntityType;
import rs.ltt.jmap.common.entity.Role;

public class Converters {


@TypeConverter
public static String toString(Role role) {
return role.toString();
}

@TypeConverter
public static Role toRole(String role) {
return Role.valueOf(role);
}

@TypeConverter
public static String toString(EntityType entityType) {
return entityType.toString();
}

@TypeConverter
public static EntityType toEntityType(String entityType) {
return EntityType.valueOf(entityType);
}

@TypeConverter
public static EmailAddressType toEmailAddressType(String type) {
return EmailAddressType.valueOf(type);
}

@TypeConverter
public static String toString(EmailAddressType type) {
return type.toString();
}

@TypeConverter
public static Date toDate(long timestamp) {
return new Date(timestamp);
}

@TypeConverter
public static long toTimestamp(Date date) {
return date.getTime();
}
}

0 comments on commit 2c1102d

Please sign in to comment.
You can’t perform that action at this time.