Merge branch 'master' of ssh://float.beyondsoft.de/git/beyondSoft/Chat

This commit is contained in:
Waldi
2017-11-06 07:17:21 +01:00
135 changed files with 6965 additions and 407 deletions

View File

@@ -1,5 +1,5 @@
def getGitSha() {
return 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim();
return 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim()
}
buildscript {
@@ -7,8 +7,8 @@ buildscript {
mavenCentral()
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'io.fabric.tools:gradle:1.+'
}
}
@@ -22,21 +22,21 @@ repositories {
maven { url "https://jitpack.io" }
}
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'realm-android'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
compileSdkVersion 26
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "de.beyondsoft.ownchat"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
minSdkVersion 19
targetSdkVersion 26
versionCode 6
versionName "1.6"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
signingConfigs {
release {
storeFile file('../ownChat.jks')
@@ -45,20 +45,24 @@ android {
keyPassword '6fhnfqm07tvbagm3t6k4'
}
}
buildTypes {
debug {
ext.enableCrashlytics = false
}
release {
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "String", "GIT_VERSION_SHA", "\"" + getGitSha() + "\""
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
abortOnError false
disable 'InvalidPackage'
@@ -79,15 +83,15 @@ dependencies {
// Glide
// Circle ImageView
compile('com.crashlytics.sdk.android:crashlytics:2.6.6@aar') {
transitive = true;
transitive = true
}
// Secure Preferences
// Firebase
// emojis
// circle progress
// event bus
compile 'com.android.support:appcompat-v7:25.3.0'
compile 'com.android.support:design:25.3.0'
compile 'com.android.support:appcompat-v7:26.1.0'
compile 'com.android.support:design:26.1.0'
compile 'com.jakewharton:butterknife:8.4.0'
compile 'com.google.dagger:dagger:2.7'
compile 'io.reactivex:rxjava:1.1.6'
@@ -96,23 +100,23 @@ dependencies {
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okhttp3:okhttp:3.7.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'de.hdodenhof:circleimageview:2.1.0'
compile 'com.scottyab:secure-preferences-lib:0.1.4'
compile 'com.google.firebase:firebase-messaging:10.2.0'
compile 'com.google.firebase:firebase-messaging:11.4.2'
compile 'hani.momanii.supernova_emoji_library:supernova-emoji-library:0.0.2'
compile 'com.github.lzyzsd:circleprogress:1.2.1'
compile 'org.greenrobot:eventbus:3.0.0'
testCompile 'junit:junit:4.12'
apt 'com.jakewharton:butterknife-compiler:8.4.0'
apt 'com.google.dagger:dagger-compiler:2.7'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
annotationProcessor 'com.google.dagger:dagger-compiler:2.7'
provided 'javax.annotation:jsr250-api:1.0'
implementation files('libs/sanselan-0_97-android-1.0.0.jar')
}
task adp2upload(type: Exec, dependsOn: "build") {
ext {
channel = "bewoplaner-chat"
slug = "bewoplaner-chat"
@@ -121,6 +125,8 @@ task adp2upload(type: Exec, dependsOn: "build") {
file = "build/outputs/apk/app-release.apk"
notes = "Nightly build for BeWoPlaner Chat"
}
commandLine 'upload_build.sh', "-c", "$channel", "-v", "$versionCode", "-p", "android", "-a", "$slug", "-f", "$file", "-i", "$identifier", "-n", "$notes"
}
apply plugin: 'com.google.gms.google-services'

View File

@@ -17,6 +17,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:launchMode="singleInstance"
android:name="de.beyondsoft.ownchat.page.splash.SplashActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.FullBackground">
@@ -27,6 +28,7 @@
</intent-filter>
</activity>
<activity
android:launchMode="singleInstance"
android:name="de.beyondsoft.ownchat.page.login.LoginActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.FullBackground" />
@@ -57,6 +59,12 @@
android:screenOrientation="portrait"
android:theme="@style/ChatStyle" />
<activity
android:name=".filepicker.FilePickerActivity"
android:configChanges="orientation|screenSize"/>
<activity android:name=".filepicker.MediaDetailsActivity"
android:configChanges="orientation|screenSize"/>
<meta-data
android:name="io.fabric.ApiKey"
android:value="1dcc8d0ead50f1b328778876834fea3392c6fc22" />
@@ -85,6 +93,18 @@
android:resource="@xml/provider_paths" />
</provider>
<provider
android:authorities="${applicationId}.provider"
android:name=".filepicker.utils.FilePickerProvider"
android:exported="false"
android:grantUriPermissions="true"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"
/>
</provider>
<receiver
android:name="de.beyondsoft.ownchat.data.firebase.ReplyNotificationReceiver"
android:enabled="true"
@@ -97,7 +117,26 @@
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorDefault" />
<activity android:name="de.beyondsoft.ownchat.page.fileconfirmation.FileConfirmationActivity"></activity>
<activity
android:name="de.beyondsoft.ownchat.page.fileconfirmation.FileConfirmationActivity"
android:label=""
android:screenOrientation="portrait"
android:theme="@style/ChatStyle"
/>
<activity
android:name=".page.sharing.SharingActivity"
android:launchMode="singleInstance"
android:label="ownChat"
android:screenOrientation="portrait"
android:theme="@style/ChatStyle">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -4,9 +4,6 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--<title>Terms</title>
-->
<style type="text/css">
body {margin:20px; font-family: "Roboto", Arial, "sans-serif"; font-size:17px; line-height:1.4em}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -18,4 +18,11 @@ public interface AppPrefsConstants {
String UPLOAD_MAX_SIZE = "upload_max_size";
String IS_EMPLOYEE = "is_employee";
String SHOW_LOGIN_AGAIN = "show_login_again";
String LAST_ACCOUNT_NO = "last_account_no";
String USER_PASSWORD = "user_password";
String USER_NAME = "user_name";
String VERIFY_CHAT_CODE_ERROR_MESSAGE = "verify_chat_code_error_message";
String IS_COMING_FROM_SHARING_ACTIVITY = "is_coming_from_sharing_activity";
String PATH_TO_FILE_TO_SHARE = "path_to_file_to_share";
}

View File

@@ -12,6 +12,7 @@ import retrofit2.http.GET;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.Path;
import retrofit2.http.Query;
import rx.Observable;
@@ -26,6 +27,9 @@ public interface ChatService {
Observable<MessagesResponse> getMessages(@Query("groupid") long groupId,
@Query("page") int page);
@GET("api/chat/message/{oid}")
Observable<MessageResponse> getMessage(@Path("oid") String messageId);
@Multipart
@POST("api/chat/messages/send")
Observable<MessageResponse> sendFile(

View File

@@ -14,12 +14,6 @@ import rx.Observable;
* Created by laszloffiferenc on 2/21/17.
*/
public interface LoginService {
@FormUrlEncoded
@POST("api/user/login")
Observable<ProfileResponse> login(
@Field("username") String username,
@Field("password") String password
);
@FormUrlEncoded
@POST("api/user/loginwithchatcode")

View File

@@ -1,4 +1,14 @@
package de.beyondsoft.ownchat.data.events;
public class LogoutDirectlyEvent {
private boolean mClearAllPrefs;
public boolean getClearAllPrefs() {
return mClearAllPrefs;
}
public LogoutDirectlyEvent(boolean clearAllPrefs) {
mClearAllPrefs = clearAllPrefs;
}
}

View File

@@ -5,6 +5,8 @@ import com.google.firebase.messaging.RemoteMessage;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.api.common.ErrorHandlingResponseConverter;
import de.beyondsoft.ownchat.data.api.services.ChatService;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
import de.beyondsoft.ownchat.data.repository.GroupRealmRepository;
import de.beyondsoft.ownchat.data.repository.MessageRealmRepository;
@@ -15,7 +17,8 @@ import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.model.Message;
import de.beyondsoft.ownchat.page.main.MainActivity;
import de.beyondsoft.ownchat.utils.Constants;
import de.beyondsoft.ownchat.utils.LoggedOutUtils;
import de.beyondsoft.ownchat.utils.rx.RxUtils;
import rx.Observable;
import android.app.Activity;
import android.app.Notification;
@@ -38,6 +41,7 @@ import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.RemoteInput;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import java.net.HttpURLConnection;
import java.net.URL;
@@ -55,6 +59,9 @@ import static de.beyondsoft.ownchat.utils.Constants.CHAT_IS_ALREADY_OPEN;
*/
public class HandleMessagesService extends FirebaseMessagingService {
@Inject
ChatService mChatService;
@Inject
MessageRealmRepository mMessageRealmRepository;
@@ -65,17 +72,10 @@ public class HandleMessagesService extends FirebaseMessagingService {
@Named(AppPrefsConstants.USER_ID)
LongPreference mUserIdReference;
@Inject
LoggedOutUtils mLoggedOutUtils;
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
InjectionHelper.getMessagingComponent(this).inject(HandleMessagesService.this);
if (mLoggedOutUtils.checkLoggedOutPrefs()) {
return;
}
customizeNotification(remoteMessage.getData());
}
@@ -93,23 +93,35 @@ public class HandleMessagesService extends FirebaseMessagingService {
}
}
private void customizeNotification(Map<String, String> data) {
Bundle bundle = new Bundle();
bundle.putString(Constants.MESSAGE_ID, data.get(Constants.MESSAGE_ID));
bundle.putLong(Constants.GROUP_ID, Long.parseLong(data.get(Constants.GROUP_ID)));
bundle.putLong(Constants.CREATED_AT, Long.parseLong(data.get(Constants.CREATED_AT)));
bundle.putString(Constants.MESSAGE_TEXT, data.get(Constants.MESSAGE_TEXT));
bundle.putString(Constants.FILE, data.get(Constants.FILE));
bundle.putString(Constants.SMALLER_IMAGE, data.get(Constants.SMALLER_IMAGE));
bundle.putString(Constants.FILENAME, data.get(Constants.FILENAME));
bundle.putLong(Constants.USER_ID, Long.parseLong(data.get(Constants.USER_ID)));
bundle.putString(Constants.USERNAME, data.get(Constants.USERNAME));
bundle.putString(Constants.USER_AVATAR, data.get(Constants.USER_AVATAR));
private void customizeNotification(Map<String, String> dataMap) {
String messageId = dataMap.get(Constants.MESSAGE_ID);
final Bitmap bitmap = getBitmapFromUrl(data.get(Constants.USER_AVATAR));
mChatService.getMessage(messageId)
.compose(RxUtils.provideDefaultTransformer())
.flatMap(new ErrorHandlingResponseConverter<>())
.flatMap(messageResponse -> Observable.just(messageResponse.response.message))
.subscribe(this::getMessageSuccess, this::getMessageError);
}
private void getMessageSuccess(Message message) {
Bundle bundle = new Bundle();
bundle.putString(Constants.MESSAGE_ID, message.id);
bundle.putLong(Constants.GROUP_ID, message.groupId);
bundle.putLong(Constants.CREATED_AT, message.createdAt);
bundle.putString(Constants.MESSAGE_TEXT, message.message);
bundle.putString(Constants.FILE, message.filePath);
bundle.putString(Constants.SMALLER_IMAGE, message.smallerImage);
bundle.putString(Constants.FILENAME, message.originalFilename);
bundle.putLong(Constants.USER_ID, message.senderId);
bundle.putString(Constants.USERNAME, message.senderName);
bundle.putString(Constants.USER_AVATAR, message.senderAvatar);
final Bitmap bitmap = getBitmapFromUrl(message.senderAvatar);
Intent intent = new Intent();
intent.putExtra(Constants.MESSAGE, bundle);
intent.setAction(Constants.NOTIFICATION_BROADCAST);
sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -117,7 +129,7 @@ public class HandleMessagesService extends FirebaseMessagingService {
if (!results.getBoolean(CHAT_IS_ALREADY_OPEN, false)) {
int groupId = (int) bundle.getLong(Constants.GROUP_ID);
int numberOfUsers = Integer.parseInt(data.get(Constants.GROUP_NR_USERS));
int numberOfUsers = message.numberOfGroupUsers;
intent = MainActivity.createIntent(context, bundle, numberOfUsers, groupId);
PendingIntent pendingIntent = PendingIntent.getActivity(context,
@@ -134,10 +146,10 @@ public class HandleMessagesService extends FirebaseMessagingService {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(getNotificationIcon())
.setContentTitle(setNotificationTitle(data, numberOfUsers))
.setContentText(getTextFromNotification(data))
.setContentTitle(setNotificationTitle(message, message.numberOfGroupUsers))
.setContentText(getTextFromNotification(message))
.setAutoCancel(true)
.setStyle(new NotificationCompat.BigTextStyle().bigText(getTextFromNotification(data)))
.setStyle(new NotificationCompat.BigTextStyle().bigText(getTextFromNotification(message)))
.setPriority(Notification.PRIORITY_MAX)
.setContentIntent(pendingIntent)
.setLargeIcon(getCircleBitmap(bitmapToDisplay))
@@ -175,6 +187,10 @@ public class HandleMessagesService extends FirebaseMessagingService {
}, null, Activity.RESULT_OK, null, null);
}
private void getMessageError(Throwable throwable) {
throwable.printStackTrace();
}
private Bitmap getCircleBitmap(Bitmap bitmap) {
final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Bitmap.Config.ARGB_8888);
@@ -211,11 +227,11 @@ public class HandleMessagesService extends FirebaseMessagingService {
mMessageRealmRepository.update(Collections.singletonList(message), messageByIdSpecification).subscribe();
}
private String setNotificationTitle(Map<String, String> data, int numberOfUsers) {
private String setNotificationTitle(Message message, int numberOfUsers) {
if (numberOfUsers > 2) {
return String.valueOf(data.get(Constants.USERNAME) + " @ " + data.get(Constants.GROUP_NAME));
return message.senderName + " @ " + message.groupName;
} else {
return String.valueOf(data.get(Constants.USERNAME));
return message.senderName;
}
}
@@ -224,6 +240,7 @@ public class HandleMessagesService extends FirebaseMessagingService {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return null;
}
Intent replyIntent = ReplyNotificationReceiver.createReplyIntent(context, bundle, noOfUsers, groupId);
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
@@ -242,15 +259,18 @@ public class HandleMessagesService extends FirebaseMessagingService {
.build();
}
private String getTextFromNotification(Map<String, String> data) {
String message = null;
if (data.get(Constants.MESSAGE_TEXT) != null) {
message = String.valueOf(data.get(Constants.MESSAGE_TEXT));
private String getTextFromNotification(Message message) {
String text = null;
if(message.message != null) {
text = message.message;
}
if (!data.get(Constants.FILE).equals("")) {
message = getString(R.string.chat_file_received);
if(!TextUtils.isEmpty(message.originalFilename)) {
text = getString(R.string.chat_file_received);
}
return message;
return text;
}
public static int getNotificationIcon() {
@@ -260,9 +280,11 @@ public class HandleMessagesService extends FirebaseMessagingService {
public static CharSequence getReplyMessage(Intent intent) {
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput != null) {
return remoteInput.getCharSequence(Constants.KEY_TEXT_REPLY);
}
return null;
}
}

View File

@@ -8,6 +8,7 @@ import com.securepreferences.SecurePreferences;
import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings;
import javax.inject.Named;
@@ -54,6 +55,41 @@ public class AppPrefsModule {
return new BooleanPreference(sharedPreferences, AppPrefsConstants.SAVE_PASSWORD);
}
@Provides
@ApplicationScope
@Named(AppPrefsConstants.IS_COMING_FROM_SHARING_ACTIVITY)
BooleanPreference provideIsComingFromSharingActivity(@AppPrefs SecurePreferences sharedPreferences) {
return new BooleanPreference(sharedPreferences, AppPrefsConstants.IS_COMING_FROM_SHARING_ACTIVITY);
}
@Provides
@ApplicationScope
@Named(AppPrefsConstants.PATH_TO_FILE_TO_SHARE)
StringPreference providePathToFileToShare(@AppPrefs SecurePreferences sharedPreferences) {
return new StringPreference(sharedPreferences, AppPrefsConstants.PATH_TO_FILE_TO_SHARE);
}
@Provides
@ApplicationScope
@Named(AppPrefsConstants.VERIFY_CHAT_CODE_ERROR_MESSAGE)
StringPreference provideVerifyChatCodeErrorMessage(@AppPrefs SecurePreferences sharedPreferences) {
return new StringPreference(sharedPreferences, AppPrefsConstants.VERIFY_CHAT_CODE_ERROR_MESSAGE);
}
@Provides
@ApplicationScope
@Named(AppPrefsConstants.USER_NAME)
StringPreference provideUserName(@AppPrefs SecurePreferences sharedPreferences) {
return new StringPreference(sharedPreferences, AppPrefsConstants.USER_NAME);
}
@Provides
@ApplicationScope
@Named(AppPrefsConstants.USER_PASSWORD)
StringPreference providePassword(@AppPrefs SecurePreferences sharedPreferences) {
return new StringPreference(sharedPreferences, AppPrefsConstants.USER_PASSWORD);
}
@Provides
@ApplicationScope
@Named(AppPrefsConstants.CHAT_CODE)
@@ -68,6 +104,13 @@ public class AppPrefsModule {
return new StringPreference(sharedPreferences, AppPrefsConstants.ACCOUNT_NO);
}
@Provides
@ApplicationScope
@Named(AppPrefsConstants.LAST_ACCOUNT_NO)
StringPreference provideLastAccountNumber(@AppPrefs SecurePreferences sharedPreferences) {
return new StringPreference(sharedPreferences, AppPrefsConstants.LAST_ACCOUNT_NO);
}
@Provides
@ApplicationScope
@Named(AppPrefsConstants.USER_ID)

View File

@@ -58,6 +58,9 @@ public interface ApplicationComponent {
@Named(AppPrefsConstants.ACCOUNT_NO)
StringPreference provideAccountNumber();
@Named(AppPrefsConstants.LAST_ACCOUNT_NO)
StringPreference provideLastAccountNumber();
@Named(AppPrefsConstants.USER_ID)
LongPreference provideUserId();
@@ -85,6 +88,21 @@ public interface ApplicationComponent {
@Named(AppPrefsConstants.SHOW_LOGIN_AGAIN)
BooleanPreference provideShowLoginAgain();
@Named(AppPrefsConstants.USER_NAME)
StringPreference provideUserName();
@Named(AppPrefsConstants.VERIFY_CHAT_CODE_ERROR_MESSAGE)
StringPreference provideVerifyChatCodeErrorMessage();
@Named(AppPrefsConstants.USER_PASSWORD)
StringPreference providePassword();
@Named(AppPrefsConstants.PATH_TO_FILE_TO_SHARE)
StringPreference providePathToFileToShare();
@Named(AppPrefsConstants.IS_COMING_FROM_SHARING_ACTIVITY)
BooleanPreference provideIsComingFromSharingActivity();
NotificationManager provideNotificationManager();
GroupRealmRepository provideGroupRealmRepository();

View File

@@ -15,6 +15,8 @@ import de.beyondsoft.ownchat.page.main.DaggerMainComponent;
import de.beyondsoft.ownchat.page.main.MainComponent;
import de.beyondsoft.ownchat.page.profile.DaggerProfileComponent;
import de.beyondsoft.ownchat.page.profile.ProfileComponent;
import de.beyondsoft.ownchat.page.sharing.DaggerSharingComponent;
import de.beyondsoft.ownchat.page.sharing.SharingComponent;
import de.beyondsoft.ownchat.page.splash.DaggerSplashComponent;
import de.beyondsoft.ownchat.page.splash.SplashComponent;
@@ -33,11 +35,22 @@ public class InjectionHelper {
private static ChatComponent sChatComponent;
private static ProfileComponent sProfileComponent;
private static FileConfirmationComponent sFileConfirmationComponent;
private static SharingComponent sSharingComponent;
public static ApplicationComponent getApplicationComponent(Context context) {
return ((BewoplanerApplication) context.getApplicationContext()).getApplicationComponent();
}
public static SharingComponent getSharingComponent(Context context) {
if(sSharingComponent == null) {
sSharingComponent = DaggerSharingComponent.builder()
.applicationComponent(getApplicationComponent(context))
.build();
}
return sSharingComponent;
}
public static SplashComponent getSplashComponent(Context context) {
if (sSplashComponent == null) {
sSplashComponent = DaggerSplashComponent.builder()

View File

@@ -0,0 +1,33 @@
package de.beyondsoft.ownchat.filepicker;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import de.beyondsoft.ownchat.filepicker.utils.Orientation;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public abstract class BaseFilePickerActivity extends AppCompatActivity {
protected void onCreate(@Nullable Bundle savedInstanceState, @LayoutRes int layout) {
super.onCreate(savedInstanceState);
setContentView(layout);
Orientation orientation = PickerManager.getInstance().getOrientation();
if(orientation==Orientation.PORTRAIT_ONLY) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else if(orientation== Orientation.LANDSCAPE_ONLY) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
initView();
}
protected abstract void initView();
}

View File

@@ -0,0 +1,170 @@
package de.beyondsoft.ownchat.filepicker;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.view.Menu;
import android.view.MenuItem;
import java.util.ArrayList;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.fragments.DocFragment;
import de.beyondsoft.ownchat.filepicker.fragments.DocPickerFragment;
import de.beyondsoft.ownchat.filepicker.fragments.ImagePickerFragmentListener;
import de.beyondsoft.ownchat.filepicker.fragments.MediaPickerFragment;
import de.beyondsoft.ownchat.filepicker.utils.FragmentUtil;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class FilePickerActivity extends BaseFilePickerActivity implements
ImagePickerFragmentListener,
DocFragment.DocFragmentListener,
DocPickerFragment.DocPickerFragmentListener,
MediaPickerFragment.MediaPickerFragmentListener {
private static final String TAG = FilePickerActivity.class.getSimpleName();
private int type;
@SuppressLint("MissingSuperCall")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.activity_file_picker);
}
@Override
protected void initView() {
Intent intent = getIntent();
if (intent != null) {
if(getSupportActionBar()!=null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
ArrayList<String> selectedPaths = intent.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_MEDIA);
type = intent.getIntExtra(FilePickerConst.EXTRA_PICKER_TYPE, FilePickerConst.MEDIA_PICKER);
if(selectedPaths!=null) {
if (PickerManager.getInstance().getMaxCount() == 1) {
selectedPaths.clear();
}
if (type == FilePickerConst.MEDIA_PICKER) {
PickerManager.getInstance().add(selectedPaths, FilePickerConst.FILE_TYPE_MEDIA);
} else {
PickerManager.getInstance().add(selectedPaths, FilePickerConst.FILE_TYPE_DOCUMENT);
}
}
else
selectedPaths = new ArrayList<>();
setToolbarTitle(PickerManager.getInstance().getCurrentCount());
openSpecificFragment(type, selectedPaths);
}
}
private void openSpecificFragment(int type, @Nullable ArrayList<String> selectedPaths) {
if (type == FilePickerConst.MEDIA_PICKER) {
MediaPickerFragment photoFragment = MediaPickerFragment.newInstance();
FragmentUtil.addFragment(this, R.id.container, photoFragment);
} else {
if(PickerManager.getInstance().isDocSupport())
PickerManager.getInstance().addDocTypes();
DocPickerFragment photoFragment = DocPickerFragment.newInstance(selectedPaths);
FragmentUtil.addFragment(this, R.id.container, photoFragment);
}
}
private void setToolbarTitle(int count) {
ActionBar actionBar = getSupportActionBar();
if(actionBar!=null) {
if (PickerManager.getInstance().getMaxCount() > 1)
actionBar.setTitle(String.format(getString(R.string.attachments_title_text), count, PickerManager.getInstance().getMaxCount()));
else {
if (type == FilePickerConst.MEDIA_PICKER)
actionBar.setTitle(R.string.select_photo_text);
else
actionBar.setTitle(R.string.select_doc_text);
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.picker_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int i = item.getItemId();
if (i == R.id.action_done) {
if (type == FilePickerConst.MEDIA_PICKER)
returnData(PickerManager.getInstance().getSelectedPhotos());
else
returnData(PickerManager.getInstance().getSelectedFiles());
return true;
} else if (i == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
super.onBackPressed();
setResult(RESULT_CANCELED);
finish();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode)
{
case FilePickerConst.REQUEST_CODE_MEDIA_DETAIL:
if(resultCode== Activity.RESULT_OK)
{
if (type == FilePickerConst.MEDIA_PICKER)
returnData(PickerManager.getInstance().getSelectedPhotos());
else
returnData(PickerManager.getInstance().getSelectedFiles());
}
else
{
setToolbarTitle(PickerManager.getInstance().getCurrentCount());
}
break;
}
}
private void returnData(ArrayList<String> paths) {
Intent intent = new Intent();
if (type == FilePickerConst.MEDIA_PICKER) {
intent.putStringArrayListExtra(FilePickerConst.KEY_SELECTED_MEDIA, paths);
} else {
intent.putStringArrayListExtra(FilePickerConst.KEY_SELECTED_DOCS, paths);
}
setResult(RESULT_OK, intent);
finish();
}
@Override
public void onItemSelected() {
setToolbarTitle(PickerManager.getInstance().getCurrentCount());
if(PickerManager.getInstance().getMaxCount()==1)
returnData(type == FilePickerConst.MEDIA_PICKER ? PickerManager.getInstance().getSelectedPhotos() : PickerManager.getInstance().getSelectedFiles());
}
}

View File

@@ -0,0 +1,157 @@
package de.beyondsoft.ownchat.filepicker;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.DrawableRes;
import android.support.v4.app.Fragment;
import java.util.ArrayList;
import de.beyondsoft.ownchat.filepicker.models.FileType;
import de.beyondsoft.ownchat.filepicker.utils.Orientation;
/**
* Created by Lyndon on 27-Oct-2017.
*/
public class FilePickerBuilder {
private final Bundle mPickerOptionsBundle;
public FilePickerBuilder()
{
mPickerOptionsBundle = new Bundle();
}
public static FilePickerBuilder getInstance()
{
return new FilePickerBuilder();
}
public FilePickerBuilder setMaxCount(int maxCount)
{
PickerManager.getInstance().setMaxCount(maxCount);
return this;
}
public FilePickerBuilder setActivityTheme(int theme)
{
PickerManager.getInstance().setTheme(theme);
return this;
}
public FilePickerBuilder setSelectedFiles(ArrayList<String> selectedPhotos)
{
mPickerOptionsBundle.putStringArrayList(FilePickerConst.KEY_SELECTED_MEDIA, selectedPhotos);
return this;
}
public FilePickerBuilder enableVideoPicker(boolean status)
{
PickerManager.getInstance().setShowVideos(status);
return this;
}
public FilePickerBuilder enableImagePicker(boolean status)
{
PickerManager.getInstance().setShowImages(status);
return this;
}
public FilePickerBuilder setCameraPlaceholder(@DrawableRes int drawable)
{
PickerManager.getInstance().setCameraDrawable(drawable);
return this;
}
public FilePickerBuilder showGifs(boolean status)
{
PickerManager.getInstance().setShowGif(status);
return this;
}
public FilePickerBuilder showFolderView(boolean status)
{
PickerManager.getInstance().setShowFolderView(status);
return this;
}
public FilePickerBuilder enableDocSupport(boolean status)
{
PickerManager.getInstance().setDocSupport(status);
return this;
}
public FilePickerBuilder enableCameraSupport(boolean status)
{
PickerManager.getInstance().setEnableCamera(status);
return this;
}
public FilePickerBuilder withOrientation(Orientation orientation)
{
PickerManager.getInstance().setOrientation(orientation);
return this;
}
public FilePickerBuilder addFileSupport(String title, String[] extensions, @DrawableRes int drawable)
{
PickerManager.getInstance().addFileType(new FileType(title,extensions,drawable));
return this;
}
public FilePickerBuilder addFileSupport(String title, String[] extensions)
{
PickerManager.getInstance().addFileType(new FileType(title,extensions,0));
return this;
}
public void pickPhoto(Activity context)
{
mPickerOptionsBundle.putInt(FilePickerConst.EXTRA_PICKER_TYPE,FilePickerConst.MEDIA_PICKER);
start(context,FilePickerConst.MEDIA_PICKER);
}
public void pickPhoto(Fragment context)
{
mPickerOptionsBundle.putInt(FilePickerConst.EXTRA_PICKER_TYPE,FilePickerConst.MEDIA_PICKER);
start(context,FilePickerConst.MEDIA_PICKER);
}
public void pickFile(Activity context)
{
mPickerOptionsBundle.putInt(FilePickerConst.EXTRA_PICKER_TYPE,FilePickerConst.DOC_PICKER);
start(context,FilePickerConst.DOC_PICKER);
}
public void pickFile(Fragment context)
{
mPickerOptionsBundle.putInt(FilePickerConst.EXTRA_PICKER_TYPE,FilePickerConst.DOC_PICKER);
start(context,FilePickerConst.DOC_PICKER);
}
private void start(Activity context, int pickerType)
{
PickerManager.getInstance().setProviderAuthorities(context.getApplicationContext().getPackageName() + ".droidninja.filepicker.provider");
Intent intent = new Intent(context, FilePickerActivity.class);
intent.putExtras(mPickerOptionsBundle);
if(pickerType==FilePickerConst.MEDIA_PICKER)
context.startActivityForResult(intent,FilePickerConst.REQUEST_CODE_PHOTO);
else
context.startActivityForResult(intent,FilePickerConst.REQUEST_CODE_DOC);
}
private void start(Fragment fragment, int pickerType)
{
PickerManager.getInstance().setProviderAuthorities(fragment.getContext().getApplicationContext().getPackageName() + ".droidninja.filepicker.provider");
Intent intent = new Intent(fragment.getActivity(), FilePickerActivity.class);
intent.putExtras(mPickerOptionsBundle);
if(pickerType==FilePickerConst.MEDIA_PICKER)
fragment.startActivityForResult(intent,FilePickerConst.REQUEST_CODE_PHOTO);
else
fragment.startActivityForResult(intent,FilePickerConst.REQUEST_CODE_DOC);
}
}

View File

@@ -0,0 +1,49 @@
package de.beyondsoft.ownchat.filepicker;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class FilePickerConst {
public static final int REQUEST_CODE_PHOTO = 233;
public static final int REQUEST_CODE_DOC = 234;
public static final int REQUEST_CODE_MEDIA_DETAIL = 235;
final static int DEFAULT_MAX_COUNT = 9;
public final static int DEFAULT_COLUMN_NUMBER = 3;
public final static int MEDIA_PICKER = 0x11;
public final static int DOC_PICKER = 0x12;
public final static String KEY_SELECTED_MEDIA = "SELECTED_PHOTOS";
public final static String KEY_SELECTED_DOCS = "SELECTED_DOCS";
public final static String EXTRA_PICKER_TYPE = "EXTRA_PICKER_TYPE";
public final static String EXTRA_SHOW_GIF = "SHOW_GIF";
public final static String EXTRA_FILE_TYPE = "EXTRA_FILE_TYPE";
public final static String EXTRA_BUCKET_ID = "EXTRA_BUCKET_ID";
public final static String ALL_PHOTOS_BUCKET_ID = "ALL_PHOTOS_BUCKET_ID";
public final static String PPT_MIME_TYPE = "application/mspowerpoint";
public final static int FILE_TYPE_MEDIA = 1;
public final static int FILE_TYPE_DOCUMENT = 2;
public final static int MEDIA_TYPE_IMAGE=1;
public final static int MEDIA_TYPE_VIDEO=3;
public enum FILE_TYPE {
PDF,
WORD,
EXCEL,
PPT,
TXT,
UNKNOWN
}
final static String PDF = "PDF";
final static String PPT = "PPT";
final static String DOC = "DOC";
final static String XLS = "XLS";
final static String TXT = "TXT";
}

View File

@@ -0,0 +1,194 @@
package de.beyondsoft.ownchat.filepicker;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.adapters.FileAdapterListener;
import de.beyondsoft.ownchat.filepicker.adapters.ImageGridAdapter;
import de.beyondsoft.ownchat.filepicker.models.ImageDirectory;
import de.beyondsoft.ownchat.filepicker.models.Media;
import de.beyondsoft.ownchat.filepicker.utils.AndroidLifecycleUtils;
import de.beyondsoft.ownchat.filepicker.utils.MediaStoreHelper;
/**
* Created by Lyndon on 27-Oct-2017.
*/
public class MediaDetailsActivity extends BaseFilePickerActivity implements FileAdapterListener {
private static final int SCROLL_THRESHOLD = 30;
private RecyclerView recyclerView;
private TextView emptyView;
private RequestManager mGlideRequestManager;
private ImageGridAdapter photoGridAdapter;
private int fileType;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.activity_media_details);
}
@Override
protected void initView() {
mGlideRequestManager = Glide.with(this);
Intent intent = getIntent();
if (intent != null) {
fileType = intent.getIntExtra(FilePickerConst.EXTRA_FILE_TYPE,FilePickerConst.MEDIA_TYPE_IMAGE);
ImageDirectory photoDirectory = intent.getParcelableExtra(ImageDirectory.class.getSimpleName());
if(photoDirectory!=null) {
setUpView(photoDirectory);
if(getSupportActionBar()!=null)
{
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(photoDirectory.getName());
}
}
}
}
private void setUpView(ImageDirectory photoDirectory) {
recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
emptyView = (TextView) findViewById(R.id.empty_view);
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, OrientationHelper.VERTICAL);
layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// Log.d(">>> Picker >>>", "dy = " + dy);
if (Math.abs(dy) > SCROLL_THRESHOLD) {
mGlideRequestManager.pauseRequests();
} else {
resumeRequestsIfNotDestroyed();
}
}
@Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
resumeRequestsIfNotDestroyed();
}
}
});
getDataFromMedia(photoDirectory.getBucketId());
}
private void getDataFromMedia(String bucketId) {
Bundle mediaStoreArgs = new Bundle();
mediaStoreArgs.putBoolean(FilePickerConst.EXTRA_SHOW_GIF, false);
mediaStoreArgs.putString(FilePickerConst.EXTRA_BUCKET_ID, bucketId);
mediaStoreArgs.putInt(FilePickerConst.EXTRA_FILE_TYPE, fileType);
if(fileType==FilePickerConst.MEDIA_TYPE_IMAGE) {
MediaStoreHelper.getPhotoDirs(this, mediaStoreArgs,
dirs -> updateList(dirs));
}
else if(fileType==FilePickerConst.MEDIA_TYPE_VIDEO)
{
MediaStoreHelper.getVideoDirs(this, mediaStoreArgs,
dirs -> updateList(dirs));
}
}
private void updateList(List<ImageDirectory> dirs) {
ArrayList<Media> medias = new ArrayList<>();
for (int i = 0; i < dirs.size(); i++) {
medias.addAll(dirs.get(i).getMedias());
}
Collections.sort(medias,new Comparator<Media>() {
@Override
public int compare(Media a, Media b) {
return b.getId() - a.getId();
}
});
if(medias.size()>0) {
emptyView.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}
else {
emptyView.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
return;
}
if(photoGridAdapter!=null)
{
photoGridAdapter.setData(medias);
photoGridAdapter.notifyDataSetChanged();
}
else
{
photoGridAdapter = new ImageGridAdapter(this, mGlideRequestManager, (ArrayList<Media>) medias,PickerManager.getInstance().getSelectedPhotos(),false, this);
recyclerView.setAdapter(photoGridAdapter);
}
}
private void resumeRequestsIfNotDestroyed() {
if (!AndroidLifecycleUtils.canLoadImage(this)) {
return;
}
mGlideRequestManager.resumeRequests();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.picker_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int i = item.getItemId();
if (i == R.id.action_done) {
setResult(RESULT_OK, null);
finish();
return true;
} else if (i == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onItemSelected() {
if(PickerManager.getInstance().getMaxCount()==1) {
setResult(RESULT_OK, null);
finish();
}
}
@Override
public void onBackPressed() {
setResult(RESULT_CANCELED, null);
finish();
}
}

View File

@@ -0,0 +1,234 @@
package de.beyondsoft.ownchat.filepicker;
import java.util.ArrayList;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.models.BaseFile;
import de.beyondsoft.ownchat.filepicker.models.FileType;
import de.beyondsoft.ownchat.filepicker.utils.Orientation;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class PickerManager {
private static PickerManager mInstance = new PickerManager();
private int mMaxCount = FilePickerConst.DEFAULT_MAX_COUNT;
private int mCurrentCount;
private boolean mShowImages = true;
private int mCameraDrawble = R.drawable.orca_attach_camera_normal;
public static PickerManager getInstance() {
return mInstance;
}
private ArrayList<String> mediaFiles;
private ArrayList<String> docFiles;
private ArrayList<FileType> fileTypes;
private int theme = R.style.AppTheme;
private boolean showVideos;
private boolean showGif;
private boolean docSupport = true;
private boolean enableCamera = true;
private Orientation orientation = Orientation.UNSPECIFIED;
private boolean showFolderView = true;
private String providerAuthorities;
private PickerManager() {
mediaFiles = new ArrayList<>();
docFiles = new ArrayList<>();
fileTypes = new ArrayList<>();
}
void setMaxCount(int count) {
clearSelections();
this.mMaxCount = count;
}
public int getMaxCount() {
return mMaxCount;
}
int getCurrentCount() {
return mCurrentCount;
}
public void add(String path, int type) {
if (path != null && shouldAdd()) {
if (!mediaFiles.contains(path) && type == FilePickerConst.FILE_TYPE_MEDIA) {
mediaFiles.add(path);
} else if (type == FilePickerConst.FILE_TYPE_DOCUMENT) {
docFiles.add(path);
} else {
return;
}
mCurrentCount++;
}
}
public void add(ArrayList<String> paths, int type) {
for (int index = 0; index < paths.size(); index++) {
add(paths.get(index), type);
}
}
public void remove(String path, int type) {
if ((type == FilePickerConst.FILE_TYPE_MEDIA) && mediaFiles.contains(path)) {
mediaFiles.remove(path);
mCurrentCount--;
} else if (type == FilePickerConst.FILE_TYPE_DOCUMENT) {
docFiles.remove(path);
mCurrentCount--;
}
}
public boolean shouldAdd() {
return mCurrentCount < mMaxCount;
}
public ArrayList<String> getSelectedPhotos() {
return mediaFiles;
}
public ArrayList<String> getSelectedFiles() {
return docFiles;
}
public ArrayList<String> getSelectedFilePaths(ArrayList<BaseFile> files) {
ArrayList<String> paths = new ArrayList<>();
for (int index = 0; index < files.size(); index++) {
paths.add(files.get(index).getPath());
}
return paths;
}
private void clearSelections() {
docFiles.clear();
mediaFiles.clear();
fileTypes.clear();
mCurrentCount = 0;
mMaxCount = 0;
}
public int getTheme() {
return theme;
}
void setTheme(int theme) {
this.theme = theme;
}
public boolean showVideo() {
return showVideos;
}
void setShowVideos(boolean showVideos) {
this.showVideos = showVideos;
}
public boolean showImages() {
return mShowImages;
}
void setShowImages(boolean showImages) {
this.mShowImages = showImages;
}
public boolean isShowGif() {
return showGif;
}
void setShowGif(boolean showGif) {
this.showGif = showGif;
}
public boolean isShowFolderView() {
return showFolderView;
}
void setShowFolderView(boolean showFolderView) {
this.showFolderView = showFolderView;
}
void addFileType(FileType fileType)
{
fileTypes.add(fileType);
}
void addDocTypes()
{
String[] pdfs = {"pdf"};
fileTypes.add(new FileType(FilePickerConst.PDF,pdfs,R.drawable.document));
String[] docs = {"doc","docx", "dot","dotx"};
fileTypes.add(new FileType(FilePickerConst.DOC,docs,R.drawable.document));
String[] ppts = {"ppt","pptx"};
fileTypes.add(new FileType(FilePickerConst.PPT,ppts,R.drawable.document));
String[] xlss = {"xls","xlsx"};
fileTypes.add(new FileType(FilePickerConst.XLS,xlss,R.drawable.document));
String[] txts = {"txt"};
fileTypes.add(new FileType(FilePickerConst.TXT,txts,R.drawable.document));
}
public ArrayList<FileType> getFileTypes()
{
return fileTypes;
}
boolean isDocSupport() {
return docSupport;
}
void setDocSupport(boolean docSupport) {
this.docSupport = docSupport;
}
public boolean isEnableCamera() {
return enableCamera;
}
void setEnableCamera(boolean enableCamera) {
this.enableCamera = enableCamera;
}
public Orientation getOrientation() {
return orientation;
}
public void setOrientation(Orientation orientation) {
this.orientation = orientation;
}
public String getProviderAuthorities() {
return providerAuthorities;
}
void setProviderAuthorities(String providerAuthorities) {
this.providerAuthorities = providerAuthorities;
}
void setCameraDrawable(int drawable) {
this.mCameraDrawble = drawable;
}
public int getCameraDrawable()
{
return mCameraDrawble;
}
}

View File

@@ -0,0 +1,9 @@
package de.beyondsoft.ownchat.filepicker.adapters;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public interface FileAdapterListener {
void onItemSelected();
}

View File

@@ -0,0 +1,122 @@
package de.beyondsoft.ownchat.filepicker.adapters;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.format.Formatter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
import de.beyondsoft.ownchat.filepicker.PickerManager;
import de.beyondsoft.ownchat.filepicker.models.Document;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class FileListAdapter extends SelectableAdapter<FileListAdapter.FileViewHolder, Document> {
private final Context context;
private final FileAdapterListener mListener;
public FileListAdapter(Context context, List<Document> items, List<String> selectedPaths, FileAdapterListener fileAdapterListener) {
super(items, selectedPaths);
this.context = context;
this.mListener = fileAdapterListener;
}
@Override
public FileViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.item_doc_layout, parent, false);
return new FileViewHolder(itemView);
}
@Override
public void onBindViewHolder(final FileViewHolder holder, int position) {
final Document document = getItems().get(position);
holder.imageView.setImageResource(document.getFileType().getDrawable());
holder.fileNameTextView.setText(document.getTitle());
holder.fileSizeTextView.setText(Formatter.formatShortFileSize(context, Long.parseLong(document.getSize())));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onItemClicked(document,holder);
}
});
holder.checkBox.setOnCheckedChangeListener(null);
holder.checkBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemClicked(document,holder);
}
});
holder.checkBox.setChecked(isSelected(document));
holder.itemView.setBackgroundResource(isSelected(document) ? R.color.colorLeftChat : android.R.color.white);
holder.checkBox.setVisibility(isSelected(document) ? View.VISIBLE : View.GONE);
holder.checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
toggleSelection(document);
holder.itemView.setBackgroundResource(isChecked ? R.color.colorLeftChat : android.R.color.white);
if(mListener!=null) {
mListener.onItemSelected();
}
});
}
private void onItemClicked(Document document, FileViewHolder holder)
{
if(PickerManager.getInstance().getMaxCount()==1)
{
PickerManager.getInstance().add(document.getPath(), FilePickerConst.FILE_TYPE_DOCUMENT);
if(mListener!=null)
mListener.onItemSelected();
}
else {
if (holder.checkBox.isChecked()) {
PickerManager.getInstance().remove(document.getPath(), FilePickerConst.FILE_TYPE_DOCUMENT);
holder.checkBox.setChecked(!holder.checkBox.isChecked());
holder.checkBox.setVisibility(View.GONE);
} else if (PickerManager.getInstance().shouldAdd()) {
PickerManager.getInstance().add(document.getPath(), FilePickerConst.FILE_TYPE_DOCUMENT);
holder.checkBox.setChecked(!holder.checkBox.isChecked());
holder.checkBox.setVisibility(View.VISIBLE);
}
}
}
@Override
public int getItemCount() {
return getItems().size();
}
public static class FileViewHolder extends RecyclerView.ViewHolder {
CheckBox checkBox;
ImageView imageView;
TextView fileNameTextView;
TextView fileSizeTextView;
public FileViewHolder(View itemView) {
super(itemView);
checkBox = (CheckBox) itemView.findViewById(R.id.checkbox);
imageView = (ImageView) itemView.findViewById(R.id.file_iv);
fileNameTextView = (TextView) itemView.findViewById(R.id.file_name_tv);
fileSizeTextView = (TextView) itemView.findViewById(R.id.file_size_tv);
}
}
}

View File

@@ -0,0 +1,144 @@
package de.beyondsoft.ownchat.filepicker.adapters;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.RequestManager;
import java.io.File;
import java.util.ArrayList;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.PickerManager;
import de.beyondsoft.ownchat.filepicker.models.ImageDirectory;
import de.beyondsoft.ownchat.filepicker.utils.AndroidLifecycleUtils;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class FolderGridAdapter extends SelectableAdapter<FolderGridAdapter.ImageViewHolder, ImageDirectory> {
private final Context context;
private final RequestManager glide;
private final boolean showCamera;
private int imageSize;
public final static int ITEM_TYPE_CAMERA = 100;
public final static int ITEM_TYPE_PHOTO = 101;
private FolderGridAdapterListener folderGridAdapterListener;
public interface FolderGridAdapterListener{
void onCameraClicked();
void onFolderClicked(ImageDirectory photoDirectory);
}
public FolderGridAdapter(Context context, RequestManager requestManager, ArrayList<ImageDirectory> photos, ArrayList<String> selectedPaths, boolean showCamera)
{
super(photos, selectedPaths);
this.context = context;
this.glide = requestManager;
this.showCamera = showCamera;
setColumnNumber(context,3);
}
@Override
public ImageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.item_folder_layout, parent, false);
return new ImageViewHolder(itemView);
}
@Override
public int getItemViewType(int position) {
if(showCamera)
return (position == 0) ? ITEM_TYPE_CAMERA : ITEM_TYPE_PHOTO;
else
return ITEM_TYPE_PHOTO;
}
@Override
public void onBindViewHolder(final ImageViewHolder holder, int position) {
if(getItemViewType(position) == ITEM_TYPE_PHOTO) {
final ImageDirectory photoDirectory = getItems().get(showCamera?position-1:position);
if(AndroidLifecycleUtils.canLoadImage(holder.imageView.getContext())) {
glide.load(new File(photoDirectory.getCoverPath()))
.override(imageSize, imageSize)
.fallback(R.drawable.document)
.thumbnail(0.5f)
.into(holder.imageView);
}
holder.folderTitle.setText(photoDirectory.getName());
holder.folderCount.setText(String.valueOf(photoDirectory.getMedias().size()));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(folderGridAdapterListener!=null) {
folderGridAdapterListener.onFolderClicked(photoDirectory);
}
}
});
holder.bottomOverlay.setVisibility(View.VISIBLE);
}
else
{
holder.imageView.setImageResource(PickerManager.getInstance().getCameraDrawable());
holder.itemView.setOnClickListener(view -> {
if(folderGridAdapterListener!=null) {
folderGridAdapterListener.onCameraClicked();
}
});
holder.bottomOverlay.setVisibility(View.GONE);
}
}
private void setColumnNumber(Context context, int columnNum) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
int widthPixels = metrics.widthPixels;
imageSize = widthPixels / columnNum;
}
@Override
public int getItemCount() {
if(showCamera)
return getItems().size()+1;
return getItems().size();
}
public void setFolderGridAdapterListener(FolderGridAdapterListener onClickListener)
{
this.folderGridAdapterListener = onClickListener;
}
static class ImageViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView folderTitle;
TextView folderCount;
View bottomOverlay;
View selectBg;
ImageViewHolder(View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.iv_photo);
folderTitle = itemView.findViewById(R.id.folder_title);
folderCount = itemView.findViewById(R.id.folder_count);
bottomOverlay = itemView.findViewById(R.id.bottomOverlay);
selectBg = itemView.findViewById(R.id.transparent_bg);
}
}
}

View File

@@ -0,0 +1,184 @@
package de.beyondsoft.ownchat.filepicker.adapters;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.ImageView;
import com.bumptech.glide.RequestManager;
import java.io.File;
import java.util.ArrayList;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
import de.beyondsoft.ownchat.filepicker.PickerManager;
import de.beyondsoft.ownchat.filepicker.models.Media;
import de.beyondsoft.ownchat.filepicker.utils.AndroidLifecycleUtils;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class ImageGridAdapter extends SelectableAdapter<ImageGridAdapter.ImageViewHolder, Media> {
private final Context context;
private final RequestManager glide;
private final boolean showCamera;
private final FileAdapterListener mListener;
private int imageSize;
public final static int ITEM_TYPE_CAMERA = 100;
public final static int ITEM_TYPE_PHOTO = 101;
private View.OnClickListener cameraOnClickListener;
public ImageGridAdapter(Context context,
RequestManager requestManager,
ArrayList<Media> medias,
ArrayList<String> selectedPaths,
boolean showCamera,
FileAdapterListener photoGridAdapterListener)
{
super(medias, selectedPaths);
this.context = context;
this.glide = requestManager;
this.showCamera = showCamera;
this.mListener = photoGridAdapterListener;
setColumnNumber(context,3);
}
@Override
public ImageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.item_image_layout, parent, false);
return new ImageViewHolder(itemView);
}
@Override
public int getItemViewType(int position) {
if(showCamera) {
return (position == 0) ? ITEM_TYPE_CAMERA : ITEM_TYPE_PHOTO;
} else {
return ITEM_TYPE_PHOTO;
}
}
@Override
public void onBindViewHolder(final ImageViewHolder holder, int position) {
if(getItemViewType(position) == ITEM_TYPE_PHOTO) {
final Media media = getItems().get(showCamera?position-1:position);
if(AndroidLifecycleUtils.canLoadImage(holder.imageView.getContext())) {
glide.load(new File(media.getPath()))
.override(imageSize, imageSize)
.placeholder(R.drawable.document)
.thumbnail(0.5f)
.into(holder.imageView);
}
if(media.getMediaType()== FilePickerConst.MEDIA_TYPE_VIDEO) {
holder.videoIcon.setVisibility(View.VISIBLE);
} else {
holder.videoIcon.setVisibility(View.GONE);
}
holder.itemView.setOnClickListener(v -> onItemClicked(holder,media));
//in some cases, it will prevent unwanted situations
holder.checkBox.setVisibility(View.GONE);
holder.checkBox.setOnCheckedChangeListener(null);
holder.checkBox.setOnClickListener(view -> onItemClicked(holder,media));
//if true, your checkbox will be selected, else unselected
holder.checkBox.setChecked(isSelected(media));
holder.selectBg.setVisibility(isSelected(media) ? View.VISIBLE : View.GONE);
holder.checkBox.setVisibility(isSelected(media) ? View.VISIBLE : View.GONE);
holder.checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
toggleSelection(media);
holder.selectBg.setVisibility(isChecked ? View.VISIBLE : View.GONE);
if (isChecked)
{
holder.checkBox.setVisibility(View.VISIBLE);
PickerManager.getInstance().add(media.getPath(), FilePickerConst.FILE_TYPE_MEDIA);
}
else
{
holder.checkBox.setVisibility(View.GONE);
PickerManager.getInstance().remove(media.getPath(),FilePickerConst.FILE_TYPE_MEDIA);
}
if(mListener != null) {
mListener.onItemSelected();
}
});
}
else
{
holder.imageView.setImageResource(PickerManager.getInstance().getCameraDrawable());
holder.checkBox.setVisibility(View.GONE);
holder.itemView.setOnClickListener(cameraOnClickListener);
holder.videoIcon.setVisibility(View.GONE);
}
}
private void onItemClicked(ImageViewHolder holder, Media media) {
if(PickerManager.getInstance().getMaxCount() == 1) {
PickerManager.getInstance().add(media.getPath(), FilePickerConst.FILE_TYPE_MEDIA);
if(mListener!=null) {
mListener.onItemSelected();
}
}
else if (holder.checkBox.isChecked() || PickerManager.getInstance().shouldAdd()) {
holder.checkBox.setChecked(!holder.checkBox.isChecked());
}
}
private void setColumnNumber(Context context, int columnNum) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
int widthPixels = metrics.widthPixels;
imageSize = widthPixels / columnNum;
}
@Override
public int getItemCount() {
if(showCamera) {
return getItems().size() + 1;
}
return getItems().size();
}
public void setCameraListener(View.OnClickListener onClickListener)
{
this.cameraOnClickListener = onClickListener;
}
public static class ImageViewHolder extends RecyclerView.ViewHolder {
CheckBox checkBox;
ImageView imageView;
ImageView videoIcon;
View selectBg;
public ImageViewHolder(View itemView) {
super(itemView);
checkBox = itemView.findViewById(R.id.checkbox);
imageView = itemView.findViewById(R.id.iv_photo);
videoIcon = itemView.findViewById(R.id.video_icon);
selectBg = itemView.findViewById(R.id.transparent_bg);
}
}
}

View File

@@ -0,0 +1,41 @@
package de.beyondsoft.ownchat.filepicker.adapters;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitles = new ArrayList<>();
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitles.add(title);
}
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitles.get(position);
}
}

View File

@@ -0,0 +1,15 @@
package de.beyondsoft.ownchat.filepicker.adapters;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public interface Selectable<T> {
boolean isSelected(T item);
void toggleSelection(T item);
void clearSelection();
int getSelectedItemCount();
}

View File

@@ -0,0 +1,72 @@
package de.beyondsoft.ownchat.filepicker.adapters;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import de.beyondsoft.ownchat.filepicker.models.BaseFile;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder, T extends BaseFile> extends RecyclerView.Adapter<VH> implements Selectable<T> {
private List<T> items;
protected List<T> selectedPhotos;
public SelectableAdapter(List<T> items, List<String> selectedPaths) {
this.items = items;
selectedPhotos = new ArrayList<>();
addPathsToSelections(selectedPaths);
}
private void addPathsToSelections(List<String> selectedPaths) {
if(selectedPaths==null)
return;
for (int index = 0; index < items.size(); index++) {
for (int jindex = 0; jindex < selectedPaths.size(); jindex++) {
if(items.get(index).getPath().equals(selectedPaths.get(jindex)))
{
selectedPhotos.add(items.get(index));
}
}
}
}
@Override
public boolean isSelected(T photo) {
return selectedPhotos.contains(photo);
}
@Override
public void toggleSelection(T photo) {
if (selectedPhotos.contains(photo)) {
selectedPhotos.remove(photo);
} else {
selectedPhotos.add(photo);
}
}
@Override
public void clearSelection() {
selectedPhotos.clear();
}
@Override
public int getSelectedItemCount() {
return selectedPhotos.size();
}
public void setData(List<T> items) {
this.items = items;
}
public List<T> getItems()
{
return items;
}
}

View File

@@ -0,0 +1,122 @@
package de.beyondsoft.ownchat.filepicker.cursors;
import android.content.Context;
import android.database.Cursor;
import android.os.AsyncTask;
import android.provider.MediaStore;
import android.text.TextUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import de.beyondsoft.ownchat.filepicker.PickerManager;
import de.beyondsoft.ownchat.filepicker.cursors.loadercallbacks.FileResultCallback;
import de.beyondsoft.ownchat.filepicker.models.Document;
import de.beyondsoft.ownchat.filepicker.models.FileType;
import static android.provider.BaseColumns._ID;
import static android.provider.MediaStore.MediaColumns.DATA;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class DocScannerTask extends AsyncTask<Void,Void,List<Document>> {
final String[] DOC_PROJECTION = {
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DATA,
MediaStore.Files.FileColumns.MIME_TYPE,
MediaStore.Files.FileColumns.SIZE,
MediaStore.Images.Media.DATE_ADDED,
MediaStore.Files.FileColumns.TITLE
};
private final FileResultCallback<Document> resultCallback;
private final Context mContext;
public DocScannerTask(Context context, FileResultCallback<Document> fileResultCallback)
{
this.mContext = context;
this.resultCallback = fileResultCallback;
}
@Override
protected List<Document> doInBackground(Void... voids) {
ArrayList<Document> documents = new ArrayList<>();
final String[] projection = DOC_PROJECTION;
String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "!="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE + " AND "
+ MediaStore.Files.FileColumns.MEDIA_TYPE + "!="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO ;
final Cursor cursor = mContext.getContentResolver().query(MediaStore.Files.getContentUri("external"),
projection,
selection,
null,
MediaStore.Files.FileColumns.DATE_ADDED + " DESC");
if(cursor!=null) {
documents = getDocumentFromCursor(cursor);
cursor.close();
}
return documents;
}
@Override
protected void onPostExecute(List<Document> documents) {
super.onPostExecute(documents);
if (resultCallback != null) {
resultCallback.onResultCallback(documents);
}
}
private ArrayList<Document> getDocumentFromCursor(Cursor data)
{
ArrayList<Document> documents = new ArrayList<>();
while (data.moveToNext()) {
int imageId = data.getInt(data.getColumnIndexOrThrow(_ID));
String path = data.getString(data.getColumnIndexOrThrow(DATA));
String title = data.getString(data.getColumnIndexOrThrow(MediaStore.Files.FileColumns.TITLE));
if(path!=null) {
FileType fileType = getFileType(PickerManager.getInstance().getFileTypes(),path);
if(fileType != null && !(new File(path).isDirectory())) {
Document document = new Document(imageId, title, path);
document.setFileType(fileType);
String mimeType = data.getString(data.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MIME_TYPE));
if (mimeType != null && !TextUtils.isEmpty(mimeType)) {
document.setMimeType(mimeType);
} else {
document.setMimeType("");
}
document.setSize(data.getString(data.getColumnIndexOrThrow(MediaStore.Files.FileColumns.SIZE)));
if (!documents.contains(document)) {
documents.add(document);
}
}
}
}
return documents;
}
private FileType getFileType(ArrayList<FileType> types, String path) {
for(int index = 0; index < types.size(); index++) {
for(String string : types.get(index).extensions) {
if(path.endsWith(string)) {
return types.get(index);
}
}
}
return null;
}
}

View File

@@ -0,0 +1,50 @@
package de.beyondsoft.ownchat.filepicker.cursors;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.content.CursorLoader;
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class ImageDirectoryLoader extends CursorLoader {
final String[] IMAGE_PROJECTION = {
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.BUCKET_ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
MediaStore.Images.Media.DATE_ADDED,
MediaStore.Images.Media.TITLE
};
public ImageDirectoryLoader(Context context, Bundle args) {
super(context);
String bucketId = args.getString(FilePickerConst.EXTRA_BUCKET_ID, null);
int mediaType = args.getInt(FilePickerConst.EXTRA_FILE_TYPE, FilePickerConst.MEDIA_TYPE_IMAGE);
setProjection(null);
setUri(MediaStore.Files.getContentUri("external"));
setSortOrder(MediaStore.Images.Media._ID + " DESC");
String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "=" + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE;
if(mediaType== FilePickerConst.MEDIA_TYPE_VIDEO) {
selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "=" + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;
}
if(bucketId!=null) {
selection += " AND " + MediaStore.Images.Media.BUCKET_ID + "='" + bucketId + "'";
}
setSelection(selection);
}
private ImageDirectoryLoader(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
super(context, uri, projection, selection, selectionArgs, sortOrder);
}
}

View File

@@ -0,0 +1,11 @@
package de.beyondsoft.ownchat.filepicker.cursors.loadercallbacks;
import java.util.List;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public interface FileResultCallback<T> {
void onResultCallback(List<T> files);
}

View File

@@ -0,0 +1,94 @@
package de.beyondsoft.ownchat.filepicker.cursors.loadercallbacks;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import de.beyondsoft.ownchat.filepicker.PickerManager;
import de.beyondsoft.ownchat.filepicker.cursors.ImageDirectoryLoader;
import de.beyondsoft.ownchat.filepicker.models.ImageDirectory;
import static android.provider.BaseColumns._ID;
import static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE;
import static android.provider.MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME;
import static android.provider.MediaStore.Images.ImageColumns.BUCKET_ID;
import static android.provider.MediaStore.MediaColumns.DATA;
import static android.provider.MediaStore.MediaColumns.DATE_ADDED;
import static android.provider.MediaStore.MediaColumns.TITLE;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class ImageDirLoaderCallback implements LoaderManager.LoaderCallbacks<Cursor> {
public final static int INDEX_ALL_PHOTOS = 0;
private WeakReference<Context> context;
private FileResultCallback<ImageDirectory> resultCallback;
public ImageDirLoaderCallback(Context context, FileResultCallback<ImageDirectory> resultCallback) {
this.context = new WeakReference<>(context);
this.resultCallback = resultCallback;
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new ImageDirectoryLoader(context.get(), args);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if (data == null) {
return;
}
List<ImageDirectory> directories = new ArrayList<>();
while (data.moveToNext()) {
int imageId = data.getInt(data.getColumnIndexOrThrow(_ID));
String bucketId = data.getString(data.getColumnIndexOrThrow(BUCKET_ID));
String name = data.getString(data.getColumnIndexOrThrow(BUCKET_DISPLAY_NAME));
String path = data.getString(data.getColumnIndexOrThrow(DATA));
String fileName = data.getString(data.getColumnIndexOrThrow(TITLE));
int mediaType = data.getInt(data.getColumnIndexOrThrow(MEDIA_TYPE));
ImageDirectory photoDirectory = new ImageDirectory();
photoDirectory.setBucketId(bucketId);
photoDirectory.setName(name);
if (!directories.contains(photoDirectory)) {
if(path.toLowerCase().endsWith("gif")) {
if (PickerManager.getInstance().isShowGif()) {
photoDirectory.addPhoto(imageId, fileName, path, mediaType);
}
}
else
{
photoDirectory.addPhoto(imageId, fileName, path, mediaType);
}
photoDirectory.setDateAdded(data.getLong(data.getColumnIndexOrThrow(DATE_ADDED)));
directories.add(photoDirectory);
} else {
directories.get(directories.indexOf(photoDirectory)).addPhoto(imageId, fileName, path, mediaType);
}
}
if (resultCallback != null) {
resultCallback.onResultCallback(directories);
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
}

View File

@@ -0,0 +1,34 @@
package de.beyondsoft.ownchat.filepicker.fragments;
import android.support.v4.app.Fragment;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public abstract class BaseFragment extends Fragment {
public static final String FILE_TYPE = "FILE_TYPE";
public BaseFragment() {
// Required empty public constructor
}
protected void fadeIn(View view) {
Animation bottomUp = AnimationUtils.loadAnimation(getContext(),
android.R.anim.fade_in);
view.startAnimation(bottomUp);
view.setVisibility(View.VISIBLE);
}
protected void fadeOut(View view) {
Animation bottomUp = AnimationUtils.loadAnimation(getContext(),
android.R.anim.fade_out);
view.startAnimation(bottomUp);
view.setVisibility(View.GONE);
}
}

View File

@@ -0,0 +1,132 @@
package de.beyondsoft.ownchat.filepicker.fragments;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.PickerManager;
import de.beyondsoft.ownchat.filepicker.adapters.FileAdapterListener;
import de.beyondsoft.ownchat.filepicker.adapters.FileListAdapter;
import de.beyondsoft.ownchat.filepicker.models.Document;
import de.beyondsoft.ownchat.filepicker.models.FileType;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class DocFragment extends BaseFragment implements FileAdapterListener {
private static final String TAG = DocFragment.class.getSimpleName();
RecyclerView recyclerView;
TextView emptyView;
private DocFragmentListener mListener;
private FileListAdapter fileListAdapter;
private FileType fileType;
public DocFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_image_picker, container, false);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof DocFragmentListener) {
mListener = (DocFragmentListener) context;
} else {
throw new RuntimeException(context.toString() + " must implement ImagePickerFragmentListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public static DocFragment newInstance(FileType fileType) {
DocFragment photoPickerFragment = new DocFragment();
Bundle bun = new Bundle();
bun.putParcelable(FILE_TYPE, fileType);
photoPickerFragment.setArguments(bun);
return photoPickerFragment;
}
public FileType getFileType() {
return getArguments().getParcelable(FILE_TYPE);
}
@Override
public void onItemSelected() {
mListener.onItemSelected();
}
public interface DocFragmentListener {
void onItemSelected();
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initView(view);
}
private void initView(View view) {
fileType = getArguments().getParcelable(FILE_TYPE);
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
emptyView = (TextView) view.findViewById(R.id.empty_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setVisibility(View.GONE);
}
public void updateList(List<Document> dirs) {
if(getView()==null)
return;
if(dirs.size()>0)
{
recyclerView.setVisibility(View.VISIBLE);
emptyView.setVisibility(View.GONE);
FileListAdapter fileListAdapter = (FileListAdapter) recyclerView.getAdapter();
if(fileListAdapter==null) {
fileListAdapter = new FileListAdapter(getActivity(), dirs, PickerManager.getInstance().getSelectedFiles(), this);
recyclerView.setAdapter(fileListAdapter);
}
else
{
fileListAdapter.setData(dirs);
fileListAdapter.notifyDataSetChanged();
}
}
else
{
recyclerView.setVisibility(View.GONE);
emptyView.setVisibility(View.VISIBLE);
}
}
}

View File

@@ -0,0 +1,156 @@
package de.beyondsoft.ownchat.filepicker.fragments;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import com.android.internal.util.Predicate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.PickerManager;
import de.beyondsoft.ownchat.filepicker.adapters.SectionsPagerAdapter;
import de.beyondsoft.ownchat.filepicker.cursors.loadercallbacks.FileResultCallback;
import de.beyondsoft.ownchat.filepicker.models.Document;
import de.beyondsoft.ownchat.filepicker.models.FileType;
import de.beyondsoft.ownchat.filepicker.utils.MediaStoreHelper;
import de.beyondsoft.ownchat.filepicker.utils.TabLayoutHelper;
import de.beyondsoft.ownchat.filepicker.utils.Utils;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class DocPickerFragment extends BaseFragment {
private static final String TAG = DocPickerFragment.class.getSimpleName();
TabLayout tabLayout;
ViewPager viewPager;
private ArrayList<String> selectedPaths;
private ProgressBar progressBar;
private DocPickerFragmentListener mListener;
public DocPickerFragment() {
// Required empty public constructor
}
public interface DocPickerFragmentListener{
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_doc_picker, container, false);
}
public static DocPickerFragment newInstance(ArrayList<String> selectedPaths) {
DocPickerFragment docPickerFragment = new DocPickerFragment();
docPickerFragment.selectedPaths = selectedPaths;
return docPickerFragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof DocPickerFragmentListener) {
mListener = (DocPickerFragmentListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement DocPickerFragmentListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setViews(view);
initView();
}
private void initView() {
setUpViewPager();
setData();
}
private void setViews(View view) {
tabLayout = (TabLayout) view.findViewById(R.id.tabs);
viewPager = (ViewPager) view.findViewById(R.id.viewPager);
progressBar = (ProgressBar) view.findViewById(R.id.progress_bar);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
}
private void setData() {
MediaStoreHelper.getDocs(getActivity(), new FileResultCallback<Document>() {
@Override
public void onResultCallback(List<Document> files) {
if(!isAdded()) return;
progressBar.setVisibility(View.GONE);
setDataOnFragments(files);
}
});
}
private void setDataOnFragments(List<Document> files) {
SectionsPagerAdapter sectionsPagerAdapter = (SectionsPagerAdapter) viewPager.getAdapter();
if(sectionsPagerAdapter!=null)
{
for (int index = 0; index < sectionsPagerAdapter.getCount(); index++) {
DocFragment docFragment = (DocFragment) getChildFragmentManager()
.findFragmentByTag(
"android:switcher:" + R.id.viewPager + ":"+index);
if(docFragment!=null)
{
FileType fileType = docFragment.getFileType();
if(fileType!=null)
docFragment.updateList(filterDocuments(fileType.extensions, files));
}
}
}
}
private void setUpViewPager() {
SectionsPagerAdapter adapter = new SectionsPagerAdapter(getChildFragmentManager());
ArrayList<FileType> supportedTypes = PickerManager.getInstance().getFileTypes();
for (int index = 0; index < supportedTypes.size(); index++) {
adapter.addFragment(DocFragment.newInstance(supportedTypes.get(index)),supportedTypes.get(index).title);
}
viewPager.setOffscreenPageLimit(supportedTypes.size());
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
TabLayoutHelper mTabLayoutHelper = new TabLayoutHelper(tabLayout, viewPager);
mTabLayoutHelper.setAutoAdjustTabModeEnabled(true);
}
private ArrayList<Document> filterDocuments(final String[] type, List<Document> documents)
{
final Predicate<Document> docType = new Predicate<Document>() {
public boolean apply(Document document) {
return document.isThisType(type);
}
};
return new ArrayList<>(Utils.filter(new HashSet<>(documents),docType));
}
}

View File

@@ -0,0 +1,9 @@
package de.beyondsoft.ownchat.filepicker.fragments;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public interface ImagePickerFragmentListener {
void onItemSelected();
}

View File

@@ -0,0 +1,244 @@
package de.beyondsoft.ownchat.filepicker.fragments;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
import de.beyondsoft.ownchat.filepicker.PickerManager;
import de.beyondsoft.ownchat.filepicker.adapters.FileAdapterListener;
import de.beyondsoft.ownchat.filepicker.adapters.ImageGridAdapter;
import de.beyondsoft.ownchat.filepicker.cursors.loadercallbacks.FileResultCallback;
import de.beyondsoft.ownchat.filepicker.models.ImageDirectory;
import de.beyondsoft.ownchat.filepicker.models.Media;
import de.beyondsoft.ownchat.filepicker.utils.AndroidLifecycleUtils;
import de.beyondsoft.ownchat.filepicker.utils.ImageCaptureManager;
import de.beyondsoft.ownchat.filepicker.utils.MediaStoreHelper;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class MediaDetailPickerFragment extends BaseFragment implements FileAdapterListener {
private static final String TAG = MediaDetailPickerFragment.class.getSimpleName();
private static final int SCROLL_THRESHOLD = 30;
RecyclerView recyclerView;
TextView emptyView;
private ImagePickerFragmentListener mListener;
private ImageGridAdapter photoGridAdapter;
private ImageCaptureManager imageCaptureManager;
private RequestManager mGlideRequestManager;
private int fileType;
public MediaDetailPickerFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_image_picker, container, false);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof ImagePickerFragmentListener) {
mListener = (ImagePickerFragmentListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement PhotoPickerFragmentListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public static MediaDetailPickerFragment newInstance(int fileType) {
MediaDetailPickerFragment mediaDetailPickerFragment = new MediaDetailPickerFragment();
Bundle bun = new Bundle();
bun.putInt(FILE_TYPE, fileType);
mediaDetailPickerFragment.setArguments(bun);
return mediaDetailPickerFragment;
}
@Override
public void onItemSelected() {
mListener.onItemSelected();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGlideRequestManager = Glide.with(this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initView(view);
}
private void initView(View view) {
recyclerView = view.findViewById(R.id.recyclerview);
emptyView = view.findViewById(R.id.empty_view);
fileType = getArguments().getInt(FILE_TYPE);
imageCaptureManager = new ImageCaptureManager(getActivity());
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, OrientationHelper.VERTICAL);
layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// Log.d(">>> Picker >>>", "dy = " + dy);
if (Math.abs(dy) > SCROLL_THRESHOLD) {
mGlideRequestManager.pauseRequests();
} else {
resumeRequestsIfNotDestroyed();
}
}
@Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
resumeRequestsIfNotDestroyed();
}
}
});
getDataFromMedia();
}
private void getDataFromMedia() {
Bundle mediaStoreArgs = new Bundle();
mediaStoreArgs.putInt(FilePickerConst.EXTRA_FILE_TYPE, fileType);
if(fileType==FilePickerConst.MEDIA_TYPE_IMAGE) {
MediaStoreHelper.getPhotoDirs(getActivity(), mediaStoreArgs,
dirs -> updateList(dirs));
}
else if(fileType==FilePickerConst.MEDIA_TYPE_VIDEO)
{
MediaStoreHelper.getVideoDirs(getActivity(), mediaStoreArgs,
dirs -> updateList(dirs));
}
}
private void updateList(List<ImageDirectory> dirs) {
ArrayList<Media> medias = new ArrayList<>();
for (int i = 0; i < dirs.size(); i++) {
medias.addAll(dirs.get(i).getMedias());
}
Collections.sort(medias,new Comparator<Media>() {
@Override
public int compare(Media a, Media b) {
return b.getId() - a.getId();
}
});
if(medias.size()>0) {
emptyView.setVisibility(View.GONE);
}
else {
emptyView.setVisibility(View.VISIBLE);
}
if(photoGridAdapter!=null)
{
photoGridAdapter.setData(medias);
photoGridAdapter.notifyDataSetChanged();
}
else
{
photoGridAdapter = new ImageGridAdapter(getActivity(), mGlideRequestManager, (ArrayList<Media>) medias, PickerManager.getInstance().getSelectedPhotos(),(fileType==FilePickerConst.MEDIA_TYPE_IMAGE) && PickerManager.getInstance().isEnableCamera(), this);
recyclerView.setAdapter(photoGridAdapter);
photoGridAdapter.setCameraListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Intent intent = imageCaptureManager.dispatchTakePictureIntent(getActivity());
if(intent!=null)
startActivityForResult(intent, ImageCaptureManager.REQUEST_TAKE_PHOTO);
else
Toast.makeText(getActivity(), R.string.no_camera_exists, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode)
{
case ImageCaptureManager.REQUEST_TAKE_PHOTO:
if(resultCode== Activity.RESULT_OK)
{
String imagePath = imageCaptureManager.galleryAddPic();
if(imagePath!=null && PickerManager.getInstance().getMaxCount()==1)
{
PickerManager.getInstance().add(imagePath, FilePickerConst.FILE_TYPE_MEDIA);
mListener.onItemSelected();
}
else {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
getDataFromMedia();
}
}, 1000);
}
}
break;
}
}
private void resumeRequestsIfNotDestroyed() {
if (!AndroidLifecycleUtils.canLoadImage(this)) {
return;
}
mGlideRequestManager.resumeRequests();
}
}

View File

@@ -0,0 +1,265 @@
package de.beyondsoft.ownchat.filepicker.fragments;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
import de.beyondsoft.ownchat.filepicker.MediaDetailsActivity;
import de.beyondsoft.ownchat.filepicker.PickerManager;
import de.beyondsoft.ownchat.filepicker.adapters.FolderGridAdapter;
import de.beyondsoft.ownchat.filepicker.cursors.loadercallbacks.FileResultCallback;
import de.beyondsoft.ownchat.filepicker.models.ImageDirectory;
import de.beyondsoft.ownchat.filepicker.utils.AndroidLifecycleUtils;
import de.beyondsoft.ownchat.filepicker.utils.GridSpacingItemDecoration;
import de.beyondsoft.ownchat.filepicker.utils.ImageCaptureManager;
import de.beyondsoft.ownchat.filepicker.utils.MediaStoreHelper;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class MediaFolderPickerFragment extends BaseFragment implements FolderGridAdapter.FolderGridAdapterListener {
private static final String TAG = MediaFolderPickerFragment.class.getSimpleName();
private static final int SCROLL_THRESHOLD = 30;
RecyclerView recyclerView;
TextView emptyView;
private ImagePickerFragmentListener mListener;
private FolderGridAdapter photoGridAdapter;
private ImageCaptureManager imageCaptureManager;
private RequestManager mGlideRequestManager;
private int fileType;
public MediaFolderPickerFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_media_folder_picker, container, false);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof ImagePickerFragmentListener) {
mListener = (ImagePickerFragmentListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement PhotoPickerFragmentListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public static MediaFolderPickerFragment newInstance(int fileType) {
MediaFolderPickerFragment photoPickerFragment = new MediaFolderPickerFragment();
Bundle bun = new Bundle();
bun.putInt(FILE_TYPE, fileType);
photoPickerFragment.setArguments(bun);
return photoPickerFragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGlideRequestManager = Glide.with(this);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initView(view);
}
private void initView(View view) {
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
emptyView = (TextView) view.findViewById(R.id.empty_view);
fileType = getArguments().getInt(FILE_TYPE);
imageCaptureManager = new ImageCaptureManager(getActivity());
GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 2);
int spanCount = 2; // 2 columns
int spacing = 5; // 5px
boolean includeEdge = false;
recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing, includeEdge));
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// Log.d(">>> Picker >>>", "dy = " + dy);
if (Math.abs(dy) > SCROLL_THRESHOLD) {
mGlideRequestManager.pauseRequests();
} else {
resumeRequestsIfNotDestroyed();
}
}
@Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
resumeRequestsIfNotDestroyed();
}
}
});
getDataFromMedia();
}
private void getDataFromMedia() {
Bundle mediaStoreArgs = new Bundle();
mediaStoreArgs.putBoolean(FilePickerConst.EXTRA_SHOW_GIF, PickerManager.getInstance().isShowGif());
mediaStoreArgs.putInt(FilePickerConst.EXTRA_FILE_TYPE, fileType);
if(fileType==FilePickerConst.MEDIA_TYPE_IMAGE) {
MediaStoreHelper.getPhotoDirs(getActivity(), mediaStoreArgs,
dirs -> updateList(dirs));
}
else if(fileType==FilePickerConst.MEDIA_TYPE_VIDEO)
{
MediaStoreHelper.getVideoDirs(getActivity(), mediaStoreArgs,
dirs -> updateList(dirs));
}
}
private void updateList(List<ImageDirectory> dirs) {
Log.i("updateList",""+dirs.size());
if(dirs.size()>0) {
emptyView.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}
else {
emptyView.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
return;
}
ImageDirectory photoDirectory = new ImageDirectory();
photoDirectory.setBucketId(FilePickerConst.ALL_PHOTOS_BUCKET_ID);
if(fileType==FilePickerConst.MEDIA_TYPE_VIDEO)
{
photoDirectory.setName(getString(R.string.all_videos));
}
else if(fileType==FilePickerConst.MEDIA_TYPE_IMAGE)
{
photoDirectory.setName(getString(R.string.all_photos));
}
else {
photoDirectory.setName(getString(R.string.all_files));
}
if(dirs.size()>0 && dirs.get(0).getMedias().size()>0)
{
photoDirectory.setDateAdded(dirs.get(0).getDateAdded());
photoDirectory.setCoverPath(dirs.get(0).getMedias().get(0).getPath());
}
for (int i = 0; i < dirs.size(); i++) {
photoDirectory.addPhotos(dirs.get(i).getMedias());
}
dirs.add(0,photoDirectory);
if(photoGridAdapter!=null)
{
photoGridAdapter.setData(dirs);
photoGridAdapter.notifyDataSetChanged();
}
else
{
photoGridAdapter = new FolderGridAdapter(getActivity(), mGlideRequestManager, (ArrayList<ImageDirectory>) dirs, null, (fileType== FilePickerConst.MEDIA_TYPE_IMAGE) && PickerManager.getInstance().isEnableCamera());
recyclerView.setAdapter(photoGridAdapter);
photoGridAdapter.setFolderGridAdapterListener(this);
}
}
@Override
public void onCameraClicked() {
try {
Intent intent = imageCaptureManager.dispatchTakePictureIntent(getActivity());
if(intent!=null)
startActivityForResult(intent, ImageCaptureManager.REQUEST_TAKE_PHOTO);
else
Toast.makeText(getActivity(), R.string.no_camera_exists, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFolderClicked(ImageDirectory photoDirectory) {
Intent intent = new Intent(getActivity(), MediaDetailsActivity.class);
intent.putExtra(ImageDirectory.class.getSimpleName(),photoDirectory);
intent.putExtra(FilePickerConst.EXTRA_FILE_TYPE,fileType);
getActivity().startActivityForResult(intent, FilePickerConst.REQUEST_CODE_MEDIA_DETAIL);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode)
{
case ImageCaptureManager.REQUEST_TAKE_PHOTO:
if(resultCode== Activity.RESULT_OK)
{
String imagePath = imageCaptureManager.galleryAddPic();
if(imagePath!=null && PickerManager.getInstance().getMaxCount()==1)
{
PickerManager.getInstance().add(imagePath, FilePickerConst.FILE_TYPE_MEDIA);
mListener.onItemSelected();
}
else {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
getDataFromMedia();
}
}, 1000);
}
}
break;
}
}
private void resumeRequestsIfNotDestroyed() {
if (!AndroidLifecycleUtils.canLoadImage(this)) {
return;
}
mGlideRequestManager.resumeRequests();
}
}

View File

@@ -0,0 +1,106 @@
package de.beyondsoft.ownchat.filepicker.fragments;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
import de.beyondsoft.ownchat.filepicker.PickerManager;
import de.beyondsoft.ownchat.filepicker.adapters.SectionsPagerAdapter;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class MediaPickerFragment extends BaseFragment {
TabLayout tabLayout;
ViewPager viewPager;
private MediaPickerFragmentListener mListener;
public MediaPickerFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_media_picker, container, false);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof MediaPickerFragmentListener) {
mListener = (MediaPickerFragmentListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement MediaPickerFragment");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public static MediaPickerFragment newInstance() {
return new MediaPickerFragment();
}
public interface MediaPickerFragmentListener {
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initView(view);
}
private void initView(View view) {
tabLayout = view.findViewById(R.id.tabs);
viewPager = view.findViewById(R.id.viewPager);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_FIXED);
SectionsPagerAdapter adapter = new SectionsPagerAdapter(getChildFragmentManager());
if(PickerManager.getInstance().showImages()) {
if (PickerManager.getInstance().isShowFolderView()) {
adapter.addFragment(MediaFolderPickerFragment.newInstance(FilePickerConst.MEDIA_TYPE_IMAGE), getString(R.string.images));
} else {
adapter.addFragment(MediaDetailPickerFragment.newInstance(FilePickerConst.MEDIA_TYPE_IMAGE), getString(R.string.images));
}
}
else
tabLayout.setVisibility(View.GONE);
if(PickerManager.getInstance().showVideo())
{
if(PickerManager.getInstance().isShowFolderView()) {
adapter.addFragment(MediaFolderPickerFragment.newInstance(FilePickerConst.MEDIA_TYPE_VIDEO), getString(R.string.videos));
} else {
adapter.addFragment(MediaDetailPickerFragment.newInstance(FilePickerConst.MEDIA_TYPE_VIDEO), getString(R.string.videos));
}
}
else {
tabLayout.setVisibility(View.GONE);
}
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
}
}

View File

@@ -0,0 +1,90 @@
package de.beyondsoft.ownchat.filepicker.models;
import android.os.Parcel;
import android.os.Parcelable;
import de.beyondsoft.ownchat.filepicker.utils.Utils;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class BaseFile implements Parcelable {
protected int id;
protected String name;
protected String path;
public BaseFile() {}
public BaseFile(int id, String name, String path) {
this.id = id;
this.name = name;
this.path = path;
}
protected BaseFile(Parcel in) {
id = in.readInt();
name = in.readString();
path = in.readString();
}
public static final Parcelable.Creator<BaseFile> CREATOR = new Parcelable.Creator<BaseFile>() {
@Override
public BaseFile createFromParcel(Parcel in) {
return new BaseFile(in);
}
@Override
public BaseFile[] newArray(int size) {
return new BaseFile[size];
}
};
public boolean isImage() {
String[] types = {"jpg","jpeg","png","gif"};
return Utils.contains(types, this.path);
}
@Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(!(o instanceof BaseFile)) {
return false;
}
BaseFile baseFile = (BaseFile) o;
return id == baseFile.id;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(id);
parcel.writeString(name);
parcel.writeString(path);
}
}

View File

@@ -0,0 +1,92 @@
package de.beyondsoft.ownchat.filepicker.models;
import java.io.File;
import de.beyondsoft.ownchat.filepicker.utils.Utils;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class Document extends BaseFile {
private String mimeType;
private String size;
private FileType fileType;
public Document(int id, String title, String path) {
super(id,title,path);
}
public Document() {
super(0,null,null);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Document)) return false;
Document document = (Document) o;
return id == document.id;
}
@Override
public int hashCode() {
return id;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getTitle() {
return new File(this.path).getName();
}
public void setTitle(String title) {
this.name = title;
}
public boolean isThisType(String[] types)
{
return Utils.contains(types, this.path);
}
public FileType getFileType()
{
return fileType;
}
public void setFileType(FileType fileType) {
this.fileType = fileType;
}
}

View File

@@ -0,0 +1,65 @@
package de.beyondsoft.ownchat.filepicker.models;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.DrawableRes;
import de.beyondsoft.ownchat.R;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class FileType implements Parcelable {
public String title;
@DrawableRes
public int drawable;
public String[] extensions;
public FileType(String title, String[] extensions, int drawable) {
this.title = title;
this.extensions = extensions;
this.drawable = drawable;
}
protected FileType(Parcel in) {
title = in.readString();
drawable = in.readInt();
extensions = in.createStringArray();
}
public static final Parcelable.Creator<FileType> CREATOR = new Parcelable.Creator<FileType>() {
@Override
public FileType createFromParcel(Parcel in) {
return new FileType(in);
}
@Override
public FileType[] newArray(int size) {
return new FileType[size];
}
};
public int getDrawable()
{
if(drawable == 0) {
return R.drawable.document;
}
return drawable;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(title);
parcel.writeInt(drawable);
parcel.writeStringArray(extensions);
}
}

View File

@@ -0,0 +1,172 @@
package de.beyondsoft.ownchat.filepicker.models;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.List;
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class ImageDirectory extends BaseFile implements Parcelable {
private String bucketId;
private String coverPath;
private String name;
private long dateAdded;
private List<Media> medias = new ArrayList<>();
public ImageDirectory()
{
super();
}
public ImageDirectory(int id, String name, String path) {
super(id, name, path);
}
protected ImageDirectory(Parcel in) {
bucketId = in.readString();
coverPath = in.readString();
name = in.readString();
dateAdded = in.readLong();
}
public static final Creator<ImageDirectory> CREATOR = new Creator<ImageDirectory>() {
@Override
public ImageDirectory createFromParcel(Parcel in) {
return new ImageDirectory(in);
}
@Override
public ImageDirectory[] newArray(int size) {
return new ImageDirectory[size];
}
};
@Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(!(o instanceof ImageDirectory)) {
return false;
}
ImageDirectory directory = (ImageDirectory) o;
boolean hasId = !TextUtils.isEmpty(bucketId);
boolean otherHasId = !TextUtils.isEmpty(directory.bucketId);
return hasId && otherHasId && TextUtils.equals(bucketId, directory.bucketId) && TextUtils.equals(name, directory.name);
}
@Override
public int hashCode() {
if (TextUtils.isEmpty(bucketId)) {
if (TextUtils.isEmpty(name)) {
return 0;
}
return name.hashCode();
}
int result = bucketId.hashCode();
if (TextUtils.isEmpty(name)) {
return result;
}
result = 31 * result + name.hashCode();
return result;
}
public String getCoverPath() {
if(medias!=null && medias.size()>0) {
return medias.get(0).getPath();
}
return coverPath;
}
public void setCoverPath(String coverPath) {
this.coverPath = coverPath;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getDateAdded() {
return dateAdded;
}
public void setDateAdded(long dateAdded) {
this.dateAdded = dateAdded;
}
public List<Media> getMedias() {
return medias;
}
public void setMedias(List<Media> medias) {
this.medias = medias;
}
public List<String> getPhotoPaths() {
List<String> paths = new ArrayList<>(medias.size());
for (Media media : medias) {
paths.add(media.getPath());
}
return paths;
}
public void addPhoto(int id, String name, String path, int mediaType) {
medias.add(new Media(id, name, path, mediaType));
}
public void addPhoto(Media media) {
medias.add(media);
}
public void addPhotos(List<Media> photosList) {
medias.addAll(photosList);
}
public String getBucketId() {
if(bucketId.equals(FilePickerConst.ALL_PHOTOS_BUCKET_ID)) {
return null;
}
return bucketId;
}
public void setBucketId(String bucketId) {
this.bucketId = bucketId;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(bucketId);
parcel.writeString(coverPath);
parcel.writeString(name);
parcel.writeLong(dateAdded);
}
}

View File

@@ -0,0 +1,65 @@
package de.beyondsoft.ownchat.filepicker.models;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class Media extends BaseFile {
public int mediaType;
public Media(int id, String name, String path, int mediaType) {
super(id, name, path);
this.mediaType = mediaType;
}
public Media() {
super(0,null,null);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Media)) return false;
Media media = (Media) o;
return id == media.id;
}
@Override
public int hashCode() {
return id;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMediaType() {
return mediaType;
}
public void setMediaType(int mediaType) {
this.mediaType = mediaType;
}
}

View File

@@ -0,0 +1,45 @@
package de.beyondsoft.ownchat.filepicker.utils;
import android.app.Activity;
import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class AndroidLifecycleUtils {
public static boolean canLoadImage(Fragment fragment) {
if (fragment == null) {
return true;
}
FragmentActivity activity = fragment.getActivity();
return canLoadImage(activity);
}
public static boolean canLoadImage(Context context) {
if (context == null) {
return true;
}
if (!(context instanceof Activity)) {
return true;
}
Activity activity = (Activity) context;
return canLoadImage(activity);
}
private static boolean canLoadImage(Activity activity) {
if (activity == null) {
return true;
}
boolean destroyed = activity.isDestroyed();
return !(destroyed || activity.isFinishing());
}
}

View File

@@ -0,0 +1,10 @@
package de.beyondsoft.ownchat.filepicker.utils;
import android.support.v4.content.FileProvider;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class FilePickerProvider extends FileProvider {
}

View File

@@ -0,0 +1,72 @@
package de.beyondsoft.ownchat.filepicker.utils;
import android.text.TextUtils;
import java.io.File;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class FileUtils {
public static int getTypeDrawable(String path) {
return R.drawable.document;
}
public static FilePickerConst.FILE_TYPE getFileType(String path) {
String fileExtension = Utils.getFileExtension(new File(path));
if(TextUtils.isEmpty(fileExtension)) {
return FilePickerConst.FILE_TYPE.UNKNOWN;
}
if(isExcelFile(path)) {
return FilePickerConst.FILE_TYPE.EXCEL;
}
if(isDocFile(path)) {
return FilePickerConst.FILE_TYPE.WORD;
}
if(isPPTFile(path)) {
return FilePickerConst.FILE_TYPE.PPT;
}
if(isPDFFile(path)) {
return FilePickerConst.FILE_TYPE.PDF;
}
if(isTxtFile(path)) {
return FilePickerConst.FILE_TYPE.TXT;
} else {
return FilePickerConst.FILE_TYPE.UNKNOWN;
}
}
public static boolean isExcelFile(String path) {
String[] types = {"xls","xlsx"};
return Utils.contains(types, path);
}
public static boolean isDocFile(String path) {
String[] types = {"doc","docx", "dot","dotx"};
return Utils.contains(types, path);
}
public static boolean isPPTFile(String path) {
String[] types = {"ppt","pptx"};
return Utils.contains(types, path);
}
public static boolean isPDFFile(String path) {
String[] types = {"pdf"};
return Utils.contains(types, path);
}
public static boolean isTxtFile(String path) {
String[] types = {"txt"};
return Utils.contains(types, path);
}
}

View File

@@ -0,0 +1,76 @@
package de.beyondsoft.ownchat.filepicker.utils;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.filepicker.fragments.BaseFragment;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class FragmentUtil {
public static boolean hadFragment(AppCompatActivity activity) {
return activity.getSupportFragmentManager().getBackStackEntryCount() != 0;
}
public static void replaceFragment(AppCompatActivity activity, int contentId, BaseFragment fragment) {
FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_left_out);
transaction.replace(contentId, fragment, fragment.getClass().getSimpleName());
transaction.addToBackStack(null);
transaction.commit();
}
public static void addFragment(AppCompatActivity activity, int contentId, BaseFragment fragment) {
FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_left_out);
transaction.add(contentId, fragment, fragment.getClass().getSimpleName());
transaction.commit();
}
public static void removeFragment(AppCompatActivity activity, BaseFragment fragment) {
activity.getSupportFragmentManager().beginTransaction()
.remove(fragment)
.commit();
}
public static void showFragment(AppCompatActivity activity, BaseFragment fragment) {
activity.getSupportFragmentManager().beginTransaction()
.show(fragment)
.commit();
}
public static void hideFragment(AppCompatActivity activity, BaseFragment fragment) {
activity.getSupportFragmentManager().beginTransaction()
.hide(fragment)
.commit();
}
public static void attachFragment(AppCompatActivity activity, BaseFragment fragment) {
activity.getSupportFragmentManager().beginTransaction()
.attach(fragment)
.commit();
}
public static void detachFragment(AppCompatActivity activity, BaseFragment fragment) {
activity.getSupportFragmentManager().beginTransaction()
.detach(fragment)
.commit();
}
public static Fragment getFragmentByTag(AppCompatActivity appCompatActivity, String tag)
{
return appCompatActivity.getSupportFragmentManager().findFragmentByTag(tag);
}
}

View File

@@ -0,0 +1,43 @@
package de.beyondsoft.ownchat.filepicker.utils;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
private boolean includeEdge;
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item position
int column = position % spanCount; // item column
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)
if (position < spanCount) { // top edge
outRect.top = spacing;
}
outRect.bottom = spacing; // item bottom
} else {
outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
if (position >= spanCount) {
outRect.top = spacing; // item top
}
}
}
}

View File

@@ -0,0 +1,123 @@
package de.beyondsoft.ownchat.filepicker.utils;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import de.beyondsoft.ownchat.filepicker.PickerManager;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class ImageCaptureManager {
private final static String CAPTURED_PHOTO_PATH_KEY = "mCurrentPhotoPath";
public static final int REQUEST_TAKE_PHOTO = 0x101;
private String mCurrentPhotoPath;
private Context mContext;
public ImageCaptureManager(Context mContext) {
this.mContext = mContext;
}
private File createImageFile() throws IOException {
// Create an image file name
// String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
String imageFileName = "JPEG_" + System.currentTimeMillis() + ".jpg";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
if (!storageDir.exists()) {
if (!storageDir.mkdir()) {
Log.e("TAG", "Throwing Errors....");
throw new IOException();
}
}
File image = new File(storageDir, imageFileName);
// File.createTempFile(
// imageFileName, /* prefix */
// ".jpg", /* suffix */
// storageDir /* directory */
// );
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
public Intent dispatchTakePictureIntent(Context context) throws IOException {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {
// Create the File where the photo should go
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
File newFile = createImageFile();
takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Uri photoURI = FileProvider.getUriForFile(context, PickerManager.getInstance().getProviderAuthorities(), newFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
} else {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(createImageFile()));
}
return takePictureIntent;
}
return null;
}
public String galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
if (TextUtils.isEmpty(mCurrentPhotoPath)) {
return null;
}
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
mContext.sendBroadcast(mediaScanIntent);
return mCurrentPhotoPath;
}
public final void notifyMediaStoreScanner(Context mContext, final File file) {
try {
MediaStore.Images.Media.insertImage(mContext.getContentResolver(),
file.getAbsolutePath(), file.getName(), null);
mContext.sendBroadcast(new Intent(
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public String getCurrentPhotoPath() {
return mCurrentPhotoPath;
}
public void onSaveInstanceState(Bundle savedInstanceState) {
if (savedInstanceState != null && mCurrentPhotoPath != null) {
savedInstanceState.putString(CAPTURED_PHOTO_PATH_KEY, mCurrentPhotoPath);
}
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
if (savedInstanceState != null && savedInstanceState.containsKey(CAPTURED_PHOTO_PATH_KEY)) {
mCurrentPhotoPath = savedInstanceState.getString(CAPTURED_PHOTO_PATH_KEY);
}
}
}

View File

@@ -0,0 +1,37 @@
package de.beyondsoft.ownchat.filepicker.utils;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
import de.beyondsoft.ownchat.filepicker.cursors.DocScannerTask;
import de.beyondsoft.ownchat.filepicker.cursors.loadercallbacks.FileResultCallback;
import de.beyondsoft.ownchat.filepicker.cursors.loadercallbacks.ImageDirLoaderCallback;
import de.beyondsoft.ownchat.filepicker.models.Document;
import de.beyondsoft.ownchat.filepicker.models.ImageDirectory;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class MediaStoreHelper {
public static void getPhotoDirs(FragmentActivity activity, Bundle args, FileResultCallback<ImageDirectory> resultCallback) {
if(activity.getSupportLoaderManager().getLoader(FilePickerConst.MEDIA_TYPE_IMAGE)!=null) {
activity.getSupportLoaderManager().restartLoader(FilePickerConst.MEDIA_TYPE_IMAGE, args, new ImageDirLoaderCallback(activity, resultCallback));
} else {
activity.getSupportLoaderManager().initLoader(FilePickerConst.MEDIA_TYPE_IMAGE, args, new ImageDirLoaderCallback(activity, resultCallback));
}
}
public static void getVideoDirs(FragmentActivity activity, Bundle args, FileResultCallback<ImageDirectory> resultCallback) {
if(activity.getSupportLoaderManager().getLoader(FilePickerConst.MEDIA_TYPE_VIDEO)!=null) {
activity.getSupportLoaderManager().restartLoader(FilePickerConst.MEDIA_TYPE_VIDEO, args, new ImageDirLoaderCallback(activity, resultCallback));
} else {
activity.getSupportLoaderManager().initLoader(FilePickerConst.MEDIA_TYPE_VIDEO, args, new ImageDirLoaderCallback(activity, resultCallback));
}
}
public static void getDocs(FragmentActivity activity, FileResultCallback<Document> fileResultCallback) {
new DocScannerTask(activity,fileResultCallback).execute();
}
}

View File

@@ -0,0 +1,11 @@
package de.beyondsoft.ownchat.filepicker.utils;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public enum Orientation {
PORTRAIT_ONLY,
LANDSCAPE_ONLY,
UNSPECIFIED
}

View File

@@ -0,0 +1,482 @@
package de.beyondsoft.ownchat.filepicker.utils;
import android.database.DataSetObserver;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPager;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import de.beyondsoft.ownchat.R;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class TabLayoutHelper {
protected TabLayout mTabLayout;
protected ViewPager mViewPager;
protected TabLayout.OnTabSelectedListener mUserOnTabSelectedListener;
protected TabLayout.OnTabSelectedListener mInternalOnTabSelectedListener;
protected FixedTabLayoutOnPageChangeListener mInternalTabLayoutOnPageChangeListener;
protected ViewPager.OnAdapterChangeListener mInternalOnAdapterChangeListener;
protected DataSetObserver mInternalDataSetObserver;
protected Runnable mAdjustTabModeRunnable;
protected Runnable mSetTabsFromPagerAdapterRunnable;
protected Runnable mUpdateScrollPositionRunnable;
protected boolean mAutoAdjustTabMode = false;
protected boolean mDuringSetTabsFromPagerAdapter;
public TabLayoutHelper(@NonNull TabLayout tabLayout, @NonNull ViewPager viewPager) {
PagerAdapter adapter = viewPager.getAdapter();
if (adapter == null) {
throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
}/**/
mTabLayout = tabLayout;
mTabLayout.setSelectedTabIndicatorColor(Color.parseColor("#FF5E00"));
mViewPager = viewPager;
mInternalDataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
handleOnDataSetChanged();
}
};
mInternalOnTabSelectedListener = new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
handleOnTabSelected(tab);
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
handleOnTabUnselected(tab);
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
handleOnTabReselected(tab);
}
};
mInternalTabLayoutOnPageChangeListener = new FixedTabLayoutOnPageChangeListener(mTabLayout);
mInternalOnAdapterChangeListener = (viewPager1, oldAdapter, newAdapter) -> handleOnAdapterChanged(viewPager1, oldAdapter, newAdapter);
setupWithViewPager(mTabLayout, mViewPager);
}
public TabLayout getTabLayout() {
return mTabLayout;
}
public ViewPager getViewPager() {
return mViewPager;
}
public void setAutoAdjustTabModeEnabled(boolean enabled) {
if (mAutoAdjustTabMode == enabled) {
return;
}
mAutoAdjustTabMode = enabled;
if (mAutoAdjustTabMode) {
adjustTabMode(-1);
} else {
cancelPendingAdjustTabMode();
}
}
public boolean isAutoAdjustTabModeEnabled() {
return mAutoAdjustTabMode;
}
@Deprecated
public void setOnTabSelectedListener(TabLayout.OnTabSelectedListener listener) {
mUserOnTabSelectedListener = listener;
}
public void release() {
cancelPendingAdjustTabMode();
cancelPendingSetTabsFromPagerAdapter();
cancelPendingUpdateScrollPosition();
if (mInternalOnAdapterChangeListener != null) {
mViewPager.removeOnAdapterChangeListener(mInternalOnAdapterChangeListener);
mInternalOnAdapterChangeListener = null;
}
if (mInternalDataSetObserver != null) {
mViewPager.getAdapter().unregisterDataSetObserver(mInternalDataSetObserver);
mInternalDataSetObserver = null;
}
if (mInternalOnTabSelectedListener != null) {
mTabLayout.removeOnTabSelectedListener(mInternalOnTabSelectedListener);
mInternalOnTabSelectedListener = null;
}
if (mInternalTabLayoutOnPageChangeListener != null) {
mViewPager.removeOnPageChangeListener(mInternalTabLayoutOnPageChangeListener);
mInternalTabLayoutOnPageChangeListener = null;
}
mUserOnTabSelectedListener = null;
mViewPager = null;
mTabLayout = null;
}
public void updateAllTabs() {
int count = mTabLayout.getTabCount();
for (int i = 0; i < count; i++) {
updateTab(mTabLayout.getTabAt(i));
}
}
protected TabLayout.Tab onCreateTab(TabLayout tabLayout, PagerAdapter adapter, int position) {
TabLayout.Tab tab = tabLayout.newTab();
tab.setText(adapter.getPageTitle(position));
return tab;
}
private void onUpdateTab(TabLayout.Tab tab) {
if (tab.getCustomView() == null) {
tab.setCustomView(null); // invokes update() method internally.
}
}
private void handleOnDataSetChanged() {
cancelPendingUpdateScrollPosition();
cancelPendingSetTabsFromPagerAdapter();
if (mSetTabsFromPagerAdapterRunnable == null) {
mSetTabsFromPagerAdapterRunnable = new Runnable() {
@Override
public void run() {
setTabsFromPagerAdapter(mTabLayout, mViewPager.getAdapter(), mViewPager.getCurrentItem());
}
};
}
mTabLayout.post(mSetTabsFromPagerAdapterRunnable);
}
private void handleOnTabSelected(TabLayout.Tab tab) {
if (mDuringSetTabsFromPagerAdapter) {
return;
}
mViewPager.setCurrentItem(tab.getPosition());
cancelPendingUpdateScrollPosition();
if (mUserOnTabSelectedListener != null) {
mUserOnTabSelectedListener.onTabSelected(tab);
}
}
private void handleOnTabUnselected(TabLayout.Tab tab) {
if (mDuringSetTabsFromPagerAdapter) {
return;
}
if (mUserOnTabSelectedListener != null) {
mUserOnTabSelectedListener.onTabUnselected(tab);
}
}
private void handleOnTabReselected(TabLayout.Tab tab) {
if (mDuringSetTabsFromPagerAdapter) {
return;
}
if (mUserOnTabSelectedListener != null) {
mUserOnTabSelectedListener.onTabReselected(tab);
}
}
protected void handleOnAdapterChanged(ViewPager viewPager, PagerAdapter oldAdapter, PagerAdapter newAdapter) {
if (mViewPager != viewPager) {
return;
}
if (oldAdapter != null) {
oldAdapter.unregisterDataSetObserver(mInternalDataSetObserver);
}
if (newAdapter != null) {
newAdapter.registerDataSetObserver(mInternalDataSetObserver);
}
setTabsFromPagerAdapter(mTabLayout, newAdapter, mViewPager.getCurrentItem());
}
protected void cancelPendingAdjustTabMode() {
if (mAdjustTabModeRunnable != null) {
mTabLayout.removeCallbacks(mAdjustTabModeRunnable);
mAdjustTabModeRunnable = null;
}
}
protected void cancelPendingSetTabsFromPagerAdapter() {
if (mSetTabsFromPagerAdapterRunnable != null) {
mTabLayout.removeCallbacks(mSetTabsFromPagerAdapterRunnable);
mSetTabsFromPagerAdapterRunnable = null;
}
}
protected void cancelPendingUpdateScrollPosition() {
if (mUpdateScrollPositionRunnable != null) {
mTabLayout.removeCallbacks(mUpdateScrollPositionRunnable);
mUpdateScrollPositionRunnable = null;
}
}
protected void adjustTabMode(int prevScrollX) {
if (mAdjustTabModeRunnable != null) {
return;
}
if (prevScrollX < 0) {
prevScrollX = mTabLayout.getScrollX();
}
if (ViewCompat.isLaidOut(mTabLayout)) {
adjustTabModeInternal(mTabLayout, prevScrollX);
} else {
final int prevScrollX1 = prevScrollX;
mAdjustTabModeRunnable = new Runnable() {
@Override
public void run() {
mAdjustTabModeRunnable = null;
adjustTabModeInternal(mTabLayout, prevScrollX1);
}
};
mTabLayout.post(mAdjustTabModeRunnable);
}
}
protected TabLayout.Tab createNewTab(TabLayout tabLayout, PagerAdapter adapter, int position) {
return onCreateTab(tabLayout, adapter, position);
}
protected void setupWithViewPager(@NonNull TabLayout tabLayout, @NonNull ViewPager viewPager) {
final PagerAdapter adapter = viewPager.getAdapter();
if (adapter == null) {
throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
}
setTabsFromPagerAdapter(tabLayout, adapter, viewPager.getCurrentItem());
viewPager.getAdapter().registerDataSetObserver(mInternalDataSetObserver);
viewPager.addOnPageChangeListener(mInternalTabLayoutOnPageChangeListener);
viewPager.addOnAdapterChangeListener(mInternalOnAdapterChangeListener);
tabLayout.addOnTabSelectedListener(mInternalOnTabSelectedListener);
}
protected void setTabsFromPagerAdapter(@NonNull TabLayout tabLayout, @Nullable PagerAdapter adapter, int currentItem) {
try {
mDuringSetTabsFromPagerAdapter = true;
int prevSelectedTab = tabLayout.getSelectedTabPosition();
int prevScrollX = tabLayout.getScrollX();
// remove all tabs
tabLayout.removeAllTabs();
// add tabs
if (adapter != null) {
int count = adapter.getCount();
for (int i = 0; i < count; i++) {
TabLayout.Tab tab = createNewTab(tabLayout, adapter, i);
tabLayout.addTab(tab, false);
updateTab(tab);
}
// select current tab
currentItem = Math.min(currentItem, count - 1);
if (currentItem >= 0) {
tabLayout.getTabAt(currentItem).select();
}
}
// adjust tab mode & gravity
if (mAutoAdjustTabMode) {
adjustTabMode(prevScrollX);
} else {
// restore scroll position if needed
int curTabMode = tabLayout.getTabMode();
if (curTabMode == TabLayout.MODE_SCROLLABLE) {
tabLayout.scrollTo(prevScrollX, 0);
}
}
} finally {
mDuringSetTabsFromPagerAdapter = false;
}
}
protected void updateTab(TabLayout.Tab tab) {
onUpdateTab(tab);
}
protected int determineTabMode(@NonNull TabLayout tabLayout) {
LinearLayout slidingTabStrip = (LinearLayout) tabLayout.getChildAt(0);
int childCount = slidingTabStrip.getChildCount();
// NOTE: slidingTabStrip.getMeasuredWidth() method does not return correct width!
// Need to measure each tabs and calculate the sum of them.
int tabLayoutWidth = tabLayout.getMeasuredWidth() - tabLayout.getPaddingLeft() - tabLayout.getPaddingRight();
int tabLayoutHeight = tabLayout.getMeasuredHeight() - tabLayout.getPaddingTop() - tabLayout.getPaddingBottom();
if (childCount == 0) {
return TabLayout.MODE_FIXED;
}
int stripWidth = 0;
int maxWidthTab = 0;
int tabHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(tabLayoutHeight, View.MeasureSpec.EXACTLY);
for (int i = 0; i < childCount; i++) {
View tabView = slidingTabStrip.getChildAt(i);
tabView.measure(View.MeasureSpec.UNSPECIFIED, tabHeightMeasureSpec);
int tabWidth = tabView.getMeasuredWidth();
stripWidth += tabWidth;
maxWidthTab = Math.max(maxWidthTab, tabWidth);
}
return ((stripWidth < tabLayoutWidth) && (maxWidthTab < (tabLayoutWidth / childCount)))
? TabLayout.MODE_FIXED : TabLayout.MODE_SCROLLABLE;
}
protected void adjustTabModeInternal(@NonNull TabLayout tabLayout, int prevScrollX) {
int prevTabMode = tabLayout.getTabMode();
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
int newTabMode = determineTabMode(tabLayout);
cancelPendingUpdateScrollPosition();
if (newTabMode == TabLayout.MODE_FIXED) {
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_FIXED);
} else {
LinearLayout slidingTabStrip = (LinearLayout) tabLayout.getChildAt(0);
slidingTabStrip.setGravity(Gravity.CENTER_HORIZONTAL);
if (prevTabMode == TabLayout.MODE_SCROLLABLE) {
// restore scroll position
tabLayout.scrollTo(prevScrollX, 0);
} else {
// scroll to current selected tab
mUpdateScrollPositionRunnable = new Runnable() {
@Override
public void run() {
mUpdateScrollPositionRunnable = null;
updateScrollPosition();
}
};
mTabLayout.post(mUpdateScrollPositionRunnable);
}
}
}
private void updateScrollPosition() {
mTabLayout.setScrollPosition(mTabLayout.getSelectedTabPosition(), 0, false);
}
protected static class FixedTabLayoutOnPageChangeListener implements ViewPager.OnPageChangeListener {
private final WeakReference<TabLayout> mTabLayoutRef;
private int mPreviousScrollState;
private int mScrollState;
public FixedTabLayoutOnPageChangeListener(TabLayout tabLayout) {
mTabLayoutRef = new WeakReference<>(tabLayout);
}
@Override
public void onPageScrollStateChanged(int state) {
mPreviousScrollState = mScrollState;
mScrollState = state;
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
final TabLayout tabLayout = mTabLayoutRef.get();
if (tabLayout != null) {
if (shouldUpdateScrollPosition()) {
// Update the scroll position, only update the text selection if we're being
// dragged (or we're settling after a drag)
final boolean updateText = (mScrollState == ViewPager.SCROLL_STATE_DRAGGING)
|| (mScrollState == ViewPager.SCROLL_STATE_SETTLING
&& mPreviousScrollState == ViewPager.SCROLL_STATE_DRAGGING);
tabLayout.setScrollPosition(position, positionOffset, updateText);
}
}
}
@Override
public void onPageSelected(int position) {
final TabLayout tabLayout = mTabLayoutRef.get();
if (tabLayout != null && tabLayout.getSelectedTabPosition() != position) {
// Select the tab, only updating the indicator if we're not being dragged/settled
// (since onPageScrolled will handle that).
Internal.selectTab(tabLayout, tabLayout.getTabAt(position),
mScrollState == ViewPager.SCROLL_STATE_IDLE);
}
}
private boolean shouldUpdateScrollPosition() {
return (mScrollState == ViewPager.SCROLL_STATE_DRAGGING) ||
((mScrollState == ViewPager.SCROLL_STATE_SETTLING) && (mPreviousScrollState == ViewPager.SCROLL_STATE_DRAGGING));
}
}
static class Internal {
private static final Method mMethodSelectTab;
static {
mMethodSelectTab = getAccessiblePrivateMethod(TabLayout.class, "selectTab", TabLayout.Tab.class, boolean.class);
}
private static Method getAccessiblePrivateMethod(Class<?> targetClass, String methodName, Class<?>... params) throws RuntimeException {
try {
Method m = targetClass.getDeclaredMethod(methodName, params);
m.setAccessible(true);
return m;
} catch (NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
public static void selectTab(TabLayout tabLayout, TabLayout.Tab tab, boolean updateIndicator) {
try {
mMethodSelectTab.invoke(tabLayout, tab, updateIndicator);
} catch (IllegalAccessException e) {
new IllegalStateException(e);
} catch (InvocationTargetException e) {
throw handleInvocationTargetException(e);
}
}
private static RuntimeException handleInvocationTargetException(InvocationTargetException e) {
Throwable targetException = e.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
} else {
throw new IllegalStateException(targetException);
}
}
}
}

View File

@@ -0,0 +1,81 @@
package de.beyondsoft.ownchat.filepicker.utils;
import android.content.Context;
import android.graphics.Point;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
import com.android.internal.util.Predicate;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class Utils {
public static <T> Collection<T> filter(Collection<T> target, Predicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element: target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
static String getFileExtension(File file) {
String name = file.getName();
try {
return name.substring(name.lastIndexOf(".") + 1);
} catch (Exception e) {
return "";
}
}
public static boolean contains(String[] types, String path) {
for (String string : types) {
if (path.toLowerCase().endsWith(string)) return true;
}
return false;
}
private static final int WIDTH_INDEX = 0;
private static final int HEIGHT_INDEX = 1;
public static int[] getScreenSize(Context context) {
int[] widthHeight = new int[2];
widthHeight[WIDTH_INDEX] = 0;
widthHeight[HEIGHT_INDEX] = 0;
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
widthHeight[WIDTH_INDEX] = size.x;
widthHeight[HEIGHT_INDEX] = size.y;
if (!isScreenSizeRetrieved(widthHeight)) {
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
widthHeight[0] = metrics.widthPixels;
widthHeight[1] = metrics.heightPixels;
}
// Last defense. Use deprecated API that was introduced in lower than API 13
if (!isScreenSizeRetrieved(widthHeight)) {
widthHeight[0] = display.getWidth(); // deprecated
widthHeight[1] = display.getHeight(); // deprecated
}
return widthHeight;
}
private static boolean isScreenSizeRetrieved(int[] widthHeight) {
return widthHeight[WIDTH_INDEX] != 0 && widthHeight[HEIGHT_INDEX] != 0;
}
}

View File

@@ -0,0 +1,35 @@
package de.beyondsoft.ownchat.filepicker.views;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
/**
* Created by Lyndon on 26-Oct-2017.
*/
public class SquareRelativeLayout extends RelativeLayout {
public SquareRelativeLayout(Context context) {
super(context);
}
public SquareRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
}

View File

@@ -37,6 +37,12 @@ public class Message {
@SerializedName("created_at")
public long createdAt;
@SerializedName("group_nb_users")
public int numberOfGroupUsers;
@SerializedName("groupname")
public String groupName;
public Status status;
public String uri;
public boolean isRead;
@@ -108,6 +114,7 @@ public class Message {
if (status == null) {
return STATUS_DELIVERED;
}
switch (status) {
case DELIVERED:
return STATUS_DELIVERED;
@@ -116,6 +123,7 @@ public class Message {
case PENDING:
return STATUS_PENDING;
}
return 1;
}
}
@@ -150,6 +158,7 @@ public class Message {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
@@ -159,42 +168,54 @@ public class Message {
if (senderId != message1.senderId) {
return false;
}
if (groupId != message1.groupId) {
return false;
}
if (createdAt != message1.createdAt && createdAt != message1.createdAt * 1000 && createdAt * 1000 != message1.createdAt) {
return false;
}
if (!id.equals(message1.id)) {
return false;
}
if (uri != null ? !uri.equals(message1.uri) : message1.uri != null) {
return false;
}
if (senderName != null ? !senderName.equals(message1.senderName) : message1.senderName != null) {
return false;
}
if (senderAvatar != null ? !senderAvatar.equals(message1.senderAvatar) : message1.senderAvatar != null) {
return false;
}
if (message != null ? !message.equals(message1.message) : message1.message != null) {
return false;
}
if (filePath != null ? !filePath.equals(message1.filePath) : message1.filePath != null) {
return false;
}
if (smallerImage != null ? !smallerImage.equals(message1.smallerImage) : message1.smallerImage != null) {
return false;
}
if (isRead != ((Message) o).isRead) {
return false;
}
return status == message1.status;
}
@Override
public int hashCode() {
int result = id.hashCode();
result = 31 * result + (int) (senderId ^ (senderId >>> 32));
result = 31 * result + (senderName != null ? senderName.hashCode() : 0);
result = 31 * result + (senderAvatar != null ? senderAvatar.hashCode() : 0);
@@ -205,6 +226,7 @@ public class Message {
result = 31 * result + (smallerImage != null ? smallerImage.hashCode() : 0);
result = 31 * result + (int) (createdAt ^ (createdAt >>> 32));
result = 31 * result + (status != null ? status.hashCode() : 0);
return result;
}
@@ -233,6 +255,7 @@ public class Message {
return true;
}
}
return false;
}
}

View File

@@ -6,15 +6,23 @@ import de.beyondsoft.ownchat.data.events.InvalidTokenEvent;
import de.beyondsoft.ownchat.data.events.LogoutDirectlyEvent;
import de.beyondsoft.ownchat.data.prefs.BooleanPreference;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
import de.beyondsoft.ownchat.data.prefs.StringPreference;
import de.beyondsoft.ownchat.di.InjectionHelper;
import de.beyondsoft.ownchat.filepicker.FilePickerBuilder;
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
import de.beyondsoft.ownchat.filepicker.utils.Orientation;
import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.model.Message;
import de.beyondsoft.ownchat.page.common.RuntimePermissionActivity;
import de.beyondsoft.ownchat.page.fileconfirmation.FileConfirmationActivity;
import de.beyondsoft.ownchat.page.login.LoginPresenter;
import de.beyondsoft.ownchat.page.main.LogoutNavigation;
import de.beyondsoft.ownchat.page.main.MainActivity;
import de.beyondsoft.ownchat.utils.Constants;
import de.beyondsoft.ownchat.utils.EndlessScrollListener;
import de.beyondsoft.ownchat.utils.FileUtils;
import de.beyondsoft.ownchat.utils.SystemUtils;
import de.beyondsoft.ownchat.utils.Utils;
import de.beyondsoft.ownchat.utils.ui.EmptyLayout;
import org.greenrobot.eventbus.EventBus;
@@ -23,6 +31,7 @@ import org.greenrobot.eventbus.ThreadMode;
import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.Rect;
import android.net.Uri;
@@ -68,7 +77,9 @@ import okhttp3.MediaType;
abstract class BaseChatActivity extends RuntimePermissionActivity implements ChatView, BaseChatAdapter.MessageClickListener, LogoutNavigation {
private final static int STORAGE_REQUEST_CODE = 9999;
private final static int SELECT_FILE = 5055;
private final static int SELECT_IMAGE_FILE = 233;
private final static int SELECT_DOC_FILE = 234;
private final static int CONFIRM_FILE = 666;
private final static int VISIBLE_THRESHOLD = 25;
protected final static String MESSAGE_ARG = "message_arg";
protected final static String GROUP_ARG = "group_arg";
@@ -119,6 +130,14 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
@Inject
LoginPresenter mLoginPresenter;
@Inject
@Named(AppPrefsConstants.PATH_TO_FILE_TO_SHARE)
StringPreference mSelectedFilePath;
@Inject
@Named(AppPrefsConstants.IS_COMING_FROM_SHARING_ACTIVITY)
BooleanPreference mIsComingFromSharingActivity;
protected Group mGroup;
protected ChatView.Callback mCallback;
protected EndlessScrollListener mEndlessScrollListener;
@@ -134,7 +153,9 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
if (!getIntent().hasExtra(GROUP_ARG) && !getIntent().hasExtra(MESSAGE_ARG)) {
throw new RuntimeException("Arguments are missing. Please use createIntentMethodInstead;");
}
super.onCreate(savedInstanceState);
EventBus.getDefault().register(this);
setContentView(R.layout.activity_chat);
ButterKnife.bind(this);
@@ -143,8 +164,10 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
mBaseChatAdapter = getAdapter();
mEmptyLayout.setOnTryAgainClickListener(v -> mCallback.fetchMoreMessagesByGroupId());
setupRecyclerView();
EmojIconActions emojIcon = new EmojIconActions(this, mCoordinatorLayout, mChatMessageEmojiEditText, mEmojiButton);
emojIcon.ShowEmojIcon();
EmojIconActions emojiIcon = new EmojIconActions(this, mCoordinatorLayout, mChatMessageEmojiEditText, mEmojiButton);
emojiIcon.ShowEmojIcon();
showLoading();
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(mKeyboardListener);
@@ -154,10 +177,13 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setStackFromEnd(true);
linearLayoutManager.setReverseLayout(true);
mRecyclerView.setLayoutManager(linearLayoutManager);
mBaseChatAdapter.setMessageClickListener(this);
mRecyclerView.setAdapter(mBaseChatAdapter);
((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
mEndlessScrollListener = new EndlessScrollListener(VISIBLE_THRESHOLD, linearLayoutManager) {
@Override
public boolean onLoad() {
@@ -168,6 +194,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
return true;
}
};
mRecyclerView.addOnScrollListener(mEndlessScrollListener);
}
@@ -197,15 +224,52 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
mRecyclerView.scrollToPosition(0);
return;
}
mBaseChatAdapter.addMessages(messages);
}
private void shareFile(int requestCode) {
mIsComingFromSharingActivity.set(false);
final Uri uri = Uri.parse(mSelectedFilePath.get());
final File file = FileUtils.getFile(this, uri);
String filePath = file.getPath();
mSelectedFilePath.delete();
if (Build.VERSION.SDK_INT >= 19) {
final int takeFlags = (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
try {
//noinspection WrongConstant
getContentResolver().takePersistableUriPermission(uri, takeFlags);
} catch (Exception e) {
e.printStackTrace();
}
}
if (!mChatPresenter.isAttached()) {
mChatPresenter.attachView(this);
}
Bundle bundle = new Bundle();
bundle.putString(Constants.FILENAME, filePath);
Intent intent = new Intent(this, FileConfirmationActivity.class);
intent.putExtras(bundle);
intent.putExtra(Constants.EXTRA_GROUP, mGroup);
startActivityForResult(intent, 666);
}
@Override
public void showError(@StringRes int errorRes) {
if (mSnackbar == null) {
mSnackbar = Snackbar.make(mCoordinatorLayout, errorRes, Snackbar.LENGTH_LONG);
mSnackbar.setActionTextColor(ContextCompat.getColor(this, R.color.colorDefault));
}
mSnackbar.setText(errorRes);
mSnackbar.show();
}
@@ -228,6 +292,13 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
@Override
public void hideMessagesLoading() {
mBaseChatAdapter.setLoading(false);
if(mIsComingFromSharingActivity.get()) {
requestAppPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
R.string.permission_storage_explained,
STORAGE_REQUEST_CODE,
this::shareFile);
}
}
@Override
@@ -251,7 +322,6 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
@OnClick(R.id.chat_send_message)
void messageSent() {
// mLoginPresenter.checkIfVoucherStillAvailable(this);
mCallback.sendMessage(mChatMessageEmojiEditText.getText().toString());
mChatMessageEmojiEditText.setText("");
}
@@ -262,20 +332,43 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
}
private void selectFile(int requestCode) {
Intent intent;
final String[] zipFileTypes = {".zip", ".rar", ".7z"};
final String[] pdfFileTypes = {".pdf"};
final String[] docFileTypes = {".txt", ".doc", ".xls", ".docx", ".xlsx", ".odt"};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
} else {
intent = new Intent(Intent.ACTION_GET_CONTENT);
}
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
final Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.file_chooser_dialog);
startActivityForResult(Intent.createChooser(intent, getResources().getString(R.string.chat_select_file)), SELECT_FILE);
ImageView attachFromGalleryImageView = dialog.findViewById(R.id.attachFromGalleryBtn);
ImageView attachDocumentImageView = dialog.findViewById(R.id.attachDocumentBtn);
attachDocumentImageView.setOnClickListener(v -> {
FilePickerBuilder.getInstance().setMaxCount(1)
.addFileSupport("ZIP", zipFileTypes)
.addFileSupport("PDF", pdfFileTypes)
.addFileSupport("DOC", docFileTypes)
.enableDocSupport(false)
.withOrientation(Orientation.PORTRAIT_ONLY)
.pickFile(this);
dialog.dismiss();
});
attachFromGalleryImageView.setOnClickListener(v -> {
FilePickerBuilder.getInstance().setMaxCount(1)
.enableVideoPicker(true)
.enableCameraSupport(false)
.showGifs(true)
.showFolderView(true)
.enableImagePicker(true)
.withOrientation(Orientation.PORTRAIT_ONLY)
.pickPhoto(this);
dialog.dismiss();
});
dialog.show();
}
@Override
@@ -295,17 +388,21 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
return;
}
if (requestCode == SELECT_FILE) {
if (null == data.getData()) {
return;
}
ArrayList<String> var1 = data.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_MEDIA);
ArrayList<String> var2 = data.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_DOCS);
final Uri uri = data.getData();
if ((requestCode == SELECT_IMAGE_FILE || requestCode == SELECT_DOC_FILE) && ((var1 != null && var1.size() > 0) || (var2 != null && var2.size() > 0))) {
String filePath = data.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_MEDIA) != null ?
data.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_MEDIA).get(0) :
data.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_DOCS).get(0);
final Uri uri = Uri.fromFile(new File(filePath));
if (Build.VERSION.SDK_INT >= 19) {
final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
try {
//noinspection WrongConstant
getContentResolver().takePersistableUriPermission(uri, takeFlags);
} catch (Exception e) {
e.printStackTrace();
@@ -316,23 +413,32 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
mChatPresenter.attachView(this);
}
// TODO: Show preview for images/gifs and maybe videos
/*Bundle bundle = new Bundle();
bundle.putString(Constants.FILENAME, uri.toString());
Bundle bundle = new Bundle();
bundle.putString(Constants.FILENAME, filePath);
Intent intent = new Intent(this, FileConfirmationActivity.class);
intent.putExtras(bundle);
startActivityForResult(intent, 666);*/
intent.putExtra(Constants.EXTRA_GROUP, mGroup);
mCallback.sendFile(uri);
startActivityForResult(intent, 666);
}
if(requestCode == CONFIRM_FILE) {
String filePath = data.getStringExtra(Constants.FILE_PATH);
String fileMessageText = data.getStringExtra(Constants.FILE_MESSAGE_TEXT);
if (!mChatPresenter.isAttached()) {
mChatPresenter.attachView(this);
}
mCallback.sendFile(Uri.fromFile(new File(filePath)), fileMessageText);
}
}
@Override
public void logoutDirectly(boolean clearAllPrefs) {
EventBus.getDefault().post(new LogoutDirectlyEvent());
EventBus.getDefault().post(new LogoutDirectlyEvent(clearAllPrefs));
finish();
}
@@ -346,16 +452,20 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
if (!mChatPresenter.isAttached()) {
mChatPresenter.attachView(this);
}
String[] split = message.filePath.split("/");
String fileName = split[split.length - 1];
File file = getExternalFilesDir(null);
if (file != null) {
mCallback.downloadFile(message, file + "/" + fileName, itemPosition);
return;
}
file = new File(Environment.getExternalStorageDirectory(), getString(R.string.app_name) + "/" + fileName);
//noinspection ResultOfMethodCallIgnored
file.mkdirs();
mCallback.downloadFile(message, file.getAbsolutePath(), itemPosition);
}
@@ -371,7 +481,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
mChatPresenter.attachView(this);
}
mCallback.resendMessage(message);
mCallback.resendMessage(message, !TextUtils.isEmpty(message.filePath) ? getContentResolver().getType(Uri.parse(message.filePath)) : "");
}
@Override
@@ -379,6 +489,11 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
return MediaType.parse(getContentResolver().getType(fileUri));
}
@Override
public MediaType getMediaType(String mimeType) {
return MediaType.parse(mimeType);
}
@Override
public File getFile(Uri fileUri) {
return FileUtils.getFile(this, fileUri);
@@ -434,14 +549,18 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
@Override
protected void onDestroy() {
mChatOpenedPref.set(false);
if (mEndlessScrollListener != null) {
mRecyclerView.removeOnScrollListener(mEndlessScrollListener);
}
getWindow().getDecorView().getViewTreeObserver().removeOnGlobalLayoutListener(mKeyboardListener);
EventBus.getDefault().unregister(this);
InjectionHelper.destroyChatComponent();
mRecyclerView.setAdapter(null);
mEmptyLayout.setOnTryAgainClickListener(null);
super.onDestroy();
}
@@ -501,4 +620,9 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
}
}
};
@Override
public void onBackPressed() {
startActivity(new Intent(this, MainActivity.class));
}
}

View File

@@ -53,7 +53,7 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
private Calendar mLastDay;
private MessageClickListener mMessageClickListener;
private boolean mIsRetrying;
protected HashMap<Integer, Integer> mDownloadProgressMap = new HashMap<>();
private HashMap<Integer, Integer> mDownloadProgressMap = new HashMap<>();
BaseChatAdapter(long userId) {
mUserId = userId;
@@ -71,11 +71,14 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
mCurrentDay = Calendar.getInstance();
mLastDay = Calendar.getInstance();
mIsRetrying = false;
if (!messages.isEmpty()) {
mPositionOffset.add(0);
mDateList.add(new Date(messages.get(0).createdAt));
}
int messageSize = messages.size();
for (int i = 1; i < messageSize; i++) {
mCurrentDay.setTimeInMillis(messages.get(i).createdAt);
mLastDay.setTimeInMillis(messages.get(i - 1).createdAt);
@@ -85,9 +88,11 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
mDateList.add(mLastDay.getTime());
mLastOffset++;
}
mPositionOffset.add(mLastOffset);
mDateList.add(new Date(messages.get(i).createdAt));
}
mMessages.addAll(messages);
notifyDataSetChanged();
}
@@ -96,11 +101,13 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
if (messages == null || messages.isEmpty() || mMessages.equals(messages)) {
return;
}
int currentMessagesCount = mMessages.size();
int lastOffsetBeforeParsing = mLastOffset;
int datesInserted = 0;
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(messages.get(0).createdAt);
if (mCurrentDay.get(Calendar.DAY_OF_YEAR) != calendar.get(Calendar.DAY_OF_YEAR)) {
mDatePositions.add(currentMessagesCount + mLastOffset);
datesInserted++;
@@ -108,12 +115,15 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
mPositionOffset.add(0);
mLastOffset++;
}
mPositionOffset.add(mLastOffset);
mDateList.add(new Date(messages.get(0).createdAt));
int messageSize = messages.size();
for (int i = 1; i < messageSize; i++) {
mCurrentDay.setTimeInMillis(messages.get(i).createdAt);
mLastDay.setTimeInMillis(messages.get(i - 1).createdAt);
if (mCurrentDay.get(Calendar.DAY_OF_YEAR) != mLastDay.get(Calendar.DAY_OF_YEAR)) {
mDatePositions.add(currentMessagesCount + mLastOffset + i);
datesInserted++;
@@ -121,9 +131,11 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
mDateList.add(mLastDay.getTime());
mLastOffset++;
}
mPositionOffset.add(mLastOffset);
mDateList.add(new Date(messages.get(i).createdAt));
}
mMessages.addAll(messages);
notifyItemRangeInserted(currentMessagesCount + lastOffsetBeforeParsing, messages.size() + datesInserted);
}
@@ -155,11 +167,14 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
mMessages.addAll(currentMessages);
Calendar lastDay = Calendar.getInstance();
if (mMessages.size() > 1) {
lastDay.setTimeInMillis(mMessages.get(1).createdAt);
}
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(message.createdAt);
if (calendar.get(Calendar.DAY_OF_YEAR) != lastDay.get(Calendar.DAY_OF_YEAR)) {
// New date inserted
setMessages(new ArrayList<>(mMessages));
@@ -180,13 +195,16 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
List<Integer> currentDatePositions = new ArrayList<>();
boolean newDateAdded = false;
if (calendar.get(Calendar.DAY_OF_YEAR) != lastDay.get(Calendar.DAY_OF_YEAR)) {
currentDatePositions.add(1);
newDateAdded = true;
}
for (int i = 0, size = mDatePositions.size(); i < size; i++) {
currentDatePositions.add(mDatePositions.get(i) + (newDateAdded ? 2 : 1));
}
mDatePositions.clear();
mDatePositions.addAll(currentDatePositions);
@@ -215,10 +233,12 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
break;
}
}
if (index == -1) {
Log.e("BaseChatAdapter", "message not found!! " + newMessage.toString());
return;
}
mMessages.set(index, newMessage);
notifyItemChanged(index);
}
@@ -228,9 +248,11 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
if (mDatePositions.contains(position)) {
return DATE_TYPE;
}
if (position == mMessages.size() + mLastOffset) {
return LOADING_TYPE;
}
return mMessages.get(position - mPositionOffset.get(position)).senderId == mUserId ?
RIGHT_CHAT_TYPE : LEFT_CHAT_TYPE;
}
@@ -252,10 +274,12 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
break;
}
}
if (myMessage == null) {
Log.e("BaseChatAdapter", "message not found!! " + messageId);
return;
}
mMessages.set(index, myMessage);
notifyItemChanged(index);
}
@@ -300,13 +324,14 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
} else {
viewHolder.filenameTextView.setVisibility(View.GONE);
}
} else if (message.filePath.toLowerCase().endsWith(".png") || message.filePath.toLowerCase().endsWith(".jpg")) {
} else if (message.filePath.toLowerCase().endsWith(".png") || message.filePath.toLowerCase().endsWith(".jpg") || message.filePath.toLowerCase().endsWith(".gif")) {
viewHolder.donutProgress.setVisibility(View.GONE);
viewHolder.fileImageView.setVisibility(View.VISIBLE);
viewHolder.filenameTextView.setVisibility(View.GONE);
viewHolder.fileImageView.setImageDrawable(null);
Log.d("FILE_PATH", message.toString());
Glide.with(viewHolder.fileImageView.getContext())
.load(message.smallerImage)
.load(message.filePath)
.placeholder(R.drawable.document)
.dontAnimate()
.override(500, 500)

View File

@@ -20,17 +20,22 @@ import de.beyondsoft.ownchat.di.scopes.ActivityScope;
import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.model.Message;
import de.beyondsoft.ownchat.page.mvp.MVPAbstractPresenter;
import de.beyondsoft.ownchat.utils.Constants;
import de.beyondsoft.ownchat.utils.SystemUtils;
import de.beyondsoft.ownchat.utils.rx.RxUtils;
import org.greenrobot.eventbus.EventBus;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.util.Pair;
import android.text.TextUtils;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -93,9 +98,20 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
@Named(AppPrefsConstants.NAME)
StringPreference mProfileNamePreference;
@Inject
@Named(AppPrefsConstants.UPLOAD_MAX_SIZE)
LongPreference mUploadMaxSizePreference;
@Inject
@Named(AppPrefsConstants.VERIFY_CHAT_CODE_ERROR_MESSAGE)
StringPreference mVerifyChatCodeErrorMessage;
@Inject
RealmProvider mRealmProvider;
@Inject
Context mContext;
@Inject
ChatPresenter() {
}
@@ -117,22 +133,24 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
getView().hideMessagesLoading();
return;
}
mGroupId = groupId;
Subscription subscription = mChatService.getMessages(groupId, mPage)
.compose(RxUtils.provideDefaultTransformer())
.flatMap(new ErrorHandlingResponseConverter<>())
.flatMap(new Func1<MessagesResponse, Observable<ArrayList<Message>>>() {
@Override
public Observable<ArrayList<Message>> call(MessagesResponse messageResponse) {
.flatMap(messageResponse -> {
ArrayList<Message> messages = messageResponse.response.messages;
for (int i = 0, size = messages.size(); i < size; i++) {
messages.get(i).status = Message.Status.DELIVERED;
messages.get(i).isRead = true;
messages.get(i).userId = mUserIdPreference.get();
}
mFetchMore = messageResponse.response.hasMorePages;
return Observable.just(messageResponse.response.messages);
}
})
.subscribe(this::messagesSuccess, this::messagesError);
addSubscription(subscription);
@@ -204,27 +222,34 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
if (messages == null) {
return;
}
for (int i = 0; i < messages.size(); i++) {
if (!isAttached()) {
break;
}
Message message = messages.get(i);
mMessages.add(message);
getView().addOneMessage(message);
}
}
/**
* Send error messages to view.
*/
private void fetchNewMessagesError(Throwable throwable) {
Log.e("fetchNewMessages", "onError", throwable);
if (!isAttached()) {
return;
}
if (mSystemUtils.isNetworkUnavailable()) {
getView().showError(R.string.error_no_internet_connection);
return;
}
getView().showError(R.string.error_something_went_wrong);
}
@@ -300,18 +325,23 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
if (!isAttached()) {
return;
}
mMessages.clear();
mMessages.addAll(messages);
mLoading = false;
getView().hideLoading();
getView().hideMessagesLoading();
if (!mMessages.isEmpty()) {
int endOffset = mOffset + LIMIT > mMessages.size() ? mMessages.size() : mOffset + LIMIT;
if (mOffset > endOffset) {
return;
}
boolean isFirstPage = mPage == FIRST_PAGE;
getView().messagesLoaded(new ArrayList<>(mMessages.subList(mOffset, endOffset)), isFirstPage);
if (isFirstPage && mSystemUtils.isNetworkUnavailable()) {
Message firstMessage = mMessages.get(0);
Message message = new Message(firstMessage.id,
@@ -331,10 +361,13 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
firstMessage.fileDownloaded);
storeGroupLocally(mGroupId, message);
}
mPage++;
mOffset += LIMIT;
return;
}
getView().showEmptyMessage();
}
@@ -342,6 +375,7 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
if (!isAttached()) {
return;
}
mLoading = false;
getView().hideLoading();
getView().hideMessagesLoading();
@@ -356,17 +390,21 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
getView().hideMessagesLoading();
return;
}
mLoading = true;
if (mPage == FIRST_PAGE) {
getView().showLoading();
} else {
getView().showMessagesLoading();
}
if (mSystemUtils.isNetworkUnavailable()) {
loadMessagesFromDBByGroupId();
getView().showError(R.string.error_no_internet_connection);
return;
}
loadMessagesFromServerByGroupId(mGroupId);
}
@@ -380,22 +418,37 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
* Send the file to the server.
*/
@Override
public void sendFile(Uri fileUri) {
public void sendFile(Uri fileUri, String messageText) {
File file = getView().getFile(fileUri);
final String mimeType = FileUtils.getMimeType(file);
if (file == null || !file.exists()) {
getView().showToastMessage(R.string.error_file_not_found);
return;
}
String[] split = file.getAbsolutePath().split("/");
if(mUploadMaxSizePreference.get() > 0 && file.length() > mUploadMaxSizePreference.get()) {
getView().showError(R.string.error_file_is_too_large);
return;
}
if(mimeType != null && (mimeType.equals(Constants.MIME_TYPE_JPEG) || mimeType.equals(Constants.MIME_TYPE_PNG)) && (file.length() > (1000L * 1024L))) {
FileUtils.clearTmpFilesDir(mContext);
file = FileUtils.scaleImageDown(file, mContext);
}
final File fileToSend = file;
String[] split = fileToSend.getAbsolutePath().split("/");
Message message = new Message(findUniqueRandomId(mRealmProvider, mUserIdPreference.get()),
mGroupId,
System.currentTimeMillis() / 1000,
null,
file.getPath(),
file.getPath(),
messageText,
fileToSend.getPath(),
fileToSend.getPath(),
split[split.length - 1],
fileUri.toString(),
mUserIdPreference.get(),
@@ -423,17 +476,15 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
getView().addOneMessage(message);
// create RequestBody instance from file
RequestBody requestFile = RequestBody.create(getView().getMediaType(fileUri), file);
RequestBody requestFile = RequestBody.create(getView().getMediaType(mimeType), fileToSend);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
MultipartBody.Part body = MultipartBody.Part.createFormData("file", fileToSend.getName(), requestFile);
// add another part within the multipart request
String groupIdString = String.valueOf(mGroupId);
RequestBody groupIdBody = RequestBody.create(okhttp3.MultipartBody.FORM, groupIdString);
Log.d("SENDING FILE", "Sending file with text message...");
RequestBody textBody = RequestBody.create(okhttp3.MultipartBody.FORM, message.message == null ? "" : message.message);
mChatService.sendFile(groupIdBody, body, textBody)
@@ -446,6 +497,7 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
@Override
public void onError(Throwable e) {
FileUtils.clearTmpFilesDir(mContext);
Log.e("sendFile", "onError", e);
@SuppressWarnings("UnnecessaryLocalVariable") Message newMessage = message;
newMessage.createdAt /= 1000;
@@ -453,18 +505,22 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
newMessage.isRead = true;
storeMessageLocally(newMessage, message.id, false);
storeGroupLocally(mGroupId, message);
if (!isAttached()) {
return;
}
if (mSystemUtils.isNetworkUnavailable()) {
getView().showError(R.string.error_no_internet_connection);
return;
}
getView().showError(R.string.error_something_went_wrong);
}
@Override
public void onNext(MessageResponse baseResponse) {
FileUtils.clearTmpFilesDir(mContext);
deleteLocalMessage(message);
baseResponse.response.message.status = Message.Status.DELIVERED;
baseResponse.response.message.isRead = true;
@@ -496,6 +552,7 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
getView().fileDownloadedSuccessfully(filePath, FileUtils.getFileTypeFromFilePath(filePath));
return;
}
downloadFileFromUrl(message.filePath, filePath, itemPosition)
.compose(RxUtils.provideDefaultTransformer())
.subscribe(new Subscriber<String>() {
@@ -523,23 +580,27 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
if (!isAttached()) {
return;
}
getView().stopItemProgress(itemPosition);
getView().fileDownloadedSuccessfully(filePath, fileType);
message.fileDownloaded = true;
message.createdAt /= 1000;
storeMessageLocally(message).subscribe();
}
});
}
@Override
public void resendMessage(Message message) {
public void resendMessage(Message message, String mimeType) {
if(mSystemUtils.isNetworkUnavailable()) {
getView().enableMessageRetry(message.id);
getView().showError(R.string.error_no_internet_connection);
return;
}
if (TextUtils.isEmpty(message.message)) {
if(!TextUtils.isEmpty(message.filePath)) {
Uri fileUri = Uri.parse(message.uri);
File file = getView().getFile(fileUri);
@@ -548,8 +609,21 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
return;
}
if(mUploadMaxSizePreference.get() > 0 && file.length() > mUploadMaxSizePreference.get()) {
getView().showError(R.string.error_file_is_too_large);
return;
}
if(mimeType != null && (mimeType.equals(Constants.MIME_TYPE_JPEG) || mimeType.equals(Constants.MIME_TYPE_PNG)) && (file.length() > (1000L * 1024L))) {
FileUtils.clearTmpFilesDir(mContext);
file = FileUtils.scaleImageDown(file, mContext);
}
final File fileToSend = file;
// create RequestBody instance from file
RequestBody requestFile = RequestBody.create(getView().getMediaType(fileUri), file);
RequestBody requestFile = RequestBody.create(getView().getMediaType(fileUri), fileToSend);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
@@ -570,20 +644,27 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
@Override
public void onError(Throwable e) {
FileUtils.clearTmpFilesDir(mContext);
Log.e("resendMessage", "onError", e);
if (!isAttached()) {
return;
}
getView().enableMessageRetry(message.id);
if (mSystemUtils.isNetworkUnavailable()) {
getView().showError(R.string.error_no_internet_connection);
return;
}
getView().showError(R.string.error_retry_failed);
}
@Override
public void onNext(MessageResponse baseResponse) {
FileUtils.clearTmpFilesDir(mContext);
deleteLocalMessage(message);
baseResponse.response.message.status = Message.Status.DELIVERED;
baseResponse.response.message.isRead = true;
@@ -591,8 +672,10 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
storeGroupLocally(mGroupId, baseResponse.response.message);
}
});
return;
}
mChatService.sendMessage(message.groupId, message.message)
.compose(RxUtils.provideDefaultTransformer())
.flatMap(new ErrorHandlingResponseConverter<>())
@@ -642,6 +725,7 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
true,
mUserIdPreference.get(),
false);
storeMessageLocally(message)
.subscribe(new Subscriber<Object>() {
@Override
@@ -654,6 +738,7 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
storeGroupLocally(mGroupId, message);
return;
}
checkForEmptyMessageAndHideIt();
message.createdAt *= 1000;
getView().addOneMessage(message);
@@ -675,13 +760,16 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
newMessage.isRead = true;
storeMessageLocally(newMessage, message.id, false);
storeGroupLocally(mGroupId, message);
if (!isAttached()) {
return;
}
if (mSystemUtils.isNetworkUnavailable()) {
getView().showError(R.string.error_no_internet_connection);
return;
}
getView().showError(R.string.error_something_went_wrong);
}
@@ -723,13 +811,17 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
messageToDelete.id = oldMessageId;
messageToDelete.removeFromList(mMessages);
mMessages.add(newMessage);
if (!isAttached()) {
mMessageToUpdate.add(new Pair<>(newMessage, oldMessageId));
return;
}
getView().lastMessageUpdated(newMessage, oldMessageId);
return;
}
mPage = FIRST_PAGE;
mOffset = 0;
loadMessagesFromDBByGroupId();

View File

@@ -43,6 +43,8 @@ interface ChatView extends MVPView {
MediaType getMediaType(Uri fileUri);
MediaType getMediaType(String mimeType);
File getFile(Uri fileUri);
void enableMessageRetry(String messageId);
@@ -67,11 +69,11 @@ interface ChatView extends MVPView {
void resetMessages();
void sendFile(Uri fileUri);
void sendFile(Uri fileUri, String messageText);
void sendMessage(String message);
void resendMessage(Message message);
void resendMessage(Message message, String mimeType);
void downloadFile(Message message, String filePath, int itemPosition);
@@ -81,5 +83,4 @@ interface ChatView extends MVPView {
void fetchNewMessages(long groupId);
}
}

View File

@@ -93,15 +93,21 @@ public class GroupChatActivity extends BaseChatActivity {
@Override
protected void setToolbar() {
mSingleChatTitleTextView.setVisibility(View.GONE);
mGroupTitleTextView.setVisibility(View.VISIBLE);
mGroupMembersTextView.setVisibility(View.VISIBLE);
mExtraImageView.setVisibility(View.VISIBLE);
mGroupMembersTextView.setText(mGroup.getContactsNames());
mExtraImageView.setImageResource(R.drawable.vertical_dots);
mChatImageView.setImageResource(mGroup.isHelpGroup() ? R.drawable.avatar_help_group : R.drawable.avatar_team_group);
mGroupTitleTextView.setText(mGroup.name);
mGroupTitleTextView.setTextColor(ContextCompat.getColor(this,
mGroup.isHelpGroup() ? R.color.colorHelpGroup : R.color.colorTeamGroup));
mGroupTitleTextView.setTextColor(ContextCompat.getColor(this, mGroup.isHelpGroup() ? R.color.colorHelpGroup : R.color.colorTeamGroup));
}
@Override

View File

@@ -34,12 +34,14 @@ class GroupChatAdapter extends BaseChatAdapter {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_chat_date, parent, false);
return new DateViewHolder(view);
}
ProgressBar progressBar = new ProgressBar(parent.getContext());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER;
params.setMargins(0, (int) parent.getContext().getResources().getDimension(R.dimen.messages_progress_top_margin), 0, 0);
progressBar.setLayoutParams(params);
ViewUtils.setProgressBarColor(progressBar, R.color.colorWhite);
return new ProgressViewHolder(progressBar);
}
@@ -47,6 +49,7 @@ class GroupChatAdapter extends BaseChatAdapter {
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int viewType = getItemViewType(position);
switch (viewType) {
case LOADING_TYPE:
break;
@@ -62,6 +65,7 @@ class GroupChatAdapter extends BaseChatAdapter {
final Message rightMessage = mMessages.get(position - mPositionOffset.get(position));
MessageViewHolder rightMessageViewHolder = (MessageViewHolder) holder;
setGroupMessage(rightMessageViewHolder, rightMessage, position, false);
if (rightMessage.status == Message.Status.DELIVERED) {
rightMessageViewHolder.statusProgressBar.setVisibility(View.GONE);
rightMessageViewHolder.statusImageView.setVisibility(View.VISIBLE);
@@ -78,6 +82,7 @@ class GroupChatAdapter extends BaseChatAdapter {
rightMessageViewHolder.sendingFailedTextView.setVisibility(View.GONE);
rightMessageViewHolder.statusImageView.setVisibility(View.GONE);
}
break;
}
}

View File

@@ -38,8 +38,10 @@ public class SingleChatActivity extends BaseChatActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mChatPresenter.attachView(this);
mCallback.resetMessages();
if (getIntent().hasExtra(MESSAGE_ARG)) {
Bundle bundle = getIntent().getBundleExtra(MESSAGE_ARG);
mGroup = new Group();
@@ -53,6 +55,7 @@ public class SingleChatActivity extends BaseChatActivity {
} else {
mCallback.loadMessagesFromServerByGroupId(mGroup.id);
}
mCallback.findGroupById();
} else {
setGroupFromArguments();

View File

@@ -37,8 +37,7 @@ class ChatMembersAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_chat_member, parent,
false);
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_chat_member, parent, false);
return new ContactViewHolder(view);
}
@@ -47,13 +46,14 @@ class ChatMembersAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
ContactViewHolder viewHolder = (ContactViewHolder) holder;
User user = mUsers.get(position);
viewHolder.contactTextView.setText(String.format(Locale.getDefault(), "%s %s", user.firstName, user.lastName));
viewHolder.contactTextView.setTextColor(ContextCompat.getColor(viewHolder.contactTextView.getContext(),
user.isEmployee ? R.color.colorBlack : R.color.colorHelpGroup));
viewHolder.contactTextView.setTextColor(ContextCompat.getColor(viewHolder.contactTextView.getContext(), user.isEmployee ? R.color.colorBlack : R.color.colorHelpGroup));
viewHolder.phoneImageView.setVisibility(TextUtils.isEmpty(user.mobile) ? View.GONE : View.VISIBLE);
if (TextUtils.isEmpty(user.avatar)) {
viewHolder.avatarCircleImageView.setImageResource(R.drawable.avatar_list);
return;
}
Glide.with(viewHolder.avatarCircleImageView.getContext())
.load(user.avatar)
.placeholder(R.drawable.avatar)

View File

@@ -3,13 +3,16 @@ package de.beyondsoft.ownchat.page.contacts;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.events.GroupUpdatedEvent;
import de.beyondsoft.ownchat.data.prefs.BooleanPreference;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
import de.beyondsoft.ownchat.data.prefs.StringPreference;
import de.beyondsoft.ownchat.di.InjectionHelper;
import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.model.Message;
import de.beyondsoft.ownchat.page.chat.GroupChatActivity;
import de.beyondsoft.ownchat.page.chat.SingleChatActivity;
import de.beyondsoft.ownchat.page.common.BaseFragment;
import de.beyondsoft.ownchat.page.sharing.SharingActivity;
import de.beyondsoft.ownchat.utils.Constants;
import de.beyondsoft.ownchat.utils.ui.EmptyLayout;
import de.beyondsoft.ownchat.utils.ui.HorizontalDividerItemDecoration;
@@ -73,6 +76,14 @@ public class ContactsFragment extends BaseFragment
@Named(AppPrefsConstants.USER_ID)
LongPreference mUserIdPreference;
@Inject
@Named(AppPrefsConstants.IS_COMING_FROM_SHARING_ACTIVITY)
BooleanPreference mIsComingFromSharingActivity;
@Inject
@Named(AppPrefsConstants.PATH_TO_FILE_TO_SHARE)
StringPreference mSelectedFilePath;
private Callback mCallback;
private ContactsAdapter mContactsAdapter;
private RecyclerView.ItemDecoration mHorizontalDividerItemDecoration;
@@ -83,6 +94,10 @@ public class ContactsFragment extends BaseFragment
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
if(mIsComingFromSharingActivity.get() && mSelectedFilePath.get() != null) {
startActivity(new Intent(getActivity(), SharingActivity.class));
}
}
@Override
@@ -107,8 +122,7 @@ public class ContactsFragment extends BaseFragment
IntentFilter filter = new IntentFilter(Constants.NOTIFICATION_BROADCAST);
getActivity().registerReceiver(mReceiver, filter);
mHorizontalDividerItemDecoration = new HorizontalDividerItemDecoration.Builder(getActivity())
.colorResId(R.color.colorFill).build();
mHorizontalDividerItemDecoration = new HorizontalDividerItemDecoration.Builder(getActivity()).colorResId(R.color.colorFill).build();
mContactsRecyclerView.addItemDecoration(mHorizontalDividerItemDecoration);
mContactsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
@@ -187,6 +201,7 @@ public class ContactsFragment extends BaseFragment
if (TextUtils.isEmpty(mSearchView.getQuery())) {
mSearchView.setIconified(true);
}
startActivity(GroupChatActivity.createIntent(getActivity(), group));
}

View File

@@ -3,7 +3,6 @@ package de.beyondsoft.ownchat.page.contacts;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.api.common.ErrorHandlingResponseConverter;
import de.beyondsoft.ownchat.data.api.responses.GroupResponse;
import de.beyondsoft.ownchat.data.api.services.ChatService;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
import de.beyondsoft.ownchat.data.repository.GroupRealmRepository;
@@ -30,14 +29,12 @@ import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
/**
* Created by imarneanu on 2/20/17.
*/
class ContactsPresenter extends MVPAbstractPresenter<ContactsView>
implements ContactsView.Callback {
class ContactsPresenter extends MVPAbstractPresenter<ContactsView> implements ContactsView.Callback {
@Inject
ChatService mChatService;
@@ -80,21 +77,21 @@ class ContactsPresenter extends MVPAbstractPresenter<ContactsView>
public void loadGroups() {
Subscription subscription = mChatService.getGroups()
.flatMap(new ErrorHandlingResponseConverter<>())
.flatMap(new Func1<GroupResponse, Observable<ArrayList<Group>>>() {
@Override
public Observable<ArrayList<Group>> call(GroupResponse groupResponse) {
.flatMap(groupResponse -> {
if (groupResponse.response.groups != null) {
for (Group group : groupResponse.response.groups) {
group.userId = mUserIdReference.get();
if (group.lastMessage != null) {
group.lastMessage.status = Message.Status.DELIVERED;
group.lastMessage.userId = mUserIdReference.get();
}
mUserRealmRepository.update(group.users, new UserByIdSpecification()).subscribe();
}
}
return Observable.just(groupResponse.response.groups);
}
})
.compose(RxUtils.provideDefaultTransformer())
.subscribe(this::groupsSuccess, this::groupsError);
@@ -109,6 +106,7 @@ class ContactsPresenter extends MVPAbstractPresenter<ContactsView>
getView().showError(R.string.error_no_internet_connection);
return;
}
getView().showError(R.string.error_something_went_wrong);
}

View File

@@ -1,17 +1,26 @@
package de.beyondsoft.ownchat.page.fileconfirmation;
import android.database.Cursor;
import android.content.Intent;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;
import butterknife.OnClick;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.di.InjectionHelper;
import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.utils.Constants;
import de.beyondsoft.ownchat.utils.FileUtils;
@@ -21,6 +30,7 @@ import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import hani.momanii.supernova_emoji_library.Actions.EmojIconActions;
import hani.momanii.supernova_emoji_library.Helper.EmojiconEditText;
public class FileConfirmationActivity extends AppCompatActivity implements FileConfirmationView {
@@ -31,17 +41,35 @@ public class FileConfirmationActivity extends AppCompatActivity implements FileC
@BindView(R.id.file_emoji_button)
ImageView mEmojiButtonImageView;
@BindView(R.id.media_file_webview)
WebView mFileWebView;
@BindView(R.id.media_file)
ImageView mFileImageView;
@BindView(R.id.file_relative_layout)
RelativeLayout mRelativeLayout;
@BindView(R.id.file_send_message)
ImageView mSendMessageButtonImageView;
@BindView(R.id.chat_toolbar_image_view)
ImageView mChatImageView;
@BindView(R.id.chat_toolbar_single_title)
TextView mSingleChatTitleTextView;
@BindView(R.id.chat_toolbar_group_title)
TextView mGroupTitleTextView;
@BindView(R.id.chat_toolbar_group_members)
TextView mGroupMembersTextView;
@BindView(R.id.chat_toolbar_extra_image)
ImageView mExtraImageView;
@Inject
FileConfirmationPresenter mFileConfirmationPresenter;
private Callback mCallback;
private Uri mSelectedUri;
private Group mGroup;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -52,43 +80,70 @@ public class FileConfirmationActivity extends AppCompatActivity implements FileC
ButterKnife.bind(this);
mFileConfirmationPresenter.attachView(this);
EmojIconActions emojiIcon = new EmojIconActions(this, mRelativeLayout, mMessageEmojiconEditText, mEmojiButtonImageView);
emojiIcon.ShowEmojIcon();
String fileUri = getIntent().getStringExtra(Constants.FILENAME);
File file = getFile(Uri.parse(fileUri));
String absolutePath = file.getAbsolutePath();
mSelectedUri = Uri.parse(fileUri);
String html = "<html><head></head><body><img src=\""+ absolutePath + "\"></body></html>";
try {
mFileWebView.loadDataWithBaseURL("", html, "text/html", "utf-8", null);
} catch (Exception e) {
e.printStackTrace();
Glide.with(this)
.load(fileUri)
.dontAnimate()
.placeholder(R.drawable.document)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(new GlideDrawableImageViewTarget(mFileImageView));
mGroup = getIntent().getParcelableExtra(Constants.EXTRA_GROUP);
setToolBar();
}
private void setToolBar() {
if(mGroup.users.size() > 2) {
mSingleChatTitleTextView.setVisibility(View.GONE);
mGroupTitleTextView.setVisibility(View.VISIBLE);
mGroupMembersTextView.setVisibility(View.VISIBLE);
mGroupMembersTextView.setText(mGroup.getContactsNames());
mExtraImageView.setImageResource(R.drawable.vertical_dots);
mChatImageView.setImageResource(mGroup.isHelpGroup() ? R.drawable.avatar_help_group : R.drawable.avatar_team_group);
mGroupTitleTextView.setText(mGroup.name);
mGroupTitleTextView.setTextColor(ContextCompat.getColor(this, mGroup.isHelpGroup() ? R.color.colorHelpGroup : R.color.colorTeamGroup));
} else {
mSingleChatTitleTextView.setVisibility(View.VISIBLE);
mSingleChatTitleTextView.setText(mGroup.name);
mSingleChatTitleTextView.setTextColor(ContextCompat.getColor(this, mGroup.onlyEmployees ? de.beyondsoft.ownchat.R.color.colorBlack : de.beyondsoft.ownchat.R.color.colorHelpGroup));
if (TextUtils.isEmpty(mGroup.avatar)) {
mChatImageView.setImageResource(mGroup.onlyEmployees ? de.beyondsoft.ownchat.R.drawable.avatar : R.drawable.avatar_help);
} else {
Glide.with(this).load(mGroup.avatar)
.placeholder(de.beyondsoft.ownchat.R.drawable.avatar)
.dontAnimate()
.into(mChatImageView);
}
}
}
private String getPath(Uri uri) {
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
@OnClick(R.id.file_send_message)
void sendFile() {
Intent intent = new Intent();
if(cursor == null) {
return null;
intent.putExtra(Constants.FILE_PATH, mSelectedUri.toString());
intent.putExtra(Constants.FILE_MESSAGE_TEXT, mMessageEmojiconEditText.getText().toString());
setResult(-1, intent);
finish();
}
int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(columnIndex);
cursor.close();
return path;
}
@Override
public void sendFileSuccessful() {
}
@Override
public void setCallback(Callback callback) {
mCallback = callback;
@OnClick(R.id.chat_toolbar_back_arrow)
void backPressed() {
onBackPressed();
}
@Override

View File

@@ -1,10 +1,8 @@
package de.beyondsoft.ownchat.page.fileconfirmation;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import de.beyondsoft.ownchat.data.api.services.ChatService;
import de.beyondsoft.ownchat.page.mvp.MVPAbstractPresenter;
import javax.inject.Inject;
@@ -13,10 +11,7 @@ import javax.inject.Inject;
* Created by Lyndon on 13-Oct-2017.
*/
public class FileConfirmationPresenter extends MVPAbstractPresenter<FileConfirmationView> implements FileConfirmationView.Callback {
@Inject
ChatService mChatService;
public class FileConfirmationPresenter extends MVPAbstractPresenter<FileConfirmationView> {
@Inject
Context mContext;
@@ -27,17 +22,11 @@ public class FileConfirmationPresenter extends MVPAbstractPresenter<FileConfirma
@Override
protected void afterAttachView(@NonNull FileConfirmationView view) {
super.afterAttachView(view);
view.setCallback(this);
}
@Override
protected void beforeDetachView(@NonNull FileConfirmationView view) {
view.setCallback(null);
super.beforeDetachView(view);
}
@Override
public void sendFile(Uri fileUri) {
}
}

View File

@@ -1,7 +1,5 @@
package de.beyondsoft.ownchat.page.fileconfirmation;
import android.net.Uri;
import de.beyondsoft.ownchat.page.mvp.MVPLceView;
/**
@@ -9,11 +7,5 @@ import de.beyondsoft.ownchat.page.mvp.MVPLceView;
*/
public interface FileConfirmationView extends MVPLceView {
void sendFileSuccessful();
void setCallback(Callback callback);
interface Callback {
void sendFile(Uri fileUri);
}
}

View File

@@ -30,7 +30,7 @@ public class ImpressumActivity extends AppCompatActivity {
setContentView(R.layout.activity_web_view);
ButterKnife.bind(this);
mWebView.setWebViewClient(new Callback());
mWebView.loadUrl("file:///android_asset/impressum.html");
mWebView.loadUrl("https://www.ownchat.de/index.php/datenschutzerklaerung-app/");
}
@OnClick(R.id.impressum_toolbar_back_arrow)

View File

@@ -22,6 +22,8 @@ import android.support.annotation.StringRes;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
@@ -135,6 +137,7 @@ public class LoginActivity extends AppCompatActivity implements LoginView {
InjectionHelper.destroyLoginComponent();
InjectionHelper.getLoginComponent(this).inject(this);
mLoginPresenter.attachView(this);
mCallback.tryToLogin(mUsernameEditText.getText().toString().trim(), mPasswordEditText.getText().toString(), mChatCodeEditText.getText().toString().trim());
}
@@ -166,6 +169,12 @@ public class LoginActivity extends AppCompatActivity implements LoginView {
mChatCodeEditText.setText(String.valueOf(mSecuredPrefs.getString(AppPrefsConstants.CHAT_CODE, null)));
} else if (key.equals(SecurePreferences.hashPrefKey(AppPrefsConstants.ACCOUNT_NO))) {
mAccountEditText.setText(String.valueOf(mSecuredPrefs.getString(AppPrefsConstants.ACCOUNT_NO, null)));
} else if(key.equals(SecurePreferences.hashPrefKey(AppPrefsConstants.USER_NAME))) {
mUsernameEditText.setText(String.valueOf(mSecuredPrefs.getString(AppPrefsConstants.USER_NAME, null)));
} else if(key.equals(SecurePreferences.hashPrefKey(AppPrefsConstants.USER_PASSWORD))) {
mPasswordEditText.setText(String.valueOf(mSecuredPrefs.getString(AppPrefsConstants.USER_PASSWORD, null)));
} else if(key.equals(SecurePreferences.hashPrefKey(AppPrefsConstants.SAVE_PASSWORD))) {
mSavePasswordCheckbox.setChecked(mSecuredPrefs.getBoolean(AppPrefsConstants.SAVE_PASSWORD, false));
}
}
}

View File

@@ -64,6 +64,10 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
@Inject
RegisterService mRegisterService;
@Inject
@Named(AppPrefsConstants.VERIFY_CHAT_CODE_ERROR_MESSAGE)
StringPreference mVerifyChatCodeErrorMessage;
@Inject
@Named(AppPrefsConstants.SHOW_LOGIN_AGAIN)
BooleanPreference mShowLoginAgainPreference;
@@ -80,6 +84,14 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
@Named(AppPrefsConstants.CHAT_CODE)
StringPreference mChatCodePreference;
@Inject
@Named(AppPrefsConstants.USER_PASSWORD)
StringPreference mPasswordPreference;
@Inject
@Named(AppPrefsConstants.USER_NAME)
StringPreference mUserNamePreference;
@Inject
@Named(AppPrefsConstants.SAVE_PASSWORD)
BooleanPreference mSavePasswordPreference;
@@ -92,6 +104,10 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
@Named(AppPrefsConstants.ACCOUNT_NO)
StringPreference mAccountNumberPreference;
@Inject
@Named(AppPrefsConstants.LAST_ACCOUNT_NO)
StringPreference mLastAccountNumberPreference;
@Inject
@Named(AppPrefsConstants.AVATAR)
StringPreference mAvatarPreference;
@@ -179,7 +195,17 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
Subscription subscription = mLoginService.loginWithChatCode(username, password, chatCode)
.compose(RxUtils.provideDefaultTransformer())
.flatMap(new ErrorHandlingResponseConverter<>())
.map(loginResponse -> loginResponse.response.user)
.map(loginResponse -> {
if(mSavePasswordPreference.get()) {
mUserNamePreference.set(username);
mPasswordPreference.set(password);
} else {
mUserNamePreference.delete();
mPasswordPreference.delete();
}
return loginResponse.response.user;
})
.subscribe(this::loginSuccess, this::loginError);
addSubscription(subscription);
@@ -196,6 +222,7 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
return;
}
try {
ErrorThrowable errorThrowable = (ErrorThrowable) throwable;
switch(ErrorUtils.getErrorType(throwable)) {
@@ -222,6 +249,10 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
default:
getView().showError(R.string.error_something_went_wrong);
}
} catch (Exception e) {
getView().showError(R.string.login_service_type_is_undefined);
e.printStackTrace();
}
}
/**
@@ -229,6 +260,13 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
* @param user {@code User} the current logged in user.
*/
private void loginSuccess(User user) {
String accountNumber = mAccountNumberPreference.get();
String lastAccountNumber = mLastAccountNumberPreference.get();
if(!accountNumber.equals(lastAccountNumber)) {
deleteDataOnCustomerIdChange();
}
mIsEmployee.set(user.isEmployee);
mChatCodePreference.set(mLastVoucher);
mLoginTokenPreference.set(user.token);
@@ -236,6 +274,7 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
mAvatarPreference.set(user.avatar);
mPhoneNumberPreference.set(user.mobile);
mProfileNamePreference.set(user.firstName.concat(" ").concat(user.lastName));
getView().loginSuccessful();
}
@@ -295,6 +334,8 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
*/
@Override
public void checkTypeAndCustomerId(String customerId, String password, boolean isChecked) {
mLastAccountNumberPreference.set(mAccountNumberPreference.get());
mAccountNumberPreference.set(customerId);
mSavePasswordPreference.set(isChecked);
@@ -310,9 +351,7 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
getView().showLoading();
Subscription subscription = mLoginService.getServiceType("1", customerId)
.flatMap(new Func1<JsonObject, Observable<Boolean>>() {
@Override
public Observable<Boolean> call(JsonObject response) {
.flatMap(response -> {
JsonObject serviceObject = response.getAsJsonObject();
if (serviceObject.has("Status")
@@ -334,8 +373,9 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
mStatus = serviceObject.get("Status").getAsInt();
}
return Observable.just(false);
}
})
.compose(RxUtils.provideDefaultTransformer())
.subscribe(this::checkTypeAndCustomerIdSuccessful, this::checkTypeAndCustomerIdError);
@@ -373,9 +413,7 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
getView().showLoading();
Subscription subscription = mLoginService.getUploadMaxSize()
.flatMap(new Func1<JsonObject, Observable<Integer>>() {
@Override
public Observable<Integer> call(JsonObject response) {
.flatMap(response -> {
JsonObject maxSizeObject = response.getAsJsonObject();
if(maxSizeObject.has("file_upload_max_size")) {
@@ -383,7 +421,6 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
}
return Observable.just(0);
}
})
.compose(RxUtils.provideDefaultTransformer())
.subscribe(this::retrieveUploadMaxSizeSuccessful, this::retrieveUploadMaxSizeError);
@@ -497,6 +534,7 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
@Override
public void onNext(JsonObject response) {
if (!response.has("result") || response.get("result") == null) {
getView().showError("Test message after verifying the cat code");
logoutNavigation.logoutDirectly(false);
return;
}
@@ -508,6 +546,8 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
if(result == 0) {
deleteData(true);
shouldClearAllPrefs = true;
getView().showError(R.string.error_deactivated_chat_code);
}
if(result == 1) {
@@ -529,6 +569,7 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
Observable.create(subscriber -> mGlide.clearDiskCache())
.subscribeOn(Schedulers.io())
.subscribe();
mGlide.clearMemory();
mSharedPreferences.edit().clear().apply();
mAccountNumberPreference.deleteFromSecurePreference();
@@ -570,6 +611,39 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
}
}
private void deleteDataOnCustomerIdChange() {
File dir = mContext.getExternalFilesDir(null);
if (dir != null) {
if (dir.isDirectory()) {
String[] children = dir.list();
for (String aChildren : children) {
//noinspection ResultOfMethodCallIgnored
new File(dir, aChildren).delete();
}
} else {
Log.e("deleteData", dir.getAbsolutePath() + " is not a directory!");
}
} else {
dir = new File(Environment.getExternalStorageDirectory(), "BeWoPlaner");
if (dir.isDirectory()) {
String[] children = dir.list();
for (String aChildren : children) {
//noinspection ResultOfMethodCallIgnored
new File(dir, aChildren).delete();
}
} else {
Log.e("deleteData", dir.getAbsolutePath() + " is not a directory!");
}
}
Realm realm = mRealmProvider.provide();
realm.executeTransaction(realm1 -> realm1.deleteAll());
}
private boolean checkPassword(String password) {
if (password.length() >= 1) {
return true;

View File

@@ -24,6 +24,7 @@ import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
@@ -106,25 +107,23 @@ public class MainActivity extends AppCompatActivity implements MainNavigation, L
InjectionHelper.getMainComponent(this).inject(this);
EventBus.getDefault().register(this);
setSupportActionBar(mToolbar);
View headerLayout = mNavigationView.getHeaderView(0);
CircleImageView avatar = headerLayout.findViewById(R.id.menu_profile_imageView);
Glide.with(this).load(mAvatarPreference.get()).into(avatar);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, mDrawer, mToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
Glide.with(MainActivity.this).load(mAvatarPreference.get()).into(avatar);
Utils.hideKeyboard(MainActivity.this);
}
};
mDrawer.closeDrawer(GravityCompat.START);
mDrawer.addDrawerListener(toggle);
View headerLayout = mNavigationView.getHeaderView(0);
CircleImageView avatar = (CircleImageView) headerLayout.findViewById(R.id.menu_profile_imageView);
Glide.with(this).load(mAvatarPreference.get()).into(avatar);
mDrawer.setOnTouchListener((view, motionEvent) -> {
Glide.with(view.getContext()).load(mAvatarPreference.get()).into(avatar);
return false;
});
toggle.syncState();
ArrayAdapter<String> adapter = new NavigationMenuAdapter(this, getResources().getStringArray(R.array.nav_menu), this);
@@ -133,6 +132,7 @@ public class MainActivity extends AppCompatActivity implements MainNavigation, L
onNewIntent(getIntent());
}
@SuppressLint("MissingSuperCall")
@Override
protected void onSaveInstanceState(Bundle outState) {}
@@ -261,14 +261,13 @@ public class MainActivity extends AppCompatActivity implements MainNavigation, L
@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onInvalidToken(InvalidTokenEvent invalidTokenEvent) {
Log.d("INVALID TOKEN", " invalid token event fired");
mLoginPresenter.verifyChatCode(this);
}
@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onLogoutDirectlyEvent(LogoutDirectlyEvent logoutDirectlyEvent) {
logoutDirectly(true);
logoutDirectly(logoutDirectlyEvent.getClearAllPrefs());
}
@Override
@@ -276,11 +275,6 @@ public class MainActivity extends AppCompatActivity implements MainNavigation, L
EventBus.getDefault().unregister(this);
mChatOpenedPref.set(false);
if (!mLogoutClicked && getIntent().getBooleanExtra(LOGOUT, true)) {
mLoginPresenter.tryToLogout(Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID), this);
}
getIntent().removeExtra(LOGOUT);
InjectionHelper.destroyMainComponents();
super.onDestroy();
}

View File

@@ -3,9 +3,11 @@ package de.beyondsoft.ownchat.page.profile;
import com.bumptech.glide.Glide;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
import de.beyondsoft.ownchat.data.prefs.StringPreference;
import de.beyondsoft.ownchat.di.InjectionHelper;
import de.beyondsoft.ownchat.model.User;
import de.beyondsoft.ownchat.utils.Constants;
import de.beyondsoft.ownchat.utils.DialogHandler;
import de.beyondsoft.ownchat.utils.FileUtils;
import de.beyondsoft.ownchat.utils.RuntimePermissionBaseFragment;
@@ -25,6 +27,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
@@ -37,6 +40,7 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnTextChanged;
import de.beyondsoft.ownchat.utils.ui.ViewUtils;
import de.hdodenhof.circleimageview.CircleImageView;
/**
@@ -61,6 +65,9 @@ public class ProfileFragment extends RuntimePermissionBaseFragment implements Pr
@BindView(R.id.profile_update_button)
Button mUpdateProfileButton;
@BindView(R.id.profile_avatar_progress_bar)
ProgressBar mProgressBar;
@Inject
@Named(AppPrefsConstants.NAME)
StringPreference mProfileNamePreference;
@@ -73,6 +80,10 @@ public class ProfileFragment extends RuntimePermissionBaseFragment implements Pr
@Named(AppPrefsConstants.PHONE_NUMBER)
StringPreference mPhoneNumberPreference;
@Inject
@Named(AppPrefsConstants.UPLOAD_MAX_SIZE)
LongPreference mUploadMaxSizePreference;
@Inject
ProfilePresenter mProfilePresenter;
@@ -95,10 +106,14 @@ public class ProfileFragment extends RuntimePermissionBaseFragment implements Pr
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
getActivity().setTitle(R.string.title_profile);
Glide.with(getActivity())
.load(mAvatarPreference.get())
.placeholder(R.drawable.avatar)
.into(mAvatarImageview);
ViewUtils.setProgressBarColor(mProgressBar, R.color.colorDefault);
if (!TextUtils.isEmpty(mPhoneNumberPreference.get())) {
mPhoneNumberEditText.setText(mPhoneNumberPreference.get());
}
@@ -134,6 +149,7 @@ public class ProfileFragment extends RuntimePermissionBaseFragment implements Pr
final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
try {
//noinspection WrongConstant
getActivity().getContentResolver().takePersistableUriPermission(uri, takeFlags);
} catch (Exception e) {
e.printStackTrace();
@@ -144,6 +160,16 @@ public class ProfileFragment extends RuntimePermissionBaseFragment implements Pr
mProfilePresenter.attachView(this);
}
mProgressBar.setVisibility(View.VISIBLE);
File file = new File(uri.getPath());
if(mUploadMaxSizePreference.get() > 0 && file.length() > mUploadMaxSizePreference.get()) {
mProgressBar.setVisibility(View.GONE);
showError(R.string.error_file_is_too_large);
return;
}
mCallback.uploadImage(uri);
}
}
@@ -179,10 +205,13 @@ public class ProfileFragment extends RuntimePermissionBaseFragment implements Pr
@Override
public void refreshImage(String imageUrl) {
mProgressBar.setVisibility(View.GONE);
Glide.with(getContext())
.load(imageUrl)
.error(R.drawable.avatar)
.into(mAvatarImageview);
mAvatarPreference.set(imageUrl);
}
@@ -210,8 +239,7 @@ public class ProfileFragment extends RuntimePermissionBaseFragment implements Pr
@OnTextChanged(value = R.id.profile_phone_number, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
void phoneNumberChanged() {
mUpdateProfileButton.setEnabled(!TextUtils.isEmpty(mPhoneNumberEditText.getText().toString())
&& mPhoneNumberEditText.getText().toString().trim().length() > 0);
mUpdateProfileButton.setEnabled(!TextUtils.isEmpty(mPhoneNumberEditText.getText().toString()) && mPhoneNumberEditText.getText().toString().trim().length() > 0);
}
@Override
@@ -227,12 +255,14 @@ public class ProfileFragment extends RuntimePermissionBaseFragment implements Pr
private void selectFile() {
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
} else {
intent = new Intent(Intent.ACTION_GET_CONTENT);
}
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

View File

@@ -4,17 +4,27 @@ import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.api.common.ErrorHandlingResponseConverter;
import de.beyondsoft.ownchat.data.api.services.ProfileService;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
import de.beyondsoft.ownchat.data.prefs.StringPreference;
import de.beyondsoft.ownchat.di.scopes.ActivityScope;
import de.beyondsoft.ownchat.model.User;
import de.beyondsoft.ownchat.page.mvp.MVPAbstractPresenter;
import de.beyondsoft.ownchat.utils.Constants;
import de.beyondsoft.ownchat.utils.FileUtils;
import de.beyondsoft.ownchat.utils.SystemUtils;
import de.beyondsoft.ownchat.utils.rx.RxUtils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.view.View;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.inject.Inject;
import javax.inject.Named;
@@ -41,6 +51,13 @@ class ProfilePresenter extends MVPAbstractPresenter<ProfileView> implements Prof
@Named(AppPrefsConstants.LOGIN_TOKEN)
StringPreference mToken;
@Inject
@Named(AppPrefsConstants.UPLOAD_MAX_SIZE)
LongPreference mUploadMaxSizePreference;
@Inject
Context mContext;
@Inject
ProfilePresenter() {
}
@@ -96,13 +113,28 @@ class ProfilePresenter extends MVPAbstractPresenter<ProfileView> implements Prof
return;
}
File file = getView().getFile(uri);
File file = FileUtils.getFile(mContext, uri);
String mimeType = FileUtils.getMimeType(file);
if(mUploadMaxSizePreference.get() > 0 && file.length() > mUploadMaxSizePreference.get()) {
getView().showError(R.string.error_file_is_too_large);
return;
}
if(mimeType != null && (mimeType.equals(Constants.MIME_TYPE_JPEG) || mimeType.equals(Constants.MIME_TYPE_PNG)) && (file.length() > (1000L * 1024L))) {
FileUtils.clearTmpFilesDir(mContext);
file = FileUtils.scaleImageDown(file, mContext);
}
RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part part = MultipartBody.Part.createFormData("picture", file.getName(), requestBody);
final Subscription subscription = mProfileService.uploadProfileImage(part)
.compose(RxUtils.provideDefaultTransformer())
.map(uploadImageResponse -> uploadImageResponse.response.picture)
.subscribe(this::uploadImageSuccess, this::profileError);
addSubscription(subscription);
}
@@ -128,5 +160,4 @@ class ProfilePresenter extends MVPAbstractPresenter<ProfileView> implements Prof
getView().refreshImage(imageResponse);
getView().showError(R.string.profile_updated);
}
}

View File

@@ -0,0 +1,173 @@
package de.beyondsoft.ownchat.page.sharing;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import java.util.ArrayList;
import javax.inject.Inject;
import javax.inject.Named;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.prefs.BooleanPreference;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
import de.beyondsoft.ownchat.data.prefs.StringPreference;
import de.beyondsoft.ownchat.di.InjectionHelper;
import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.page.chat.GroupChatActivity;
import de.beyondsoft.ownchat.page.chat.SingleChatActivity;
import de.beyondsoft.ownchat.page.login.LoginActivity;
import de.beyondsoft.ownchat.utils.ui.EmptyLayout;
import de.beyondsoft.ownchat.utils.ui.HorizontalDividerItemDecoration;
/**
* Created by Lyndon on 03-Nov-2017.
*/
public class SharingActivity extends AppCompatActivity implements SharingView, SharingContactsAdapter.OnOpenClickListener {
@Inject
SharingPresenter mSharingPresenter;
@Inject
@Named(AppPrefsConstants.LOGIN_TOKEN)
StringPreference mLoginTokenPreference;
@Inject
@Named(AppPrefsConstants.USER_ID)
LongPreference mUserIdPreference;
@BindView(R.id.sharing_contacts_recycler_view)
RecyclerView mContactsRecyclerView;
@BindView(R.id.sharing_contacts_coordinator_layout)
CoordinatorLayout mCoordinatorLayout;
@BindView(R.id.sharing_contacts_empty_layout)
EmptyLayout mEmptyLayout;
@BindView(R.id.chat_toolbar_single_title)
TextView mSingleChatTitleTextView;
@Inject
@Named(AppPrefsConstants.PATH_TO_FILE_TO_SHARE)
StringPreference mSelectedFilePath;
@Inject
@Named(AppPrefsConstants.IS_COMING_FROM_SHARING_ACTIVITY)
BooleanPreference mIsComingFromSharingActivity;
private SharingView.Callback mCallback;
private SharingContactsAdapter mContactsAdapter;
private Snackbar mSnackbar;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sharing);
InjectionHelper.getSharingComponent(this).inject(this);
ButterKnife.bind(this);
mSharingPresenter.attachView(this);
mContactsRecyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(this).colorResId(R.color.colorFill).build());
mContactsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mContactsAdapter = new SharingContactsAdapter(this, mUserIdPreference.get());
mContactsRecyclerView.setAdapter(mContactsAdapter);
setToolBar();
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
handleSendFile(intent);
}
}
private void setToolBar() {
mSingleChatTitleTextView.setVisibility(View.VISIBLE);
mSingleChatTitleTextView.setText(R.string.sharing_title);
}
void handleSendFile(Intent intent) {
Uri fileUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (fileUri != null) {
mSelectedFilePath.set(fileUri.toString());
mIsComingFromSharingActivity.set(true);
if (!mLoginTokenPreference.isSet()) {
startActivity(new Intent(this, LoginActivity.class));
finishAffinity();
}
}
}
@Override
public void onResume() {
super.onResume();
mCallback.loadGroups();
mCallback.loadGroupsFromDB();
}
@Override
public void showError(@StringRes int message) {
if (mSnackbar == null) {
mSnackbar = Snackbar.make(mCoordinatorLayout, message, Snackbar.LENGTH_LONG);
mSnackbar.setActionTextColor(ContextCompat.getColor(this, R.color.colorDefault));
}
mSnackbar.setText(message);
mSnackbar.show();
}
@Override
public void onOpenGroupMessage(Group group) {
startActivity(GroupChatActivity.createIntent(this, group));
finishAffinity();
}
@Override
public void onOpenPrivateMessage(Group contact) {
startActivity(SingleChatActivity.createIntent(this, contact));
finishAffinity();
}
@Override
public void setCallback(Callback callback) {
mCallback = callback;
}
@Override
public void showProgress() {
mEmptyLayout.showLoading();
}
@Override
public void hideProgress() {
mEmptyLayout.setVisibility(View.GONE);
}
@Override
public void setGroups(ArrayList<Group> groups) {
mContactsAdapter.setGroups(groups);
}
}

View File

@@ -0,0 +1,15 @@
package de.beyondsoft.ownchat.page.sharing;
import dagger.Component;
import de.beyondsoft.ownchat.di.ApplicationComponent;
import de.beyondsoft.ownchat.di.scopes.ActivityScope;
/**
* Created by Lyndon on 03-Nov-2017.
*/
@ActivityScope
@Component(dependencies = ApplicationComponent.class, modules = SharingModule.class)
public interface SharingComponent {
void inject(SharingActivity sharingActivity);
}

View File

@@ -0,0 +1,130 @@
package de.beyondsoft.ownchat.page.sharing;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.model.Group;
import de.hdodenhof.circleimageview.CircleImageView;
/**
* Created by Lyndon on 03-Nov-2017.
*/
public class SharingContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int GROUP_TYPE = 0;
private static final int CONTACT_TYPE = 1;
private ArrayList<Group> mGroups;
private SharingContactsAdapter.OnOpenClickListener mItemClickListener;
private long mUserId;
interface OnOpenClickListener {
void onOpenGroupMessage(Group group);
void onOpenPrivateMessage(Group contact);
}
SharingContactsAdapter(OnOpenClickListener openClickListener, long userId) {
mItemClickListener = openClickListener;
mGroups = new ArrayList<>();
mUserId = userId;
}
void setGroups(ArrayList<Group> groups) {
mGroups.clear();
if (groups != null) {
mGroups.addAll(groups);
}
notifyDataSetChanged();
}
@Override
public final int getItemViewType(int position) {
if (mGroups.get(position).users.size() > 2) {
return GROUP_TYPE;
}
return CONTACT_TYPE;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_sharing_contact, parent, false);
return new SharingContactsAdapter.SharingContactViewHolder(view);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Group group = mGroups.get(position);
SharingContactsAdapter.SharingContactViewHolder viewHolder = (SharingContactsAdapter.SharingContactViewHolder) holder;
int type = getItemViewType(position);
if (type == GROUP_TYPE) {
viewHolder.name.setText(group.name);
viewHolder.name.setTextColor(ContextCompat.getColor(viewHolder.name.getContext(), group.isHelpGroup() ? R.color.colorHelpGroup : R.color.colorTeamGroup));
viewHolder.avatar.setImageResource(group.isHelpGroup() ? R.drawable.avatar_help_group : R.drawable.avatar_team_group);
return;
} else if(!group.onlyEmployees) {
viewHolder.avatar.setImageResource(R.drawable.avatar_help);
}
if(type == CONTACT_TYPE) {
viewHolder.name.setTextColor(ContextCompat.getColor(viewHolder.name.getContext(), group.isEmployee(mGroups.get(position).users) ? R.color.colorBlack : R.color.colorHelpGroup));
}
viewHolder.name.setText(group.name);
Glide.with(viewHolder.avatar.getContext()).load(group.avatar)
.placeholder(group.onlyEmployees ? R.drawable.avatar_list : R.drawable.avatar_help)
.dontAnimate()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(viewHolder.avatar);
}
@Override
public int getItemCount() {
return mGroups.size();
}
class SharingContactViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.sharing_contact_avatar)
CircleImageView avatar;
@BindView(R.id.sharing_contact_name)
TextView name;
SharingContactViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
@OnClick(R.id.sharing_contact_container)
void onClickContact() {
int type = getItemViewType();
if (type == GROUP_TYPE) {
mItemClickListener.onOpenGroupMessage(mGroups.get(getAdapterPosition()));
return;
}
mItemClickListener.onOpenPrivateMessage(mGroups.get(getAdapterPosition()));
}
}
}

View File

@@ -0,0 +1,21 @@
package de.beyondsoft.ownchat.page.sharing;
import dagger.Module;
import dagger.Provides;
import de.beyondsoft.ownchat.data.api.services.ChatService;
import de.beyondsoft.ownchat.di.P3DSEndpoint;
import de.beyondsoft.ownchat.di.scopes.ActivityScope;
import retrofit2.Retrofit;
/**
* Created by Lyndon on 03-Nov-2017.
*/
@Module
public class SharingModule {
@Provides
@ActivityScope
ChatService provideChatService(@P3DSEndpoint Retrofit retrofit) {
return retrofit.create(ChatService.class);
}
}

View File

@@ -0,0 +1,180 @@
package de.beyondsoft.ownchat.page.sharing;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.util.Log;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.util.ArrayList;
import javax.inject.Inject;
import javax.inject.Named;
import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.api.common.ErrorHandlingResponseConverter;
import de.beyondsoft.ownchat.data.api.responses.MessageResponse;
import de.beyondsoft.ownchat.data.api.services.ChatService;
import de.beyondsoft.ownchat.data.events.GroupUpdatedEvent;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
import de.beyondsoft.ownchat.data.prefs.StringPreference;
import de.beyondsoft.ownchat.data.repository.GroupRealmRepository;
import de.beyondsoft.ownchat.data.repository.RealmProvider;
import de.beyondsoft.ownchat.data.repository.UserRealmRepository;
import de.beyondsoft.ownchat.data.repository.specifications.GroupByIdSpecification;
import de.beyondsoft.ownchat.data.repository.specifications.GroupSpecification;
import de.beyondsoft.ownchat.data.repository.specifications.MessageByIdSpecification;
import de.beyondsoft.ownchat.data.repository.specifications.UserByIdSpecification;
import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.model.Message;
import de.beyondsoft.ownchat.page.mvp.MVPAbstractPresenter;
import de.beyondsoft.ownchat.utils.Constants;
import de.beyondsoft.ownchat.utils.FileUtils;
import de.beyondsoft.ownchat.utils.SystemUtils;
import de.beyondsoft.ownchat.utils.rx.RxUtils;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import rx.Completable;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Created by Lyndon on 03-Nov-2017.
*/
public class SharingPresenter extends MVPAbstractPresenter<SharingView> implements SharingView.Callback {
@Inject
Context mContext;
@Inject
ChatService mChatService;
@Inject
GroupRealmRepository mGroupRealmRepository;
@Inject
UserRealmRepository mUserRealmRepository;
@Inject
SystemUtils mSystemUtils;
@Inject
@Named(AppPrefsConstants.USER_ID)
LongPreference mUserIdReference;
@Inject
@Named(AppPrefsConstants.AVATAR)
StringPreference mAvatarPreference;
@Inject
@Named(AppPrefsConstants.NAME)
StringPreference mProfileNamePreference;
@Inject
@Named(AppPrefsConstants.UPLOAD_MAX_SIZE)
LongPreference mUploadMaxSizePreference;
@Inject
RealmProvider mRealmProvider;
@Inject
SharingPresenter() {}
@Override
protected void afterAttachView(@NonNull SharingView view) {
super.afterAttachView(view);
view.setCallback(this);
view.showProgress();
}
@Override
protected void beforeDetachView(@NonNull SharingView view) {
view.setCallback(null);
super.beforeDetachView(view);
}
@Override
public void loadGroups() {
Subscription subscription = mChatService.getGroups()
.flatMap(new ErrorHandlingResponseConverter<>())
.flatMap(groupResponse -> {
if (groupResponse.response.groups != null) {
for (Group group : groupResponse.response.groups) {
group.userId = mUserIdReference.get();
if (group.lastMessage != null) {
group.lastMessage.status = Message.Status.DELIVERED;
group.lastMessage.userId = mUserIdReference.get();
}
mUserRealmRepository.update(group.users, new UserByIdSpecification()).subscribe();
}
}
return Observable.just(groupResponse.response.groups);
})
.compose(RxUtils.provideDefaultTransformer())
.subscribe(this::groupsSuccess, this::groupsError);
addSubscription(subscription);
}
private void groupsError(Throwable throwable) {
if (mSystemUtils.isNetworkUnavailable()) {
getView().showError(R.string.error_no_internet_connection);
return;
}
getView().showError(R.string.error_something_went_wrong);
}
private void groupsSuccess(ArrayList<Group> groups) {
mGroupRealmRepository.update(groups, new GroupByIdSpecification(mUserIdReference.get()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Object>() {
@Override
public void onCompleted() {
loadGroupsFromDB();
}
@Override
public void onError(Throwable e) {
Log.e(SharingPresenter.class.getSimpleName(), e.getMessage(), e);
}
@Override
public void onNext(Object o) {
// nop here
}
});
}
@Override
public void loadGroupsFromDB() {
GroupSpecification groupSpecification = new GroupSpecification(mUserIdReference.get());
mGroupRealmRepository.queryForAll(groupSpecification)
.map(ArrayList::new)
.compose(RxUtils.provideDefaultTransformer())
.subscribe(this::loadGroupsFromDBSuccessful, this::loadGroupsError);
}
private void loadGroupsFromDBSuccessful(ArrayList<Group> groups) {
if (!isAttached()) {
return;
}
getView().hideProgress();
getView().setGroups(groups);
}
private void loadGroupsError(Throwable throwable) {
Log.e(SharingPresenter.class.getSimpleName(), throwable.getMessage(), throwable);
}
}

View File

@@ -0,0 +1,30 @@
package de.beyondsoft.ownchat.page.sharing;
import android.support.annotation.StringRes;
import java.util.ArrayList;
import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.page.mvp.MVPView;
/**
* Created by Lyndon on 03-Nov-2017.
*/
public interface SharingView extends MVPView {
void setCallback(Callback setCallback);
void showProgress();
void hideProgress();
void setGroups(ArrayList<Group> groups);
void showError(@StringRes int message);
interface Callback {
void loadGroups();
void loadGroupsFromDB();
}
}

View File

@@ -47,9 +47,7 @@ public class AppStoppedService extends Service {
@Override
public void onTaskRemoved(Intent rootIntent) {
mAppKilledPreference.set(true);
if (!mSavedPasswordPref.get()) {
mNotificationManager.cancelAll();
}
stopSelf();
}
}

View File

@@ -23,4 +23,13 @@ public interface Constants {
String CHAT_IS_ALREADY_OPEN = "chat_is_already_open";
String KEY_TEXT_REPLY = "key_text_reply";
String FILE_PATH = "file_uri";
String FILE_MESSAGE_TEXT = "file_message_text";
String EXTRA_GROUP = "group";
String MIME_TYPE_JPEG = "image/jpeg";
String MIME_TYPE_PNG = "image/png";
String MIME_TYPE_GIF = "image/gif";
String TMP_FILE_DIR = "tmp_files";
}

View File

@@ -21,18 +21,25 @@ import android.content.Intent;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.ContactsContract;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Log;
import android.webkit.MimeTypeMap;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
/**
* @author Peli
@@ -49,11 +56,616 @@ public class FileUtils {
public static final String MIME_TYPE_AUDIO = "audio/*";
public static final String MIME_TYPE_TEXT = "text/*";
public static final String MIME_TYPE_IMAGE = "image/*";
private static final String MIME_TYPE_IMAGE = "image/*";
public static final String MIME_TYPE_VIDEO = "video/*";
public static final String MIME_TYPE_APP = "application/*";
public static final String HIDDEN_PREFIX = ".";
private static final String HIDDEN_PREFIX = ".";
private static final HashMap<String, String> types = new HashMap<>();
private static HashMap<String, String> getTypes() {
if(types.size() == 0) {
Log.d("GETTING_MIME_TYPES", "types have a size of 0");
types.put("323","text/h323");
types.put("3g2","video/3gpp2");
types.put("3gp","video/3gpp");
types.put("3gp2","video/3gpp2");
types.put("3gpp","video/3gpp");
types.put("7z","application/x-7z-compressed");
types.put("aa","audio/audible");
types.put("AAC","audio/aac");
types.put("aaf","application/octet-stream");
types.put("aax","audio/vnd.audible.aax");
types.put("ac3","audio/ac3");
types.put("aca","application/octet-stream");
types.put("accda","application/msaccess.addin");
types.put("accdb","application/msaccess");
types.put("accdc","application/msaccess.cab");
types.put("accde","application/msaccess");
types.put("accdr","application/msaccess.runtime");
types.put("accdt","application/msaccess");
types.put("accdw","application/msaccess.webapplication");
types.put("accft","application/msaccess.ftemplate");
types.put("acx","application/internet-property-stream");
types.put("AddIn","text/xml");
types.put("ade","application/msaccess");
types.put("adobebridge","application/x-bridge-url");
types.put("adp","application/msaccess");
types.put("ADT","audio/vnd.dlna.adts");
types.put("ADTS","audio/aac");
types.put("afm","application/octet-stream");
types.put("ai","application/postscript");
types.put("aif","audio/aiff");
types.put("aifc","audio/aiff");
types.put("aiff","audio/aiff");
types.put("air","application/vnd.adobe.air-application-installer-package+zip");
types.put("amc","application/mpeg");
types.put("anx","application/annodex");
types.put("apk","application/vnd.android.package-archive");
types.put("application","application/x-ms-application");
types.put("art","image/x-jg");
types.put("asa","application/xml");
types.put("asax","application/xml");
types.put("ascx","application/xml");
types.put("asd","application/octet-stream");
types.put("asf","video/x-ms-asf");
types.put("ashx","application/xml");
types.put("asi","application/octet-stream");
types.put("asm","text/plain");
types.put("asmx","application/xml");
types.put("aspx","application/xml");
types.put("asr","video/x-ms-asf");
types.put("asx","video/x-ms-asf");
types.put("atom","application/atom+xml");
types.put("au","audio/basic");
types.put("avi","video/x-msvideo");
types.put("axa","audio/annodex");
types.put("axs","application/olescript");
types.put("axv","video/annodex");
types.put("bas","text/plain");
types.put("bcpio","application/x-bcpio");
types.put("bin","application/octet-stream");
types.put("bmp","image/bmp");
types.put("c","text/plain");
types.put("cab","application/octet-stream");
types.put("caf","audio/x-caf");
types.put("calx","application/vnd.ms-office.calx");
types.put("cat","application/vnd.ms-pki.seccat");
types.put("cc","text/plain");
types.put("cd","text/plain");
types.put("cdda","audio/aiff");
types.put("cdf","application/x-cdf");
types.put("cer","application/x-x509-ca-cert");
types.put("cfg","text/plain");
types.put("chm","application/octet-stream");
types.put("class","application/x-java-applet");
types.put("clp","application/x-msclip");
types.put("cmd","text/plain");
types.put("cmx","image/x-cmx");
types.put("cnf","text/plain");
types.put("cod","image/cis-cod");
types.put("config","application/xml");
types.put("contact","text/x-ms-contact");
types.put("coverage","application/xml");
types.put("cpio","application/x-cpio");
types.put("cpp","text/plain");
types.put("crd","application/x-mscardfile");
types.put("crl","application/pkix-crl");
types.put("crt","application/x-x509-ca-cert");
types.put("cs","text/plain");
types.put("csdproj","text/plain");
types.put("csh","application/x-csh");
types.put("csproj","text/plain");
types.put("css","text/css");
types.put("csv","text/csv");
types.put("cur","application/octet-stream");
types.put("cxx","text/plain");
types.put("dat","application/octet-stream");
types.put("datasource","application/xml");
types.put("dbproj","text/plain");
types.put("dcr","application/x-director");
types.put("def","text/plain");
types.put("deploy","application/octet-stream");
types.put("der","application/x-x509-ca-cert");
types.put("dgml","application/xml");
types.put("dib","image/bmp");
types.put("dif","video/x-dv");
types.put("dir","application/x-director");
types.put("disco","text/xml");
types.put("divx","video/divx");
types.put("dll","application/x-msdownload");
types.put("dll.config","text/xml");
types.put("dlm","text/dlm");
types.put("doc","application/msword");
types.put("docm","application/vnd.ms-word.document.macroEnabled.12");
types.put("docx","application/vnd.openxmlformats-officedocument.wordprocessingml.document");
types.put("dot","application/msword");
types.put("dotm","application/vnd.ms-word.template.macroEnabled.12");
types.put("dotx","application/vnd.openxmlformats-officedocument.wordprocessingml.template");
types.put("dsp","application/octet-stream");
types.put("dsw","text/plain");
types.put("dtd","text/xml");
types.put("dtsConfig","text/xml");
types.put("dv","video/x-dv");
types.put("dvi","application/x-dvi");
types.put("dwf","drawing/x-dwf");
types.put("dwp","application/octet-stream");
types.put("dxr","application/x-director");
types.put("eml","message/rfc822");
types.put("emz","application/octet-stream");
types.put("eot","application/vnd.ms-fontobject");
types.put("eps","application/postscript");
types.put("etl","application/etl");
types.put("etx","text/x-setext");
types.put("evy","application/envoy");
types.put("exe","application/octet-stream");
types.put("exe.config","text/xml");
types.put("fdf","application/vnd.fdf");
types.put("fif","application/fractals");
types.put("filters","application/xml");
types.put("fla","application/octet-stream");
types.put("flac","audio/flac");
types.put("flr","x-world/x-vrml");
types.put("flv","video/x-flv");
types.put("fsscript","application/fsharp-script");
types.put("fsx","application/fsharp-script");
types.put("generictest","application/xml");
types.put("gif","image/gif");
types.put("group","text/x-ms-group");
types.put("gsm","audio/x-gsm");
types.put("gtar","application/x-gtar");
types.put("gz","application/x-gzip");
types.put("h","text/plain");
types.put("hdf","application/x-hdf");
types.put("hdml","text/x-hdml");
types.put("hhc","application/x-oleobject");
types.put("hhk","application/octet-stream");
types.put("hhp","application/octet-stream");
types.put("hlp","application/winhlp");
types.put("hpp","text/plain");
types.put("hqx","application/mac-binhex40");
types.put("hta","application/hta");
types.put("htc","text/x-component");
types.put("htm","text/html");
types.put("html","text/html");
types.put("htt","text/webviewhtml");
types.put("hxa","application/xml");
types.put("hxc","application/xml");
types.put("hxd","application/octet-stream");
types.put("hxe","application/xml");
types.put("hxf","application/xml");
types.put("hxh","application/octet-stream");
types.put("hxi","application/octet-stream");
types.put("hxk","application/xml");
types.put("hxq","application/octet-stream");
types.put("hxr","application/octet-stream");
types.put("hxs","application/octet-stream");
types.put("hxt","text/html");
types.put("hxv","application/xml");
types.put("hxw","application/octet-stream");
types.put("hxx","text/plain");
types.put("i","text/plain");
types.put("ico","image/x-icon");
types.put("ics","application/octet-stream");
types.put("idl","text/plain");
types.put("ief","image/ief");
types.put("iii","application/x-iphone");
types.put("inc","text/plain");
types.put("inf","application/octet-stream");
types.put("ini","text/plain");
types.put("inl","text/plain");
types.put("ins","application/x-internet-signup");
types.put("ipa","application/x-itunes-ipa");
types.put("ipg","application/x-itunes-ipg");
types.put("ipproj","text/plain");
types.put("ipsw","application/x-itunes-ipsw");
types.put("iqy","text/x-ms-iqy");
types.put("isp","application/x-internet-signup");
types.put("ite","application/x-itunes-ite");
types.put("itlp","application/x-itunes-itlp");
types.put("itms","application/x-itunes-itms");
types.put("itpc","application/x-itunes-itpc");
types.put("IVF","video/x-ivf");
types.put("jar","application/java-archive");
types.put("java","application/octet-stream");
types.put("jck","application/liquidmotion");
types.put("jcz","application/liquidmotion");
types.put("jfif","image/pjpeg");
types.put("jnlp","application/x-java-jnlp-file");
types.put("jpb","application/octet-stream");
types.put("jpe","image/jpeg");
types.put("jpeg","image/jpeg");
types.put("jpg","image/jpeg");
types.put("js","application/javascript");
types.put("json","application/json");
types.put("jsx","text/jscript");
types.put("jsxbin","text/plain");
types.put("latex","application/x-latex");
types.put("library-ms","application/windows-library+xml");
types.put("lit","application/x-ms-reader");
types.put("loadtest","application/xml");
types.put("lpk","application/octet-stream");
types.put("lsf","video/x-la-asf");
types.put("lst","text/plain");
types.put("lsx","video/x-la-asf");
types.put("lzh","application/octet-stream");
types.put("m13","application/x-msmediaview");
types.put("m14","application/x-msmediaview");
types.put("m1v","video/mpeg");
types.put("m2t","video/vnd.dlna.mpeg-tts");
types.put("m2ts","video/vnd.dlna.mpeg-tts");
types.put("m2v","video/mpeg");
types.put("m3u","audio/x-mpegurl");
types.put("m3u8","audio/x-mpegurl");
types.put("m4a","audio/m4a");
types.put("m4b","audio/m4b");
types.put("m4p","audio/m4p");
types.put("m4r","audio/x-m4r");
types.put("m4v","video/x-m4v");
types.put("mac","image/x-macpaint");
types.put("mak","text/plain");
types.put("man","application/x-troff-man");
types.put("manifest","application/x-ms-manifest");
types.put("map","text/plain");
types.put("master","application/xml");
types.put("mda","application/msaccess");
types.put("mdb","application/x-msaccess");
types.put("mde","application/msaccess");
types.put("mdp","application/octet-stream");
types.put("me","application/x-troff-me");
types.put("mfp","application/x-shockwave-flash");
types.put("mht","message/rfc822");
types.put("mhtml","message/rfc822");
types.put("mid","audio/mid");
types.put("midi","audio/mid");
types.put("mix","application/octet-stream");
types.put("mk","text/plain");
types.put("mmf","application/x-smaf");
types.put("mno","text/xml");
types.put("mny","application/x-msmoney");
types.put("mod","video/mpeg");
types.put("mov","video/quicktime");
types.put("movie","video/x-sgi-movie");
types.put("mp2","video/mpeg");
types.put("mp2v","video/mpeg");
types.put("mp3","audio/mpeg");
types.put("mp4","video/mp4");
types.put("mp4v","video/mp4");
types.put("mpa","video/mpeg");
types.put("mpe","video/mpeg");
types.put("mpeg","video/mpeg");
types.put("mpf","application/vnd.ms-mediapackage");
types.put("mpg","video/mpeg");
types.put("mpp","application/vnd.ms-project");
types.put("mpv2","video/mpeg");
types.put("mqv","video/quicktime");
types.put("ms","application/x-troff-ms");
types.put("msi","application/octet-stream");
types.put("mso","application/octet-stream");
types.put("mts","video/vnd.dlna.mpeg-tts");
types.put("mtx","application/xml");
types.put("mvb","application/x-msmediaview");
types.put("mvc","application/x-miva-compiled");
types.put("mxp","application/x-mmxp");
types.put("nc","application/x-netcdf");
types.put("nsc","video/x-ms-asf");
types.put("nws","message/rfc822");
types.put("ocx","application/octet-stream");
types.put("oda","application/oda");
types.put("odb","application/vnd.oasis.opendocument.database");
types.put("odc","application/vnd.oasis.opendocument.chart");
types.put("odf","application/vnd.oasis.opendocument.formula");
types.put("odg","application/vnd.oasis.opendocument.graphics");
types.put("odh","text/plain");
types.put("odi","application/vnd.oasis.opendocument.image");
types.put("odl","text/plain");
types.put("odm","application/vnd.oasis.opendocument.text-master");
types.put("odp","application/vnd.oasis.opendocument.presentation");
types.put("ods","application/vnd.oasis.opendocument.spreadsheet");
types.put("odt","application/vnd.oasis.opendocument.text");
types.put("oga","audio/ogg");
types.put("ogg","audio/ogg");
types.put("ogv","video/ogg");
types.put("ogx","application/ogg");
types.put("one","application/onenote");
types.put("onea","application/onenote");
types.put("onepkg","application/onenote");
types.put("onetmp","application/onenote");
types.put("onetoc","application/onenote");
types.put("onetoc2","application/onenote");
types.put("opus","audio/ogg");
types.put("orderedtest","application/xml");
types.put("osdx","application/opensearchdescription+xml");
types.put("otf","application/font-sfnt");
types.put("otg","application/vnd.oasis.opendocument.graphics-template");
types.put("oth","application/vnd.oasis.opendocument.text-web");
types.put("otp","application/vnd.oasis.opendocument.presentation-template");
types.put("ots","application/vnd.oasis.opendocument.spreadsheet-template");
types.put("ott","application/vnd.oasis.opendocument.text-template");
types.put("oxt","application/vnd.openofficeorg.extension");
types.put("p10","application/pkcs10");
types.put("p12","application/x-pkcs12");
types.put("p7b","application/x-pkcs7-certificates");
types.put("p7c","application/pkcs7-mime");
types.put("p7m","application/pkcs7-mime");
types.put("p7r","application/x-pkcs7-certreqresp");
types.put("p7s","application/pkcs7-signature");
types.put("pbm","image/x-portable-bitmap");
types.put("pcast","application/x-podcast");
types.put("pct","image/pict");
types.put("pcx","application/octet-stream");
types.put("pcz","application/octet-stream");
types.put("pdf","application/pdf");
types.put("pfb","application/octet-stream");
types.put("pfm","application/octet-stream");
types.put("pfx","application/x-pkcs12");
types.put("pgm","image/x-portable-graymap");
types.put("pic","image/pict");
types.put("pict","image/pict");
types.put("pkgdef","text/plain");
types.put("pkgundef","text/plain");
types.put("pko","application/vnd.ms-pki.pko");
types.put("pls","audio/scpls");
types.put("pma","application/x-perfmon");
types.put("pmc","application/x-perfmon");
types.put("pml","application/x-perfmon");
types.put("pmr","application/x-perfmon");
types.put("pmw","application/x-perfmon");
types.put("png","image/png");
types.put("pnm","image/x-portable-anymap");
types.put("pnt","image/x-macpaint");
types.put("pntg","image/x-macpaint");
types.put("pnz","image/png");
types.put("pot","application/vnd.ms-powerpoint");
types.put("potm","application/vnd.ms-powerpoint.template.macroEnabled.12");
types.put("potx","application/vnd.openxmlformats-officedocument.presentationml.template");
types.put("ppa","application/vnd.ms-powerpoint");
types.put("ppam","application/vnd.ms-powerpoint.addin.macroEnabled.12");
types.put("ppm","image/x-portable-pixmap");
types.put("pps","application/vnd.ms-powerpoint");
types.put("ppsm","application/vnd.ms-powerpoint.slideshow.macroEnabled.12");
types.put("ppsx","application/vnd.openxmlformats-officedocument.presentationml.slideshow");
types.put("ppt","application/vnd.ms-powerpoint");
types.put("pptm","application/vnd.ms-powerpoint.presentation.macroEnabled.12");
types.put("pptx","application/vnd.openxmlformats-officedocument.presentationml.presentation");
types.put("prf","application/pics-rules");
types.put("prm","application/octet-stream");
types.put("prx","application/octet-stream");
types.put("ps","application/postscript");
types.put("psc1","application/PowerShell");
types.put("psd","application/octet-stream");
types.put("psess","application/xml");
types.put("psm","application/octet-stream");
types.put("psp","application/octet-stream");
types.put("pub","application/x-mspublisher");
types.put("pwz","application/vnd.ms-powerpoint");
types.put("qht","text/x-html-insertion");
types.put("qhtm","text/x-html-insertion");
types.put("qt","video/quicktime");
types.put("qti","image/x-quicktime");
types.put("qtif","image/x-quicktime");
types.put("qtl","application/x-quicktimeplayer");
types.put("qxd","application/octet-stream");
types.put("ra","audio/x-pn-realaudio");
types.put("ram","audio/x-pn-realaudio");
types.put("rar","application/x-rar-compressed");
types.put("ras","image/x-cmu-raster");
types.put("rat","application/rat-file");
types.put("rc","text/plain");
types.put("rc2","text/plain");
types.put("rct","text/plain");
types.put("rdlc","application/xml");
types.put("reg","text/plain");
types.put("resx","application/xml");
types.put("rf","image/vnd.rn-realflash");
types.put("rgb","image/x-rgb");
types.put("rgs","text/plain");
types.put("rm","application/vnd.rn-realmedia");
types.put("rmi","audio/mid");
types.put("rmp","application/vnd.rn-rn_music_package");
types.put("roff","application/x-troff");
types.put("rpm","audio/x-pn-realaudio-plugin");
types.put("rqy","text/x-ms-rqy");
types.put("rtf","application/rtf");
types.put("rtx","text/richtext");
types.put("ruleset","application/xml");
types.put("s","text/plain");
types.put("safariextz","application/x-safari-safariextz");
types.put("scd","application/x-msschedule");
types.put("scr","text/plain");
types.put("sct","text/scriptlet");
types.put("sd2","audio/x-sd2");
types.put("sdp","application/sdp");
types.put("sea","application/octet-stream");
types.put("searchConnector-ms","application/windows-search-connector+xml");
types.put("setpay","application/set-payment-initiation");
types.put("setreg","application/set-registration-initiation");
types.put("settings","application/xml");
types.put("sgimb","application/x-sgimb");
types.put("sgml","text/sgml");
types.put("sh","application/x-sh");
types.put("shar","application/x-shar");
types.put("shtml","text/html");
types.put("sit","application/x-stuffit");
types.put("sitemap","application/xml");
types.put("skin","application/xml");
types.put("sldm","application/vnd.ms-powerpoint.slide.macroEnabled.12");
types.put("sldx","application/vnd.openxmlformats-officedocument.presentationml.slide");
types.put("slk","application/vnd.ms-excel");
types.put("sln","text/plain");
types.put("slupkg-ms","application/x-ms-license");
types.put("smd","audio/x-smd");
types.put("smi","application/octet-stream");
types.put("smx","audio/x-smd");
types.put("smz","audio/x-smd");
types.put("snd","audio/basic");
types.put("snippet","application/xml");
types.put("snp","application/octet-stream");
types.put("sol","text/plain");
types.put("sor","text/plain");
types.put("spc","application/x-pkcs7-certificates");
types.put("spl","application/futuresplash");
types.put("spx","audio/ogg");
types.put("src","application/x-wais-source");
types.put("srf","text/plain");
types.put("SSISDeploymentManifest","text/xml");
types.put("ssm","application/streamingmedia");
types.put("sst","application/vnd.ms-pki.certstore");
types.put("stl","application/vnd.ms-pki.stl");
types.put("sv4cpio","application/x-sv4cpio");
types.put("sv4crc","application/x-sv4crc");
types.put("svc","application/xml");
types.put("svg","image/svg+xml");
types.put("swf","application/x-shockwave-flash");
types.put("t","application/x-troff");
types.put("tar","application/x-tar");
types.put("tcl","application/x-tcl");
types.put("testrunconfig","application/xml");
types.put("testsettings","application/xml");
types.put("tex","application/x-tex");
types.put("texi","application/x-texinfo");
types.put("texinfo","application/x-texinfo");
types.put("tgz","application/x-compressed");
types.put("thmx","application/vnd.ms-officetheme");
types.put("thn","application/octet-stream");
types.put("tif","image/tiff");
types.put("tiff","image/tiff");
types.put("tlh","text/plain");
types.put("tli","text/plain");
types.put("toc","application/octet-stream");
types.put("tr","application/x-troff");
types.put("trm","application/x-msterminal");
types.put("trx","application/xml");
types.put("ts","video/vnd.dlna.mpeg-tts");
types.put("tsv","text/tab-separated-values");
types.put("ttf","application/font-sfnt");
types.put("tts","video/vnd.dlna.mpeg-tts");
types.put("txt","text/plain");
types.put("u32","application/octet-stream");
types.put("uls","text/iuls");
types.put("user","text/plain");
types.put("ustar","application/x-ustar");
types.put("vb","text/plain");
types.put("vbdproj","text/plain");
types.put("vbk","video/mpeg");
types.put("vbproj","text/plain");
types.put("vbs","text/vbscript");
types.put("vcf","text/x-vcard");
types.put("vcproj","application/xml");
types.put("vcs","text/plain");
types.put("vcxproj","application/xml");
types.put("vddproj","text/plain");
types.put("vdp","text/plain");
types.put("vdproj","text/plain");
types.put("vdx","application/vnd.ms-visio.viewer");
types.put("vml","text/xml");
types.put("vscontent","application/xml");
types.put("vsct","text/xml");
types.put("vsd","application/vnd.visio");
types.put("vsi","application/ms-vsi");
types.put("vsix","application/vsix");
types.put("vsixlangpack","text/xml");
types.put("vsixmanifest","text/xml");
types.put("vsmdi","application/xml");
types.put("vspscc","text/plain");
types.put("vss","application/vnd.visio");
types.put("vsscc","text/plain");
types.put("vssettings","text/xml");
types.put("vssscc","text/plain");
types.put("vst","application/vnd.visio");
types.put("vstemplate","text/xml");
types.put("vsto","application/x-ms-vsto");
types.put("vsw","application/vnd.visio");
types.put("vsx","application/vnd.visio");
types.put("vtx","application/vnd.visio");
types.put("wav","audio/wav");
types.put("wave","audio/wav");
types.put("wax","audio/x-ms-wax");
types.put("wbk","application/msword");
types.put("wbmp","image/vnd.wap.wbmp");
types.put("wcm","application/vnd.ms-works");
types.put("wdb","application/vnd.ms-works");
types.put("wdp","image/vnd.ms-photo");
types.put("webarchive","application/x-safari-webarchive");
types.put("webm","video/webm");
types.put("webp","image/webp");
types.put("webtest","application/xml");
types.put("wiq","application/xml");
types.put("wiz","application/msword");
types.put("wks","application/vnd.ms-works");
types.put("WLMP","application/wlmoviemaker");
types.put("wlpginstall","application/x-wlpg-detect");
types.put("wlpginstall3","application/x-wlpg3-detect");
types.put("wm","video/x-ms-wm");
types.put("wma","audio/x-ms-wma");
types.put("wmd","application/x-ms-wmd");
types.put("wmf","application/x-msmetafile");
types.put("wml","text/vnd.wap.wml");
types.put("wmlc","application/vnd.wap.wmlc");
types.put("wmls","text/vnd.wap.wmlscript");
types.put("wmlsc","application/vnd.wap.wmlscriptc");
types.put("wmp","video/x-ms-wmp");
types.put("wmv","video/x-ms-wmv");
types.put("wmx","video/x-ms-wmx");
types.put("wmz","application/x-ms-wmz");
types.put("woff","application/font-woff");
types.put("wpl","application/vnd.ms-wpl");
types.put("wps","application/vnd.ms-works");
types.put("wri","application/x-mswrite");
types.put("wrl","x-world/x-vrml");
types.put("wrz","x-world/x-vrml");
types.put("wsc","text/scriptlet");
types.put("wsdl","text/xml");
types.put("wvx","video/x-ms-wvx");
types.put("x","application/directx");
types.put("xaf","x-world/x-vrml");
types.put("xaml","application/xaml+xml");
types.put("xap","application/x-silverlight-app");
types.put("xbap","application/x-ms-xbap");
types.put("xbm","image/x-xbitmap");
types.put("xdr","text/plain");
types.put("xht","application/xhtml+xml");
types.put("xhtml","application/xhtml+xml");
types.put("xla","application/vnd.ms-excel");
types.put("xlam","application/vnd.ms-excel.addin.macroEnabled.12");
types.put("xlc","application/vnd.ms-excel");
types.put("xld","application/vnd.ms-excel");
types.put("xlk","application/vnd.ms-excel");
types.put("xll","application/vnd.ms-excel");
types.put("xlm","application/vnd.ms-excel");
types.put("xls","application/vnd.ms-excel");
types.put("xlsb","application/vnd.ms-excel.sheet.binary.macroEnabled.12");
types.put("xlsm","application/vnd.ms-excel.sheet.macroEnabled.12");
types.put("xlsx","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
types.put("xlt","application/vnd.ms-excel");
types.put("xltm","application/vnd.ms-excel.template.macroEnabled.12");
types.put("xltx","application/vnd.openxmlformats-officedocument.spreadsheetml.template");
types.put("xlw","application/vnd.ms-excel");
types.put("xml","text/xml");
types.put("xmta","application/xml");
types.put("xof","x-world/x-vrml");
types.put("XOML","text/plain");
types.put("xpm","image/x-xpixmap");
types.put("xps","application/vnd.ms-xpsdocument");
types.put("xrm-ms","text/xml");
types.put("xsc","application/xml");
types.put("xsd","text/xml");
types.put("xsf","text/xml");
types.put("xsl","text/xml");
types.put("xslt","text/xml");
types.put("xsn","application/octet-stream");
types.put("xss","application/xml");
types.put("xspf","application/xspf+xml");
types.put("xtp","application/octet-stream");
types.put("xwd","image/x-xwindowdump");
types.put("z","application/x-compress");
types.put("zip","application/zip");
} else {
Log.d("GETTING_MIME_TYPES", "types have a size greater than 0");
}
return types;
}
/**
* Gets the extension of a file name, like ".png" or ".jpg".
@@ -61,7 +673,7 @@ public class FileUtils {
* @return Extension including the dot("."); "" if there is no extension;
* null if uri was null.
*/
public static String getExtension(String uri) {
private static String getExtension(String uri) {
if (uri == null) {
return null;
}
@@ -79,7 +691,7 @@ public class FileUtils {
/**
* @return Whether the URI is a local one.
*/
public static boolean isLocal(String url) {
private static boolean isLocal(String url) {
if (url != null && !url.startsWith("http://") && !url.startsWith("https://")) {
return true;
}
@@ -90,7 +702,7 @@ public class FileUtils {
* @return True if Uri is a MediaStore Uri.
* @author paulburke
*/
public static boolean isMediaUri(Uri uri) {
private static boolean isMediaUri(Uri uri) {
return "media".equalsIgnoreCase(uri.getAuthority());
}
@@ -99,10 +711,11 @@ public class FileUtils {
*
* @return uri
*/
public static Uri getUri(File file) {
private static Uri getUri(File file) {
if (file != null) {
return Uri.fromFile(file);
}
return null;
}
@@ -134,11 +747,14 @@ public class FileUtils {
* @return The MIME type for the given file.
*/
public static String getMimeType(File file) {
String extension = getExtension(file.getName().toLowerCase());
String extension = getExtension(file.getName());
if(extension.contains(".")) {
extension = extension.substring(1);
}
if (extension.length() > 0) {
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.substring(1));
return getTypes().get(extension);
}
return "application/octet-stream";
@@ -464,13 +1080,10 @@ public class FileUtils {
*
* @author paulburke
*/
public static Comparator<File> sComparator = new Comparator<File>() {
@Override
public int compare(File f1, File f2) {
public static Comparator<File> sComparator = (f1, f2) -> {
// Sort alphabetically by lower case, which is much cleaner
return f1.getName().toLowerCase().compareTo(
f2.getName().toLowerCase());
}
};
/**
@@ -478,13 +1091,10 @@ public class FileUtils {
*
* @author paulburke
*/
public static FileFilter sFileFilter = new FileFilter() {
@Override
public boolean accept(File file) {
public static FileFilter sFileFilter = file -> {
final String fileName = file.getName();
// Return files only (not directories) and skip hidden files
return file.isFile() && !fileName.startsWith(HIDDEN_PREFIX);
}
};
/**
@@ -492,13 +1102,10 @@ public class FileUtils {
*
* @author paulburke
*/
public static FileFilter sDirFilter = new FileFilter() {
@Override
public boolean accept(File file) {
public static FileFilter sDirFilter = file -> {
final String fileName = file.getName();
// Return directories only and skip hidden directories
return file.isDirectory() && !fileName.startsWith(HIDDEN_PREFIX);
}
};
/**
@@ -563,4 +1170,71 @@ public class FileUtils {
return extension;
}
private static String getTmpFilesDir(Context context) {
String dirName = context.getExternalFilesDir(null) + "/" + Constants.TMP_FILE_DIR;
boolean mkdir = new File(dirName).mkdir();
return dirName;
}
public static void clearTmpFilesDir(Context context) {
File dir = new File(getTmpFilesDir(context));
if(!dir.exists()) {
return;
}
for(File f : dir.listFiles()) {
boolean delete = f.delete();
}
}
public static File scaleImageDown(File image, Context context) {
File tmpFile = null;
try {
String tmpFileLocation = FileUtils.getTmpFilesDir(context) + "/" + image.getName();
FileUtils.clearTmpFilesDir(context);
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap bitmapToScale = BitmapFactory.decodeFile(image.getPath(), options);
int originalWidth = options.outWidth;
int originalHeight = options.outHeight;
int newHeight, newWidth;
double aspectRatio = ((double) originalWidth) / ((double) originalHeight);
if(originalHeight > originalWidth) {
aspectRatio = ((double) originalHeight) / ((double) originalWidth);
newWidth = 1080;
newHeight = (int) (newWidth * aspectRatio);
} else {
newHeight = 1080;
newWidth = (int) (newHeight * aspectRatio);
}
Bitmap bitmap = Bitmap.createScaledBitmap(bitmapToScale, newWidth, newHeight, false);
tmpFile = new File(tmpFileLocation);
//noinspection ResultOfMethodCallIgnored
tmpFile.createNewFile();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);
FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
fileOutputStream.write(outputStream.toByteArray());
bitmap.recycle();
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
Utils.copyExifData(image, tmpFile, null);
return tmpFile;
}
}

View File

@@ -1,52 +0,0 @@
package de.beyondsoft.ownchat.utils;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.prefs.BooleanPreference;
import de.beyondsoft.ownchat.di.scopes.ActivityScope;
import de.beyondsoft.ownchat.page.login.LoginPresenter;
import android.app.NotificationManager;
import android.content.Context;
import android.provider.Settings;
import javax.inject.Inject;
import javax.inject.Named;
@ActivityScope
public class LoggedOutUtils {
@Inject
@Named(AppPrefsConstants.APP_KILLED)
BooleanPreference mAppKilledPreference;
@Inject
@Named(AppPrefsConstants.SAVE_PASSWORD)
BooleanPreference mSavePasswordPreference;
@Inject
NotificationManager mNotificationManager;
@Inject
LoginPresenter mLoginPresenter;
@Inject
Context mContext;
@Inject
LoggedOutUtils() {
}
/**
* Check if the user is still logged in.
*/
public boolean checkLoggedOutPrefs() {
if (!mSavePasswordPreference.get() && mAppKilledPreference.get()) {
mNotificationManager.cancelAll();
mLoginPresenter.logout(Settings.Secure.getString(mContext.getContentResolver(), Settings.Secure.ANDROID_ID), true, null);
return true;
}
return false;
}
}

View File

@@ -6,6 +6,26 @@ import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.ImageWriteException;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.IImageMetadata;
import org.apache.sanselan.formats.jpeg.JpegImageMetadata;
import org.apache.sanselan.formats.jpeg.exifRewrite.ExifRewriter;
import org.apache.sanselan.formats.tiff.TiffImageMetadata;
import org.apache.sanselan.formats.tiff.constants.TagInfo;
import org.apache.sanselan.formats.tiff.constants.TiffConstants;
import org.apache.sanselan.formats.tiff.write.TiffOutputDirectory;
import org.apache.sanselan.formats.tiff.write.TiffOutputField;
import org.apache.sanselan.formats.tiff.write.TiffOutputSet;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
/**
* Created by imarneanu on 2/13/17.
*/
@@ -35,4 +55,131 @@ public class Utils {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
public static boolean copyExifData(File sourceFile, File destFile, List<TagInfo> excludedFields) {
String tempFileName = destFile.getAbsolutePath() + ".tmp";
File tempFile = null;
OutputStream tempStream = null;
try {
tempFile = new File (tempFileName);
TiffOutputSet sourceSet = getSanselanOutputSet(sourceFile, TiffConstants.DEFAULT_TIFF_BYTE_ORDER);
TiffOutputSet destSet = getSanselanOutputSet(destFile, sourceSet.byteOrder);
// If the EXIF data endianess of the source and destination files
// differ then fail. This only happens if the source and
// destination images were created on different devices. It's
// technically possible to copy this data by changing the byte
// order of the data, but handling this case is outside the scope
// of this implementation
if (sourceSet.byteOrder != destSet.byteOrder) return false;
destSet.getOrCreateExifDirectory();
// Go through the source directories
List<?> sourceDirectories = sourceSet.getDirectories();
for (int i=0; i<sourceDirectories.size(); i++) {
TiffOutputDirectory sourceDirectory = (TiffOutputDirectory)sourceDirectories.get(i);
TiffOutputDirectory destinationDirectory = getOrCreateExifDirectory(destSet, sourceDirectory);
if (destinationDirectory == null) continue; // failed to create
// Loop the fields
List<?> sourceFields = sourceDirectory.getFields();
for (int j=0; j<sourceFields.size(); j++) {
// Get the source field
TiffOutputField sourceField = (TiffOutputField) sourceFields.get(j);
// Check exclusion list
if (excludedFields != null && excludedFields.contains(sourceField.tagInfo)) {
destinationDirectory.removeField(sourceField.tagInfo);
continue;
}
// Remove any existing field
destinationDirectory.removeField(sourceField.tagInfo);
// Add field
destinationDirectory.add(sourceField);
}
}
// Save data to destination
tempStream = new BufferedOutputStream(new FileOutputStream(tempFile));
new ExifRewriter().updateExifMetadataLossless(destFile, tempStream, destSet);
tempStream.close();
// Replace file
if (destFile.delete()) {
tempFile.renameTo(destFile);
}
return true;
}
catch (ImageReadException | ImageWriteException | IOException exception) {
exception.printStackTrace();
} finally {
if (tempStream != null) {
try {
tempStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
if (tempFile != null) {
if (tempFile.exists()) {
tempFile.delete();
}
}
}
return false;
}
private static TiffOutputSet getSanselanOutputSet(File jpegImageFile, int defaultByteOrder) throws IOException, ImageReadException, ImageWriteException {
TiffImageMetadata exif = null;
TiffOutputSet outputSet = null;
IImageMetadata metadata = Sanselan.getMetadata(jpegImageFile);
JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
if(jpegMetadata != null) {
exif = jpegMetadata.getExif();
if (exif != null) {
outputSet = exif.getOutputSet();
}
}
// If JPEG file contains no EXIF metadata, create an empty set
// of EXIF metadata. Otherwise, use existing EXIF metadata to
// keep all other existing tags
if (outputSet == null) {
outputSet = new TiffOutputSet(exif==null?defaultByteOrder:exif.contents.header.byteOrder);
}
return outputSet;
}
private static TiffOutputDirectory getOrCreateExifDirectory(TiffOutputSet outputSet, TiffOutputDirectory outputDirectory) {
TiffOutputDirectory result = outputSet.findDirectory(outputDirectory.type);
if (result != null) {
return result;
}
result = new TiffOutputDirectory(outputDirectory.type);
try {
outputSet.addDirectory(result);
}
catch (ImageWriteException e) {
return null;
}
return result;
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:duration="300" android:fromXDelta="100.0%p" android:toXDelta="0.0" />
</set>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:duration="300" android:fromXDelta="0.0" android:toXDelta="-100.0%p" />
</set>

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 KiB

View File

@@ -1,18 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:emojicon="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/file_relative_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="de.beyondsoft.ownchat.page.fileconfirmation.FileConfirmationActivity">
<WebView
android:id="@+id/media_file_webview"
<include layout="@layout/chat_toolbar" />
<ImageView
android:id="@+id/media_file"
android:layout_width="match_parent"
android:layout_height="match_parent">
</WebView>
</ImageView>
<LinearLayout
android:layout_width="match_parent"

View File

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

View File

@@ -1,4 +1,5 @@
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.v4.widget.DrawerLayout
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/drawer_layout"

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/white"
/>
<TextView
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:text="@string/no_files_found"
android:textSize="25sp"
android:textStyle="bold"
android:visibility="gone"
/>
</RelativeLayout>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sharing_contacts_coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<include layout="@layout/chat_toolbar" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize">
<android.support.v7.widget.RecyclerView
android:id="@+id/sharing_contacts_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorWhite" />
<de.beyondsoft.ownchat.utils.ui.EmptyLayout
android:id="@+id/sharing_contacts_empty_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:gravity="center_vertical"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<ImageView
android:id="@+id/attachFromGalleryBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".50"
android:adjustViewBounds="false"
android:contentDescription="@null"
android:cropToPadding="false"
android:layout_margin="10dp"
android:src="@mipmap/ic_file_dialog_gallery" />
<ImageView
android:id="@+id/attachDocumentBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".50"
android:contentDescription="@null"
android:layout_margin="10dp"
android:src="@mipmap/ic_file_dialog_document" />
</LinearLayout>

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contacts_coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"

Some files were not shown because too many files have changed in this diff Show More