Merge branch 'master' of ssh://float.beyondsoft.de/git/beyondSoft/Chat
@@ -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'
|
||||
@@ -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>
|
||||
@@ -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}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB |
@@ -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";
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package de.beyondsoft.ownchat.filepicker.adapters;
|
||||
|
||||
/**
|
||||
* Created by Lyndon on 26-Oct-2017.
|
||||
*/
|
||||
|
||||
public interface FileAdapterListener {
|
||||
void onItemSelected();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package de.beyondsoft.ownchat.filepicker.fragments;
|
||||
|
||||
/**
|
||||
* Created by Lyndon on 26-Oct-2017.
|
||||
*/
|
||||
|
||||
public interface ImagePickerFragmentListener {
|
||||
void onItemSelected();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
if (mSystemUtils.isNetworkUnavailable()) {
|
||||
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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -47,9 +47,7 @@ public class AppStoppedService extends Service {
|
||||
@Override
|
||||
public void onTaskRemoved(Intent rootIntent) {
|
||||
mAppKilledPreference.set(true);
|
||||
if (!mSavedPasswordPref.get()) {
|
||||
mNotificationManager.cancelAll();
|
||||
}
|
||||
|
||||
stopSelf();
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -18,7 +38,7 @@ public class Utils {
|
||||
public static void clearFullBackStack(AppCompatActivity appCompatActivity) {
|
||||
FragmentManager fragmentManager = appCompatActivity.getSupportFragmentManager();
|
||||
|
||||
if (fragmentManager.getBackStackEntryCount() > 0) {
|
||||
if(fragmentManager.getBackStackEntryCount() > 0) {
|
||||
// clear the fragment back stack
|
||||
FragmentManager.BackStackEntry first = fragmentManager.getBackStackEntryAt(0);
|
||||
fragmentManager.popBackStackImmediate(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 206 KiB |
|
After Width: | Height: | Size: 841 KiB |
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||