diff --git a/.gitignore b/.gitignore index 7e54476492..e81a9ab83e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ #builds /build *.apk +*.hprof .gradle /local.properties diff --git a/build.gradle b/build.gradle index d3ed022bb3..f1b6eed269 100755 --- a/build.gradle +++ b/build.gradle @@ -54,7 +54,6 @@ allprojects { maven { url "https://github.com/vector-im/jitsi_libre_maven/raw/master/releases" } - google() maven { url "https://maven.google.com" } diff --git a/gradle.properties b/gradle.properties index 392837c7de..e6bd5c7c80 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit diff --git a/sentry.properties b/sentry.properties new file mode 100644 index 0000000000..7734b91893 --- /dev/null +++ b/sentry.properties @@ -0,0 +1,7 @@ ++defaults.url=https://sentry.ir-cloud.ir/ + ++defaults.project=messenger + ++defaults.org=batna + ++auth.token=a9b6f48c8b9d4c6399f01536eaf3cf964ce15a119e0544c0b3a33409ca131d30 \ No newline at end of file diff --git a/vector/build.gradle b/vector/build.gradle index 0f56f7c9c4..ca2f6fe495 100755 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -31,6 +31,7 @@ ext.abiVersionCodes = ["armeabi-v7a": 1, "arm64-v8a": 2, "x86": 3, "x86_64": 4]. android { compileSdkVersion 28 + buildToolsVersion '28.0.3' packagingOptions { exclude 'META-INF/LICENSE' @@ -44,11 +45,11 @@ android { defaultConfig { applicationId "im.vector" - minSdkVersion 16 + minSdkVersion 21 targetSdkVersion 28 // use the version code - versionCode rootProject.ext.versionCodeProp - versionName rootProject.ext.versionNameProp + versionCode 9907051 + versionName "Mehr99-A" // Keep abiFilter for the universalApk ndk { @@ -56,6 +57,7 @@ android { } multiDexEnabled true + vectorDrawables.useSupportLibrary = true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -127,6 +129,7 @@ android { // use the version name versionCode rootProject.ext.versionCodeProp versionName rootProject.ext.versionNameProp + buildConfigField "boolean", "IS_SABA", "false" buildConfigField "boolean", "ALLOW_FCM_USE", "true" buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"G\"" buildConfigField "String", "FLAVOR_DESCRIPTION", "\"GooglePlay\"" @@ -137,14 +140,27 @@ android { // use the version name versionCode rootProject.ext.versionCodeProp versionName rootProject.ext.versionNameProp + buildConfigField "boolean", "IS_SABA", "false" buildConfigField "boolean", "ALLOW_FCM_USE", "false" buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"F\"" buildConfigField "String", "FLAVOR_DESCRIPTION", "\"FDroid\"" } + + saba { + applicationId "ir.batna.messaging" + versionCode 9905261 + versionName "Mordad99-C" + buildConfigField "boolean", "IS_SABA", "true" + buildConfigField "boolean", "ALLOW_HOME_SERVER_CHANGE", "true" + buildConfigField "boolean", "ALLOW_FCM_USE", "false" + buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"S\"" + buildConfigField "String", "FLAVOR_DESCRIPTION", "\"Saba\"" + } } lintOptions { lintConfig file("lint.xml") + abortOnError false } testOptions { @@ -176,6 +192,8 @@ static def gitBranchName() { } dependencies { + compile 'uk.co.chrisjenx:calligraphy:2.3.0' + // Kotlin implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" @@ -270,6 +288,9 @@ dependencies { // appfdroid flavor only + implementation 'io.sentry:sentry-android:2.0.2' + implementation 'org.slf4j:slf4j-nop:1.7.25' + // Test testImplementation 'junit:junit:4.12' // Test testImplementation 'androidx.test:runner:1.2.0' @@ -296,7 +317,8 @@ configurations.all { } } -if (!getGradle().getStartParameter().getTaskRequests().toString().contains("Appfdroid") +if (!getGradle().getStartParameter().getTaskRequests().toString().contains("fdroid") + && !getGradle().getStartParameter().getTaskRequests().toString().contains("Saba") && !getGradle().getStartParameter().getTaskRequests().toString().contains("assembleAndroidTest")) { apply plugin: 'com.google.gms.google-services' } diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 0724bb8886..5921e28d37 100755 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -549,7 +549,7 @@ - + \ No newline at end of file diff --git a/vector/src/main/java/im/vector/VectorApp.java b/vector/src/main/java/im/vector/VectorApp.java index 5e798fb0df..1cb6b6100d 100755 --- a/vector/src/main/java/im/vector/VectorApp.java +++ b/vector/src/main/java/im/vector/VectorApp.java @@ -71,6 +71,7 @@ import im.vector.notifications.NotificationDrawerManager; import im.vector.notifications.NotificationUtils; import im.vector.push.PushManager; +import im.vector.services.EventStreamServiceX; import im.vector.settings.FontScale; import im.vector.settings.VectorLocale; import im.vector.tools.VectorUncaughtExceptionHandler; @@ -193,7 +194,6 @@ public void onReceive(Context context, Intent intent) { @Override public void onCreate() { - Log.d(LOG_TAG, "onCreate"); super.onCreate(); mLifeCycleListener = new VectorLifeCycleObserver(); @@ -359,6 +359,20 @@ public void onActivityDestroyed(Activity activity) { PreferencesManager.fixMigrationIssues(this); initApplicationLocale(); visitSessionVariables(); + if (BuildConfig.IS_SABA) { + // Sentry.captureMessage("Startup"); + try { + Intent serviceIntent = new Intent(this, EventStreamServiceX.class); + serviceIntent.setAction(EventStreamServiceX.ACTION_SIMULATED_PERMANENT_LISTENING); + if (Build.VERSION.SDK_INT >= 26) { + startForegroundService(serviceIntent); + } else { + startService(serviceIntent); + } + } catch (Exception e) { + Log.v("Error in VectorApp:", e.getMessage()); + } + } } @Override diff --git a/vector/src/main/java/im/vector/activity/AccountCreationCaptchaActivity.java b/vector/src/main/java/im/vector/activity/AccountCreationCaptchaActivity.java index 479011a8a5..88dd7795a3 100755 --- a/vector/src/main/java/im/vector/activity/AccountCreationCaptchaActivity.java +++ b/vector/src/main/java/im/vector/activity/AccountCreationCaptchaActivity.java @@ -18,6 +18,7 @@ package im.vector.activity; import android.annotation.SuppressLint; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.http.SslError; @@ -46,6 +47,7 @@ import im.vector.R; import im.vector.ui.themes.ThemeUtils; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * AccountCreationCaptchaActivity displays a webview to check captchas. @@ -84,6 +86,11 @@ public class AccountCreationCaptchaActivity extends VectorAppCompatActivity { " " + " "; + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_vector_registration_captcha; diff --git a/vector/src/main/java/im/vector/activity/Calligraphy.java b/vector/src/main/java/im/vector/activity/Calligraphy.java new file mode 100644 index 0000000000..f568d79ed4 --- /dev/null +++ b/vector/src/main/java/im/vector/activity/Calligraphy.java @@ -0,0 +1,20 @@ +package im.vector.activity; + +import android.app.Application; + +import im.vector.R; +import uk.co.chrisjenx.calligraphy.CalligraphyConfig; + +public class Calligraphy extends Application { + @Override + public void onCreate() { + super.onCreate(); + CalligraphyConfig.initDefault(new CalligraphyConfig.Builder() + .setDefaultFontPath("font/shabnam.ttf") + .setFontAttrId(R.attr.fontPath) + .build() + ); + + } + +} diff --git a/vector/src/main/java/im/vector/activity/CommonActivityUtils.java b/vector/src/main/java/im/vector/activity/CommonActivityUtils.java index 91f899042f..cde4fd6f68 100755 --- a/vector/src/main/java/im/vector/activity/CommonActivityUtils.java +++ b/vector/src/main/java/im/vector/activity/CommonActivityUtils.java @@ -920,7 +920,7 @@ public void run() { * @param outputFilename optional the output filename * @param callback the asynchronous callback */ - private static void saveFileInto(final File sourceFile, final String dstDirPath, final String outputFilename, final ApiCallback callback) { + private static void saveFileInto(final File sourceFile, final String dstDirPath, final String outputFilename, final ApiCallback callback, Context context) { // sanity check if ((null == sourceFile) || (null == dstDirPath)) { new Handler(Looper.getMainLooper()).post(new Runnable() { @@ -958,7 +958,11 @@ protected Pair doInBackground(Void... params) { } File dstDir = Environment.getExternalStoragePublicDirectory(dstDirPath); - if (dstDir != null) { + assert outputFilename != null; + if (outputFilename.contains(".3gp")|| outputFilename.contains(".mp3") ||outputFilename.contains(".aac")) { + dstDir = new File(context.getApplicationContext().getCacheDir(), "voice"); + } + if (dstDir != null) { dstDir.mkdirs(); } @@ -1069,7 +1073,7 @@ public void onSuccess(String fullFilePath) { try { File file = new File(fullFilePath); - downloadManager.addCompletedDownload(file.getName(), file.getName(), true, mimeType, file.getAbsolutePath(), file.length(), true); + downloadManager.addCompletedDownload(file.getName(), file.getName(), true, mimeType, file.getAbsolutePath(), file.length(), false); } catch (Exception e) { Log.e(LOG_TAG, "## saveMediaIntoDownloads(): Exception Msg=" + e.getMessage(), e); } @@ -1103,7 +1107,7 @@ public void onUnexpectedError(Exception e) { callback.onUnexpectedError(e); } } - }); + },context); } //============================================================================================================== diff --git a/vector/src/main/java/im/vector/activity/CountryPickerActivity.java b/vector/src/main/java/im/vector/activity/CountryPickerActivity.java index cc684e5a33..61a62f3520 100644 --- a/vector/src/main/java/im/vector/activity/CountryPickerActivity.java +++ b/vector/src/main/java/im/vector/activity/CountryPickerActivity.java @@ -38,6 +38,7 @@ import im.vector.ui.themes.ThemeUtils; import im.vector.util.CountryPhoneData; import im.vector.util.PhoneNumberUtils; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; public class CountryPickerActivity extends VectorAppCompatActivity implements CountryAdapter.OnSelectCountryListener, SearchView.OnQueryTextListener { @@ -72,6 +73,12 @@ public static Intent getIntent(final Context context, final boolean withIndicato */ @NotNull + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public ActivityOtherThemes getOtherThemes() { return ActivityOtherThemes.Picker.INSTANCE; diff --git a/vector/src/main/java/im/vector/activity/JitsiCallActivity.java b/vector/src/main/java/im/vector/activity/JitsiCallActivity.java index 9169992c6e..c36e9c2da1 100755 --- a/vector/src/main/java/im/vector/activity/JitsiCallActivity.java +++ b/vector/src/main/java/im/vector/activity/JitsiCallActivity.java @@ -116,7 +116,6 @@ public void initUiAndData() { setWaitingView(findViewById(R.id.jitsi_progress_layout)); mWidget = (Widget) getIntent().getSerializableExtra(EXTRA_WIDGET_ID); - mJitsi = new JitsiWidgetProperties(mWidget.getUrl()); mIsVideoCall = getIntent().getBooleanExtra(EXTRA_ENABLE_VIDEO, true); try { diff --git a/vector/src/main/java/im/vector/activity/LanguagePickerActivity.java b/vector/src/main/java/im/vector/activity/LanguagePickerActivity.java index ab6ecd4b76..26b4bdcad1 100644 --- a/vector/src/main/java/im/vector/activity/LanguagePickerActivity.java +++ b/vector/src/main/java/im/vector/activity/LanguagePickerActivity.java @@ -40,6 +40,7 @@ import im.vector.settings.VectorLocale; import im.vector.ui.themes.ActivityOtherThemes; import im.vector.ui.themes.ThemeUtils; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; public class LanguagePickerActivity extends VectorAppCompatActivity implements LanguagesAdapter.OnSelectLocaleListener, SearchView.OnQueryTextListener { @@ -64,6 +65,12 @@ public static Intent getIntent(final Context context) { */ @NotNull + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public ActivityOtherThemes getOtherThemes() { return ActivityOtherThemes.Picker.INSTANCE; diff --git a/vector/src/main/java/im/vector/activity/LockScreenActivity.java b/vector/src/main/java/im/vector/activity/LockScreenActivity.java index ed86b9b1fd..a988b6d7b2 100755 --- a/vector/src/main/java/im/vector/activity/LockScreenActivity.java +++ b/vector/src/main/java/im/vector/activity/LockScreenActivity.java @@ -18,6 +18,7 @@ package im.vector.activity; +import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.text.TextUtils; @@ -48,6 +49,7 @@ import im.vector.notifications.NotificationUtils; import im.vector.ui.themes.ActivityOtherThemes; import im.vector.util.ViewUtilKt; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * LockScreenActivity is displayed within the notification to send a message without opening the application. @@ -74,6 +76,12 @@ public static boolean isDisplayingALockScreenActivity() { private EditText mEditText; @NotNull + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public ActivityOtherThemes getOtherThemes() { return ActivityOtherThemes.Lock.INSTANCE; diff --git a/vector/src/main/java/im/vector/activity/LoggingOutActivity.java b/vector/src/main/java/im/vector/activity/LoggingOutActivity.java index df0d9e9f4f..a48b2a34df 100755 --- a/vector/src/main/java/im/vector/activity/LoggingOutActivity.java +++ b/vector/src/main/java/im/vector/activity/LoggingOutActivity.java @@ -18,12 +18,14 @@ package im.vector.activity; +import android.content.Context; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.Drawable; import android.widget.ImageView; import butterknife.BindView; import im.vector.R; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * LoggingOutActivity displays an animation while a session log out is in progress. @@ -33,6 +35,11 @@ public class LoggingOutActivity extends MXCActionBarActivity { @BindView(R.id.animated_logo_image_view) ImageView animatedLogo; + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.vector_activity_splash; diff --git a/vector/src/main/java/im/vector/activity/LoginActivity.java b/vector/src/main/java/im/vector/activity/LoginActivity.java index 8c78d0acb1..6c934bcef0 100644 --- a/vector/src/main/java/im/vector/activity/LoginActivity.java +++ b/vector/src/main/java/im/vector/activity/LoginActivity.java @@ -105,6 +105,7 @@ import im.vector.ui.badge.BadgeProxy; import im.vector.util.PhoneNumberUtils; import im.vector.util.ViewUtilKt; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * Displays the login screen. @@ -408,6 +409,11 @@ public void onReceive(Context context, Intent intent) { private Dialog mCurrentDialog; + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override protected void onDestroy() { if (mLoginPhoneNumberHandler != null) { @@ -2344,9 +2350,18 @@ private void refreshDisplay(boolean checkFlow) { mForgotValidateEmailButton.setVisibility(View.GONE); mSubmitThreePidButton.setVisibility(View.GONE); mSkipThreePidButton.setVisibility(View.GONE); - - mHomeServerOptionLayout.setVisibility(View.VISIBLE); - + /** + * Batna ==>Allow choose home server + */ + if (BuildConfig.IS_SABA) { + if (BuildConfig.ALLOW_HOME_SERVER_CHANGE) { + mHomeServerOptionLayout.setVisibility(View.VISIBLE); + } else { + mHomeServerOptionLayout.setVisibility(View.GONE); + } + }else { + mHomeServerOptionLayout.setVisibility(View.VISIBLE); + } // Then show them depending on mode switch (mMode) { case MODE_LOGIN: diff --git a/vector/src/main/java/im/vector/activity/MXCActionBarActivity.java b/vector/src/main/java/im/vector/activity/MXCActionBarActivity.java index bf2a89db03..c5fa4adb1b 100755 --- a/vector/src/main/java/im/vector/activity/MXCActionBarActivity.java +++ b/vector/src/main/java/im/vector/activity/MXCActionBarActivity.java @@ -38,6 +38,7 @@ import im.vector.MyPresenceManager; import im.vector.R; import im.vector.VectorApp; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * extends ActionBarActivity to manage the rageshake @@ -49,6 +50,11 @@ public abstract class MXCActionBarActivity extends VectorAppCompatActivity { protected MXSession mSession = null; Room mRoom = null; + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public void onLowMemory() { super.onLowMemory(); diff --git a/vector/src/main/java/im/vector/activity/MediaPreviewerActivity.java b/vector/src/main/java/im/vector/activity/MediaPreviewerActivity.java index b3b9310fbc..759890f3c6 100644 --- a/vector/src/main/java/im/vector/activity/MediaPreviewerActivity.java +++ b/vector/src/main/java/im/vector/activity/MediaPreviewerActivity.java @@ -2,6 +2,7 @@ import android.annotation.SuppressLint; import android.app.Activity; +import android.content.Context; import android.net.Uri; import android.view.MotionEvent; import android.view.View; @@ -25,6 +26,7 @@ import butterknife.OnClick; import im.vector.R; import im.vector.adapters.MediaPreviewAdapter; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * Previews media selected to be send. @@ -53,6 +55,11 @@ public class MediaPreviewerActivity extends MXCActionBarActivity implements Medi @BindView(R.id.media_previewer_video_play) ImageView mPlayCircleView; + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { @@ -71,6 +78,8 @@ public void initUiAndData() { Log.d(LOG_TAG, "onCreate : Going to splash screen"); return; } + setResult(Activity.RESULT_OK, getIntent()); + finish(); mPreviewerVideoView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { diff --git a/vector/src/main/java/im/vector/activity/NotificationPrivacyActivity.java b/vector/src/main/java/im/vector/activity/NotificationPrivacyActivity.java index fdddcbdb8f..6011dd57ee 100644 --- a/vector/src/main/java/im/vector/activity/NotificationPrivacyActivity.java +++ b/vector/src/main/java/im/vector/activity/NotificationPrivacyActivity.java @@ -28,6 +28,7 @@ import im.vector.Matrix; import im.vector.R; import im.vector.push.PushManager; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /* * This activity allows the user to choose a notifications privacy policy. @@ -53,6 +54,11 @@ public class NotificationPrivacyActivity extends VectorAppCompatActivity { * LifeCycle * ========================================================================================== */ + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_notification_privacy; diff --git a/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java b/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java index b01534ebee..f0941c39b3 100644 --- a/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java +++ b/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java @@ -44,6 +44,7 @@ import im.vector.Matrix; import im.vector.R; import im.vector.util.PhoneNumberUtils; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; public class PhoneNumberAdditionActivity extends VectorAppCompatActivity implements TextView.OnEditorActionListener, TextWatcher, View.OnClickListener { @@ -89,6 +90,11 @@ public static Intent getIntent(final Context context, final String sessionId) { * ********************************************************************************************* */ + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_phone_number_addition; diff --git a/vector/src/main/java/im/vector/activity/RoomDirectoryPickerActivity.java b/vector/src/main/java/im/vector/activity/RoomDirectoryPickerActivity.java index c661ef37e1..afb43903ad 100644 --- a/vector/src/main/java/im/vector/activity/RoomDirectoryPickerActivity.java +++ b/vector/src/main/java/im/vector/activity/RoomDirectoryPickerActivity.java @@ -47,6 +47,7 @@ import im.vector.R; import im.vector.adapters.RoomDirectoryAdapter; import im.vector.util.RoomDirectoryData; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; public class RoomDirectoryPickerActivity extends VectorAppCompatActivity implements RoomDirectoryAdapter.OnSelectRoomDirectoryListener { // LOG TAG @@ -76,6 +77,11 @@ public static Intent getIntent(final Context context, final String sessionId) { * ********************************************************************************************* */ + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_room_directory_picker; diff --git a/vector/src/main/java/im/vector/activity/SplashActivity.java b/vector/src/main/java/im/vector/activity/SplashActivity.java index d9f21b2a5a..e87e855065 100755 --- a/vector/src/main/java/im/vector/activity/SplashActivity.java +++ b/vector/src/main/java/im/vector/activity/SplashActivity.java @@ -17,6 +17,7 @@ */ package im.vector.activity; +import android.content.Context; import android.content.Intent; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.Drawable; @@ -49,6 +50,7 @@ import im.vector.receiver.VectorUniversalLinkReceiver; import im.vector.services.EventStreamServiceX; import im.vector.util.PreferencesManager; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * SplashActivity displays a splash while loading and initializing the client. @@ -135,6 +137,11 @@ private void onFinish() { } } + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.vector_activity_splash; diff --git a/vector/src/main/java/im/vector/activity/VectorAppCompatActivity.kt b/vector/src/main/java/im/vector/activity/VectorAppCompatActivity.kt index c6fcdae99f..91c278c864 100755 --- a/vector/src/main/java/im/vector/activity/VectorAppCompatActivity.kt +++ b/vector/src/main/java/im/vector/activity/VectorAppCompatActivity.kt @@ -86,7 +86,7 @@ abstract class VectorAppCompatActivity : BaseMvRxActivity() { super.attachBaseContext(VectorApp.getLocalisedContext(base)) } - final override fun onCreate(savedInstanceState: Bundle?) { + open override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ThemeUtils.setActivityTheme(this, getOtherThemes()) diff --git a/vector/src/main/java/im/vector/activity/VectorCallViewActivity.java b/vector/src/main/java/im/vector/activity/VectorCallViewActivity.java index 1a60860571..0a7b7a1cda 100755 --- a/vector/src/main/java/im/vector/activity/VectorCallViewActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorCallViewActivity.java @@ -38,6 +38,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.Window; import android.view.WindowManager; import android.view.animation.AccelerateInterpolator; import android.widget.ImageView; @@ -64,6 +65,7 @@ import java.util.Timer; import java.util.TimerTask; +import im.vector.BuildConfig; import im.vector.Matrix; import im.vector.R; import im.vector.VectorApp; @@ -390,6 +392,16 @@ public void initUiAndData() { View mainContainerLayoutView = findViewById(R.id.call_layout); + /** + * BATNA ==> Open call view Activity when phone lock + */ + if (BuildConfig.IS_SABA) { + Window winManager = getWindow(); + winManager.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); + winManager.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); + winManager.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); + } + // when video is in full screen, touching the screen restore the edges (fade in) mainContainerLayoutView.setOnClickListener(new View.OnClickListener() { @Override diff --git a/vector/src/main/java/im/vector/activity/VectorFakeRoomPreviewActivity.java b/vector/src/main/java/im/vector/activity/VectorFakeRoomPreviewActivity.java index 723ed7bbe3..5c8e91fca2 100644 --- a/vector/src/main/java/im/vector/activity/VectorFakeRoomPreviewActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorFakeRoomPreviewActivity.java @@ -18,6 +18,7 @@ package im.vector.activity; import android.annotation.SuppressLint; +import android.content.Context; import android.content.Intent; import org.matrix.androidsdk.MXSession; @@ -26,6 +27,7 @@ import im.vector.Matrix; import im.vector.R; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * Dummy activity used to trigger the room activity in preview mode, @@ -41,6 +43,11 @@ public class VectorFakeRoomPreviewActivity extends VectorAppCompatActivity { private static final String LOG_TAG = VectorFakeRoomPreviewActivity.class.getSimpleName(); + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_empty; diff --git a/vector/src/main/java/im/vector/activity/VectorGroupDetailsActivity.java b/vector/src/main/java/im/vector/activity/VectorGroupDetailsActivity.java index bca1948a8f..9c6fe3a188 100755 --- a/vector/src/main/java/im/vector/activity/VectorGroupDetailsActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorGroupDetailsActivity.java @@ -49,6 +49,7 @@ import im.vector.ui.themes.ActivityOtherThemes; import im.vector.ui.themes.ThemeUtils; import im.vector.view.VectorViewPager; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * @@ -137,6 +138,11 @@ public void onGroupInvitedUsersListUpdate(String groupId) { } }; + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_vector_group_details; diff --git a/vector/src/main/java/im/vector/activity/VectorHomeActivity.java b/vector/src/main/java/im/vector/activity/VectorHomeActivity.java index 84cf1f1d7d..15f0979143 100644 --- a/vector/src/main/java/im/vector/activity/VectorHomeActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorHomeActivity.java @@ -34,7 +34,9 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.provider.Settings; import android.text.Editable; +import android.text.Html; import android.text.TextUtils; import android.text.TextWatcher; import android.util.TypedValue; @@ -53,6 +55,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.SearchView; @@ -62,6 +65,7 @@ import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModelProviders; import androidx.preference.PreferenceManager; @@ -85,6 +89,7 @@ import org.matrix.androidsdk.core.model.MatrixError; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; +import org.matrix.androidsdk.crypto.keysbackup.KeysBackupStateManager; import org.matrix.androidsdk.data.MyUser; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomPreviewData; @@ -95,6 +100,9 @@ import org.matrix.androidsdk.listeners.MXEventListener; import org.matrix.androidsdk.rest.model.Event; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; @@ -112,6 +120,7 @@ import im.vector.BuildConfig; import im.vector.Matrix; import im.vector.MyPresenceManager; +import im.vector.callback.OnRecoveryKeyListener; import im.vector.PublicRoomsManager; import im.vector.R; import im.vector.VectorApp; @@ -123,12 +132,16 @@ import im.vector.fragments.HomeFragment; import im.vector.fragments.PeopleFragment; import im.vector.fragments.RoomsFragment; +import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel; import im.vector.fragments.signout.SignOutBottomSheetDialogFragment; import im.vector.fragments.signout.SignOutViewModel; +import im.vector.keymanager.KeyManager; import im.vector.push.PushManager; import im.vector.receiver.VectorUniversalLinkReceiver; import im.vector.services.EventStreamServiceX; +import im.vector.sharedpreferences.BatnaSharedPreferences; import im.vector.tools.VectorUncaughtExceptionHandler; +import im.vector.ui.arch.LiveEvent; import im.vector.ui.themes.ActivityOtherThemes; import im.vector.ui.themes.ThemeUtils; import im.vector.util.BugReporter; @@ -141,6 +154,7 @@ import im.vector.view.KeysBackupBanner; import im.vector.view.UnreadCounterBadgeView; import im.vector.view.VectorPendingCallView; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * Displays the main screen of the app, with rooms the user has joined and the ability to create @@ -213,9 +227,6 @@ public class VectorHomeActivity extends VectorAppCompatActivity implements Searc @BindView(R.id.fab_expand_menu_button) AddFloatingActionButton mFabMain; - @BindView(R.id.button_start_chat) - FloatingActionButton mFabStartChat; - @BindView(R.id.button_create_room) FloatingActionButton mFabCreateRoom; @@ -254,9 +265,6 @@ public class VectorHomeActivity extends VectorAppCompatActivity implements Searc @BindView(R.id.home_search_view) SearchView mSearchView; - @BindView(R.id.floating_action_menu_touch_guard) - View touchGuard; - // a shared files intent is waiting the store init private Intent mSharedFilesIntent = null; @@ -294,6 +302,11 @@ public static VectorHomeActivity getInstance() { * ********************************************************************************************* */ + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @NotNull @Override public ActivityOtherThemes getOtherThemes() { @@ -305,6 +318,7 @@ public int getLayoutRes() { return R.layout.activity_home; } + @RequiresApi(api = Build.VERSION_CODES.N) @Override public void initUiAndData() { mFragmentManager = getSupportFragmentManager(); @@ -358,6 +372,12 @@ public void initUiAndData() { } else { switch (keysBackupState) { case Disabled: + if (BuildConfig.IS_SABA) { + KeysBackupStateManager.KeysBackupState keyBackupState = mSession.getCrypto().getKeysBackup().getState(); + if (keyBackupState == KeysBackupStateManager.KeysBackupState.Disabled) { + KeyManager.getKeyBackup(this, mSession); + } + } mKeysBackupBanner.render(new KeysBackupBanner.State.Setup(model.getNumberOfKeysToBackup()), false); break; case NotTrusted: @@ -542,21 +562,39 @@ public void run() { } } - final View selectedMenu; - if (isFirstCreation()) { - selectedMenu = mBottomNavigationView.findViewById(R.id.bottom_action_home); - } else { - selectedMenu = mBottomNavigationView.findViewById(getSavedInstanceState().getInt(CURRENT_MENU_ID, R.id.bottom_action_home)); - } - if (selectedMenu != null) { - selectedMenu.performClick(); - } + // Open default tab + tabsGotoConversations(); // initialize the public rooms list PublicRoomsManager.getInstance().setSession(mSession); PublicRoomsManager.getInstance().refreshPublicRoomsCount(null); initViews(); + + /** + *BATNA ==> Added 'ACTION_MANAGE_OVERLAY_PERMISSION' to app + */ + if (BuildConfig.IS_SABA) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (!Settings.canDrawOverlays(this)) { + new AlertDialog.Builder(VectorHomeActivity.this) + .setMessage(Html.fromHtml(getString(R.string.saba_receiving_a_permission_desc), Html.FROM_HTML_MODE_COMPACT)) + .setPositiveButton(R.string.saba_receiving_a_permission, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (!Settings.canDrawOverlays(VectorHomeActivity.this)) { + Intent intentTest = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); + startActivityForResult(intentTest, 0); + } + } + }) + .setNegativeButton("", null) + .setCancelable(false) + .show(); + } + } + } + } /** @@ -615,25 +653,27 @@ public void run() { VectorUncaughtExceptionHandler.INSTANCE.clearAppCrashStatus(this); // crash reported by a rage shake - try { - new AlertDialog.Builder(this) - .setMessage(R.string.send_bug_report_app_crashed) - .setCancelable(false) - .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - BugReporter.sendBugReport(); - } - }) - .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - BugReporter.deleteCrashFile(VectorHomeActivity.this); - } - }) - .show(); - } catch (Exception e) { - Log.e(LOG_TAG, "## onResume() : appCrashedAlert failed " + e.getMessage(), e); + if (!BuildConfig.IS_SABA) { + try { + new AlertDialog.Builder(this) + .setMessage(R.string.send_bug_report_app_crashed) + .setCancelable(false) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + BugReporter.sendBugReport(); + } + }) + .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + BugReporter.deleteCrashFile(VectorHomeActivity.this); + } + }) + .show(); + } catch (Exception e) { + Log.e(LOG_TAG, "## onResume() : appCrashedAlert failed " + e.getMessage(), e); + } } } @@ -749,7 +789,7 @@ public void onClick(DialogInterface dialog, int which) { setAnalyticsAuthorization(false); } }) - .show(); + .show().dismiss(); } private void setAnalyticsAuthorization(boolean useAnalytics) { @@ -759,7 +799,7 @@ private void setAnalyticsAuthorization(boolean useAnalytics) { @Override public int getMenuRes() { - return R.menu.vector_home; + return -1; } @Override @@ -775,15 +815,8 @@ public boolean onPrepareOptionsMenu(Menu menu) { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - // search in rooms content case R.id.ic_action_global_search: - final Intent searchIntent = new Intent(this, VectorUnifiedSearchActivity.class); - - if (R.id.bottom_action_people == mCurrentMenuId) { - searchIntent.putExtra(VectorUnifiedSearchActivity.EXTRA_TAB_INDEX, VectorUnifiedSearchActivity.SEARCH_PEOPLE_TAB_POSITION); - } - - startActivity(searchIntent); + gotoGlobalSearch(); return true; case R.id.ic_action_historical: startActivity(new Intent(this, HistoricalRoomsActivity.class)); @@ -1069,8 +1102,6 @@ public void updateTabStyle(final int primaryColor, mFabJoinRoom.setColorPressed(fabPressedColor); mFabCreateRoom.setColorNormal(fabColor); mFabCreateRoom.setColorPressed(fabPressedColor); - mFabStartChat.setColorNormal(fabColor); - mFabStartChat.setColorPressed(fabPressedColor); } // Set color of toolbar search view @@ -1131,11 +1162,6 @@ public void run() { } - mFabStartChat.setIconDrawable(ThemeUtils.INSTANCE.tintDrawableWithColor( - ContextCompat.getDrawable(this, R.drawable.ic_person_black_24dp), - ContextCompat.getColor(this, android.R.color.white) - )); - mFabCreateRoom.setIconDrawable(ThemeUtils.INSTANCE.tintDrawableWithColor( ContextCompat.getDrawable(this, R.drawable.ic_add_white), ContextCompat.getColor(this, android.R.color.white) @@ -1145,24 +1171,6 @@ public void run() { ContextCompat.getDrawable(this, R.drawable.riot_tab_rooms), ContextCompat.getColor(this, android.R.color.white) )); - - mFloatingActionsMenu.setOnFloatingActionsMenuUpdateListener(new FloatingActionsMenu.OnFloatingActionsMenuUpdateListener() { - @Override - public void onMenuExpanded() { - touchGuard.animate().alpha(0.6f); - - touchGuard.setClickable(true); - } - - @Override - public void onMenuCollapsed() { - touchGuard.animate().alpha(0); - - touchGuard.setClickable(false); - } - }); - - touchGuard.setClickable(false); } /** @@ -1341,36 +1349,25 @@ private void processIntentUniversalLink() { * ********************************************************************************************* */ - private void revealFloatingActionMenu() { - if (null != mFloatingActionsMenu) { - mFloatingActionsMenu.collapse(); - mFloatingActionsMenu.setVisibility(View.VISIBLE); - ViewPropertyAnimator animator = mFabMain.animate().scaleX(1).scaleY(1).alpha(1).setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - if (mFloatingActionsMenu != null) { - mFloatingActionsMenu.setVisibility(View.VISIBLE); - } - } - }); - animator.start(); - } + private void revealFloatingActionMenu() { + mFloatingActionsMenu.setVisibility(View.VISIBLE); } private void concealFloatingActionMenu() { if (null != mFloatingActionsMenu) { mFloatingActionsMenu.collapse(); - ViewPropertyAnimator animator = mFabMain.animate().scaleX(0).scaleY(0).alpha(0).setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - if (mFloatingActionsMenu != null) { - mFloatingActionsMenu.setVisibility(View.GONE); - } - } - }); - animator.start(); + mFloatingActionsMenu.setVisibility(View.GONE); + +// ViewPropertyAnimator animator = mFabMain.animate().scaleX(0).scaleY(0).alpha(0).setListener(new AnimatorListenerAdapter() { +// @Override +// public void onAnimationEnd(Animator animation) { +// super.onAnimationEnd(animation); +// if (mFloatingActionsMenu != null) { +// mFloatingActionsMenu.setVisibility(View.GONE); +// } +// } +// }); +// animator.start(); } } @@ -1432,15 +1429,6 @@ public View getFloatingActionButton() { return mFabMain; } - /** - * Open the room creation with inviting people. - */ - private void invitePeopleToNewRoom() { - final Intent settingsIntent = new Intent(VectorHomeActivity.this, VectorRoomCreationActivity.class); - settingsIntent.putExtra(MXCActionBarActivity.EXTRA_MATRIX_ID, mSession.getMyUserId()); - startActivity(settingsIntent); - } - /** * Create a room and open the dedicated activity */ @@ -1666,11 +1654,11 @@ public void onPreviewRoom(MXSession session, String roomId) { } /** - * Create the room forget / leave callback + * Create the room forget / leave im.vector.callback * * @param roomId the room id - * @param onSuccessCallback the success callback - * @return the asynchronous callback + * @param onSuccessCallback the success im.vector.callback + * @return the asynchronous im.vector.callback */ private ApiCallback createForgetLeaveCallback(final String roomId, final ApiCallback onSuccessCallback) { return new ApiCallback() { @@ -1687,7 +1675,13 @@ public void onSuccess(Void info) { private void onError(final String message) { hideWaitingView(); - Toast.makeText(VectorHomeActivity.this, message, Toast.LENGTH_LONG).show(); + /** + * BATNA ==> remove error toast from preview page + * + * */ + if (!BuildConfig.IS_SABA) { + Toast.makeText(VectorHomeActivity.this, message, Toast.LENGTH_LONG).show(); + } } @Override @@ -1716,7 +1710,7 @@ public void onUnexpectedError(Exception e) { * Trigger the room forget * * @param roomId the room id - * @param onSuccessCallback the success asynchronous callback + * @param onSuccessCallback the success asynchronous im.vector.callback */ public void onForgetRoom(final String roomId, final ApiCallback onSuccessCallback) { Room room = mSession.getDataHandler().getRoom(roomId); @@ -1731,7 +1725,7 @@ public void onForgetRoom(final String roomId, final ApiCallback onSuccessC * Trigger the room leave / invitation reject. * * @param roomId the room id - * @param onSuccessCallback the success asynchronous callback + * @param onSuccessCallback the success asynchronous im.vector.callback */ public void onRejectInvitation(final String roomId, final ApiCallback onSuccessCallback) { Room room = mSession.getDataHandler().getRoom(roomId); @@ -1764,7 +1758,12 @@ private void initSlidingMenu() { public void onDrawerClosed(View view) { switch (mSlidingMenuIndex) { case R.id.sliding_menu_messages: { - // no action + tabsGotoConversations(); + break; + } + + case R.id.sliding_menu_groups: { + tabsGotoGroups(); break; } @@ -1828,6 +1827,12 @@ public void run() { startActivity(new Intent(VectorHomeActivity.this, DebugMenuActivity.class)); break; } + + // Saba modification: show AboutSabaActivity instead of default about pages + case R.id.about_saba: { + startActivity(new Intent(VectorHomeActivity.this, AboutSabaActivity.class)); + break; + } } mSlidingMenuIndex = -1; @@ -2274,17 +2279,6 @@ public void onClick(DialogInterface dialog, int which) { * UI Event * ========================================================================================== */ - @OnClick(R.id.floating_action_menu_touch_guard) - void touchGuardClicked() { - mFloatingActionsMenu.collapse(); - } - - @OnClick(R.id.button_start_chat) - void fabMenuStartChat() { - mFloatingActionsMenu.collapse(); - invitePeopleToNewRoom(); - } - @OnClick(R.id.button_create_room) void fabMenuCreateRoom() { mFloatingActionsMenu.collapse(); @@ -2465,4 +2459,47 @@ public void setupKeysBackup() { public void recoverKeysBackup() { startActivity(KeysBackupManageActivity.Companion.intent(this, mSession.getMyUserId())); } + + /* ========================================================================================== + * Main Callbacks + * ========================================================================================== */ + @OnClick(R.id.button_start_chat) + void toolbarButtonStartChat() { + invitePeopleToNewRoom(); + } + + @OnClick(R.id.button_global_search) + void toolbarButtonGlobalChat() { + gotoGlobalSearch(); + } + + /* ========================================================================================== + * Main Helper Methods + * ========================================================================================== */ + + /** + * Open the room creation with inviting people. + * This method is used for starting a new 1-1 chat. + */ + private void invitePeopleToNewRoom() { + final Intent settingsIntent = new Intent(VectorHomeActivity.this, VectorRoomCreationActivity.class); + settingsIntent.putExtra(MXCActionBarActivity.EXTRA_MATRIX_ID, mSession.getMyUserId()); + startActivity(settingsIntent); + } + + private void gotoGlobalSearch() { + final Intent searchIntent = new Intent(this, VectorUnifiedSearchActivity.class); + if (mCurrentMenuId == R.id.bottom_action_people) { + searchIntent.putExtra(VectorUnifiedSearchActivity.EXTRA_TAB_INDEX, VectorUnifiedSearchActivity.SEARCH_PEOPLE_TAB_POSITION); + } + startActivity(searchIntent); + } + + private void tabsGotoConversations() { + mBottomNavigationView.findViewById(R.id.bottom_action_people).performClick(); + } + + private void tabsGotoGroups() { + mBottomNavigationView.findViewById(R.id.bottom_action_rooms).performClick(); + } } diff --git a/vector/src/main/java/im/vector/activity/VectorLauncherActivity.kt b/vector/src/main/java/im/vector/activity/VectorLauncherActivity.kt index dd837f2f39..0446729134 100644 --- a/vector/src/main/java/im/vector/activity/VectorLauncherActivity.kt +++ b/vector/src/main/java/im/vector/activity/VectorLauncherActivity.kt @@ -18,6 +18,7 @@ package im.vector.activity import android.content.Intent import android.os.Bundle +import android.os.Handler import androidx.appcompat.app.AppCompatActivity /** @@ -27,8 +28,14 @@ class VectorLauncherActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + /** + * BATNA ==> set duration for Splash Activity + */ + Handler().postDelayed(Runnable { + startActivity(Intent(this, LoginActivity::class.java)) + finish() },500) + + - startActivity(Intent(this, LoginActivity::class.java)) - finish() } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/activity/VectorMediaPickerActivity.java b/vector/src/main/java/im/vector/activity/VectorMediaPickerActivity.java index 0a9ed12bc7..5ac635f844 100755 --- a/vector/src/main/java/im/vector/activity/VectorMediaPickerActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorMediaPickerActivity.java @@ -53,6 +53,7 @@ import android.view.TextureView; import android.view.View; import android.view.ViewGroup; +import android.widget.EditText; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TableLayout; @@ -88,6 +89,7 @@ import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLSurface; +import im.vector.BuildConfig; import im.vector.R; import im.vector.VectorApp; import im.vector.listeners.ImageViewOnTouchListener; @@ -98,6 +100,7 @@ import im.vector.util.ViewUtilKt; import im.vector.view.RecentMediaLayout; import im.vector.view.VideoRecordView; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * VectorMediasPickerActivity is used to take a photo or to send an old one. @@ -175,6 +178,10 @@ private class MediaStoreMedia { // camera preview and gallery selection layout private ImageView mTakeImageView; + /** + * BATNA ==> add caption to image and video + */ + private EditText edtSendCaption; private TableLayout mGalleryTableLayout; private RelativeLayout mCameraPreviewLayout; private TextureView mCameraTextureView; @@ -229,7 +236,18 @@ public boolean onTouch(View v, MotionEvent event) { private VideoRecordView mRecordAnimationView; + /** + * BATNA ==> define String caption + */ + public static String stringCaption; + @NotNull + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public ActivityOtherThemes getOtherThemes() { return ActivityOtherThemes.NoActionBarFullscreen.INSTANCE; @@ -281,6 +299,11 @@ public void initUiAndData() { mVideoButtonView = findViewById(R.id.media_picker_preview_video_button); mTakeImageView = findViewById(R.id.media_picker_camera_button); + /** + * BATNA ==> find caption edit text + */ + if (BuildConfig.IS_SABA) + edtSendCaption = findViewById(R.id.test_send_caption); mGalleryTableLayout = findViewById(R.id.gallery_table_layout); // hide switch camera view if there is only one camera @@ -335,8 +358,15 @@ public boolean onTouch(View v, MotionEvent event) { public void onClick(View v) { if (null != mVideoUri) { sendVideoFile(); + /** + * BATNA ==> init String caption + */ + if (BuildConfig.IS_SABA) + stringCaption = edtSendCaption.getText().toString(); } else { attachImageFrom(mTakenImageOrigin); + if (BuildConfig.IS_SABA) + stringCaption = edtSendCaption.getText().toString(); } } }); diff --git a/vector/src/main/java/im/vector/activity/VectorMediaViewerActivity.java b/vector/src/main/java/im/vector/activity/VectorMediaViewerActivity.java index 191d61c3af..0570d25fe4 100755 --- a/vector/src/main/java/im/vector/activity/VectorMediaViewerActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorMediaViewerActivity.java @@ -17,6 +17,7 @@ package im.vector.activity; +import android.content.Context; import android.content.Intent; import android.net.Uri; import android.view.Menu; @@ -48,6 +49,7 @@ import im.vector.adapters.VectorMediaViewerAdapter; import im.vector.util.PermissionsToolsKt; import im.vector.util.SlidableMediaInfo; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * Display a medias list. @@ -117,6 +119,11 @@ public void transformPage(View view, float position) { } } + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_vector_media_viewer; diff --git a/vector/src/main/java/im/vector/activity/VectorMemberDetailsActivity.java b/vector/src/main/java/im/vector/activity/VectorMemberDetailsActivity.java index d18054d80c..69a88e7d2c 100644 --- a/vector/src/main/java/im/vector/activity/VectorMemberDetailsActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorMemberDetailsActivity.java @@ -18,6 +18,7 @@ package im.vector.activity; import android.app.ActivityOptions; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.Build; @@ -42,6 +43,7 @@ import org.matrix.androidsdk.core.callback.ApiCallback; import org.matrix.androidsdk.core.callback.SimpleApiCallback; import org.matrix.androidsdk.core.model.MatrixError; +import org.matrix.androidsdk.crypto.CryptoConstantsKt; import org.matrix.androidsdk.crypto.MXCryptoError; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; @@ -74,6 +76,7 @@ import im.vector.util.PermissionsToolsKt; import im.vector.util.SystemUtilsKt; import im.vector.util.VectorUtils; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * VectorMemberDetailsActivity displays the member information and allows to perform some dedicated actions. @@ -244,6 +247,11 @@ public void run() { } }; + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (requestCode == DEVICE_VERIFICATION_REQ_CODE) { @@ -371,9 +379,9 @@ private void startCheckCallPermissions(boolean aIsVideoCall) { final int requestCode; if (aIsVideoCall) { - requestCode = PermissionsToolsKt.PERMISSION_REQUEST_CODE_VIDEO_CALL; + requestCode = PermissionsToolsKt.PERMISSIONS_FOR_VIDEO_IP_CALL; } else { - requestCode = PermissionsToolsKt.PERMISSION_REQUEST_CODE_AUDIO_CALL; + requestCode = PermissionsToolsKt.PERMISSIONS_FOR_AUDIO_IP_CALL; } if (PermissionsToolsKt.checkPermissions(requestCode, this, requestCode)) { @@ -385,11 +393,11 @@ private void startCheckCallPermissions(boolean aIsVideoCall) { public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (0 == permissions.length) { Log.d(LOG_TAG, "## onRequestPermissionsResult(): cancelled " + requestCode); - } else if (requestCode == PermissionsToolsKt.PERMISSION_REQUEST_CODE_AUDIO_CALL) { + } else if (requestCode == PermissionsToolsKt.PERMISSIONS_FOR_AUDIO_IP_CALL) { if (PermissionsToolsKt.onPermissionResultAudioIpCall(this, grantResults)) { startCall(false); } - } else if (requestCode == PermissionsToolsKt.PERMISSION_REQUEST_CODE_VIDEO_CALL) { + } else if (requestCode == PermissionsToolsKt.PERMISSIONS_FOR_VIDEO_IP_CALL) { if (PermissionsToolsKt.onPermissionResultVideoIpCall(this, grantResults)) { startCall(true); } @@ -436,7 +444,7 @@ public void onClick(DialogInterface dialog, int which) { Log.d(LOG_TAG, "## performItemAction(): Start new room - start chat"); enableProgressBarView(CommonActivityUtils.UTILS_DISPLAY_PROGRESS_BAR); - mSession.createDirectMessageRoom(mMemberId, mCreateDirectMessageCallBack); + mSession.createDirectMessageRoom(mMemberId, CryptoConstantsKt.MXCRYPTO_ALGORITHM_MEGOLM, mCreateDirectMessageCallBack); } }) .setNegativeButton(R.string.cancel, null) @@ -1573,6 +1581,7 @@ void onUserInfoClicked(TextView v) { private void refreshUserDevicesList() { // Refresh the adapter data + mSession.checkCrypto(); List deviceList = mSession.getCrypto().getUserDevices(mMemberId); mDevicesListViewAdapter.clear(); diff --git a/vector/src/main/java/im/vector/activity/VectorPublicRoomsActivity.java b/vector/src/main/java/im/vector/activity/VectorPublicRoomsActivity.java index 49dd5e5beb..1284175bf6 100755 --- a/vector/src/main/java/im/vector/activity/VectorPublicRoomsActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorPublicRoomsActivity.java @@ -17,6 +17,7 @@ package im.vector.activity; +import android.content.Context; import android.content.Intent; import androidx.fragment.app.FragmentManager; @@ -26,6 +27,7 @@ import im.vector.R; import im.vector.fragments.VectorPublicRoomsListFragment; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * Displays a list of public rooms @@ -36,6 +38,12 @@ public class VectorPublicRoomsActivity extends MXCActionBarActivity { public static final String EXTRA_SEARCHED_PATTERN = "VectorPublicRoomsActivity.EXTRA_SEARCHED_PATTERN"; private static final String TAG_FRAGMENT_PUBLIC_ROOMS_LIST = "VectorPublicRoomsActivity.TAG_FRAGMENT_PUBLIC_ROOMS_LIST"; + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_vector_public_rooms; diff --git a/vector/src/main/java/im/vector/activity/VectorRoomActivity.java b/vector/src/main/java/im/vector/activity/VectorRoomActivity.java index 3819fa6172..a855c82657 100755 --- a/vector/src/main/java/im/vector/activity/VectorRoomActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorRoomActivity.java @@ -27,11 +27,14 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.ColorStateList; import android.content.res.Configuration; import android.graphics.Color; +import android.media.MediaPlayer; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.os.Vibrator; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -50,12 +53,17 @@ import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.appcompat.app.AlertDialog; +import androidx.core.app.ActivityCompat; import androidx.fragment.app.FragmentManager; import com.google.gson.JsonParser; @@ -93,6 +101,8 @@ import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.message.Message; +import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -106,10 +116,13 @@ import butterknife.OnClick; import butterknife.OnLongClick; import butterknife.OnTouch; +import im.vector.BuildConfig; import im.vector.Matrix; import im.vector.R; +import im.vector.Thread.VectorThread; import im.vector.VectorApp; import im.vector.activity.util.RequestCodesKt; +import im.vector.adapters.VectorMessagesAdapter; import im.vector.dialogs.DialogCallAdapter; import im.vector.dialogs.DialogListItem; import im.vector.dialogs.DialogSendItemAdapter; @@ -134,6 +147,7 @@ import im.vector.util.VectorUtils; import im.vector.view.ActiveWidgetsBanner; import im.vector.view.NotificationAreaView; +import im.vector.view.NotificationAreaViewToolbar; import im.vector.view.VectorAutoCompleteTextView; import im.vector.view.VectorOngoingConferenceCallView; import im.vector.view.VectorPendingCallView; @@ -141,6 +155,9 @@ import im.vector.widgets.WidgetsManager; import im.vector.widgets.model.JitsiWidgetProperties; import kotlin.Unit; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; + +import static im.vector.util.PermissionsToolsKt.MY_PERMISSIONS_REQUEST_REC_Audio; /** * Displays a single room with messages. @@ -152,6 +169,7 @@ public class VectorRoomActivity extends MXCActionBarActivity implements VectorMessageListFragment.VectorMessageListFragmentListener, VectorReadReceiptsDialogFragment.VectorReadReceiptsDialogFragmentListener { + // the session public static final String EXTRA_MATRIX_ID = MXCActionBarActivity.EXTRA_MATRIX_ID; // the room id (string) @@ -294,6 +312,10 @@ public class VectorRoomActivity extends MXCActionBarActivity implements @BindView(R.id.room_notifications_area) NotificationAreaView mNotificationsArea; + // notifications area toolbar + @BindView(R.id.room_notifications_area_head) + NotificationAreaViewToolbar mNotificationsAreaHead; + private String mLatestTypingMessage; private Boolean mIsScrolledToTheBottom; private Event mLatestDisplayedEvent; // the event at the bottom of the list @@ -332,6 +354,299 @@ public class VectorRoomActivity extends MXCActionBarActivity implements @BindView(R.id.room_preview_subinvitation_textview) TextView subInvitationTextView; + private static ImageView recordButton; + + private static File newFile; + private ColorStateList hintColor; + @SuppressLint("StaticFieldLeak") + private static ImageView play; + private static ImageView pause; + private static ImageView close; + private SeekBar seekBar; + private static TextView voiceCancel; + public static String voicePath; + + private static LinearLayout linearLayout; + private static Handler myHandler = new Handler(); + public static String mediaDataSourceName; + + private static MediaPlayer mediaPlayer; + private static boolean isRemainderVoice; + + private static Handler mHandler; + private static int time = 0; + private boolean recordIsDone = false; + private static VectorThread vectorThread; + private static boolean actionUp; + + public static MediaPlayer getMediaPlayer() { + return mediaPlayer; + } + public static LinearLayout getLinearLayout() { + return linearLayout; + } + + public static ImageView getPlay() { + return play; + } + + public static ImageView getPause() { + return pause; + } + + @SuppressLint("SetTextI18n") + + public void playBack(String savedMediaPath, boolean downloaded) { + mediaDataSourceName = savedMediaPath; + if (mediaPlayer.isPlaying()) { + mediaPlayer.stop(); + } + File file = new File(savedMediaPath); + if (file.exists() && downloaded) { + mVectorMessageListFragment.getMessageAdapter().notifyDataSetChanged(); + return; + } + + mediaPlayer = new MediaPlayer(); + linearLayout.setVisibility(View.VISIBLE); + pause.setVisibility(View.VISIBLE); + play.setVisibility(View.GONE); + + try { + mediaPlayer.reset(); + isRemainderVoice = true; + mediaPlayer.setDataSource(savedMediaPath); + mediaPlayer.prepare(); + mediaPlayer.start(); + seekBar.setMax(mediaPlayer.getDuration()); + myHandler.postDelayed(UpdateVoiceTime, 100); + + } catch (IOException e) { + e.printStackTrace(); + } + mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + linearLayout.setVisibility(View.GONE); + isRemainderVoice = false; + } + }); + pause.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mediaPlayer.isPlaying()) { + mediaPlayer.pause(); + play.setVisibility(View.VISIBLE); + pause.setVisibility(View.GONE); + VectorMessagesAdapter.getVectorMessagesAdapterImageTypeView().setImageResource(R.drawable.play); + } + } + }); + play.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mediaPlayer.isPlaying() && mediaPlayer.getCurrentPosition() <= 500) + return; + + mediaPlayer.start(); + pause.setVisibility(View.VISIBLE); + play.setVisibility(View.GONE); + VectorMessagesAdapter.getVectorMessagesAdapterImageTypeView().setImageResource(R.drawable.pause); + } + }); + close.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + linearLayout.setVisibility(View.GONE); + mediaPlayer.stop(); + isRemainderVoice = false; + if (VectorMessagesAdapter.getVectorMessagesAdapterImageTypeView() != null) { + VectorMessagesAdapter.getVectorMessagesAdapterImageTypeView().setImageResource(R.drawable.play); + } + VectorMessagesAdapter.setRemainderVoice(false); + } + }); + seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) + mediaPlayer.seekTo(progress); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + } + }); + mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { + @Override + public boolean onError(MediaPlayer mp, int what, int extra) { + mediaPlayer = new MediaPlayer(); + mediaPlayer.reset(); + return false; + } + }); + } + + private Runnable UpdateVoiceTime = new Runnable() { + public void run() { + int startTime = mediaPlayer.getCurrentPosition(); + seekBar.setProgress(startTime); + if (isRemainderVoice) + myHandler.postDelayed(this, 100); + } + }; + + Runnable mAction = new Runnable() { + @Override + public void run() { + + if (actionUp) { + mHandler.postDelayed(this, 100); + if (time < 500) { + time += 100; + + } else { + vectorThread = new VectorThread(); + runOnUiThread(new Runnable() { + @Override + public void run() { + mEditText.setHint(R.string.recording); + voiceCancel.setText(R.string.cancel_recording); + } + }); + vectorThread.startVoiceRecorder(getApplicationContext()); + vectorThread.start(); + recordIsDone = true; + actionUp = false; + } + } + + } + }; + + @RequiresApi(api = Build.VERSION_CODES.O) + @SuppressLint({"WrongViewCast", "ClickableViewAccessibility"}) + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + voicePath =getApplicationContext().getCacheDir()+"/voice/"; + mediaPlayer = new MediaPlayer(); + if (!mEditText.getText().toString().equalsIgnoreCase(" recording ... ")) + mEditText.setText(""); + recordButton = findViewById(R.id.room_send_audio_view); + play = findViewById(R.id.play); + pause = findViewById(R.id.pause); + voiceCancel = findViewById(R.id.voice_cancel_hint); + close = findViewById(R.id.close); + seekBar = findViewById(R.id.seekBar); + linearLayout = findViewById(R.id.play_layout); + hintColor = mEditText.getHintTextColors(); + resetLayout(); + Activity vector = this; + + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, MY_PERMISSIONS_REQUEST_REC_Audio); + } + recordButton.setOnTouchListener(new View.OnTouchListener() { + boolean cancelRecording = false; + + @SuppressLint({"ClickableViewAccessibility", "SetTextI18n"}) + @Override + public boolean onTouch(View v, MotionEvent event) { + mediaPlayer.stop(); + mediaPlayer.reset(); + linearLayout.setVisibility(View.GONE); + int y = 0, x = 0, xResult = 0; + int eventX = (int) event.getX(); + int[] location = new int[2]; + recordButton.getLocationOnScreen(location); + x = location[0]; + y = location[1]; + + xResult = Math.abs(Math.abs(x) + Math.abs(eventX)); + int a = (206 + (eventX)); + int alpha = eventX > 0 ? 255 : Math.max(0, a); + voiceCancel.setTextColor(Color.argb(alpha, 0, 0, 0)); + mEditText.setHintTextColor(Color.argb(alpha, 230, 10, 10)); + + if (xResult >= Math.abs(x + 150)) { + cancelRecording = true; + resetLayout(); + if (VectorThread.getAudioRecorder() != null) { + vectorThread.resetVoiceRecorder(); + vectorThread.deleteFile(); + } + } + + if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) { + mHandler = new Handler(); + if (event.getAction() == MotionEvent.ACTION_DOWN) { + actionUp = true; + mHandler.postDelayed(mAction, 0); + voiceCancel.setVisibility(View.VISIBLE); + mStartCallLayout.setVisibility(View.INVISIBLE); + mSendImageView.setVisibility(View.GONE); + mEditText.setHint(""); + recordButton.setScaleX((float) 1.4); + recordButton.setScaleY((float) 1.5); + mEditText.setHintTextColor(Color.argb(255, 230, 10, 10)); + + } else if (event.getAction() == MotionEvent.ACTION_UP && event.getEventTime() - event.getDownTime() > 1550 && !cancelRecording) { + resetLayout(); + actionUp = false; + time = 0; + if (recordIsDone) { + sendMediasIntent(vectorThread.stopVoiceRecorder(getApplicationContext())); + recordIsDone = false; + } + + mEditText.setText(""); + mEditText.setTextColor(Color.argb(255, 0, 0, 0)); + + } else if (event.getAction() == MotionEvent.ACTION_UP && event.getEventTime() - event.getDownTime() <= 1550) { + resetLayout(); + if (vectorThread != null) + vectorThread.deleteFile(); + if (vectorThread != null) { + vectorThread.resetVoiceRecorder(); + } + } + + } else if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(vector, new String[]{Manifest.permission.RECORD_AUDIO}, MY_PERMISSIONS_REQUEST_REC_Audio); + } + if (event.getAction() == MotionEvent.ACTION_UP) { + actionUp = false; + time = 0; + if (vectorThread != null) { + vectorThread.resetVoiceRecorder(); + } + resetLayout(); + if (cancelRecording) { + cancelRecording = false; + return false; + } + } + return true; + } + }); + } + + private void resetLayout() { + recordButton.setScaleX((float) 1); + recordButton.setScaleY((float) 1); + mEditText.setHint(R.string.room_message_placeholder_encrypted); + mEditText.setHintTextColor(hintColor); + voiceCancel.setVisibility(View.GONE); + mStartCallLayout.setVisibility(View.VISIBLE); + mSendImageView.setVisibility(View.VISIBLE); + } + // network events private final IMXNetworkEventListener mNetworkEventListener = new IMXNetworkEventListener() { @Override @@ -620,11 +935,17 @@ public void onPreviewSizeChanged(int width, int height) { // Activity classes //================================================================================ + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_vector_room; } + @Override public void initUiAndData() { setWaitingView(findViewById(R.id.main_progress_layout)); @@ -712,6 +1033,45 @@ public void jumpToBottom() { } }); + + /** + * Batna => setDelegate Notification toolbar + */ + if (BuildConfig.IS_SABA) { + mNotificationsAreaHead.setDelegate(new NotificationAreaViewToolbar.Delegate() { + @NotNull + @Override + public IMessagesAdapterActionsListener providesMessagesActionListener() { + return mVectorMessageListFragment; + } + + @Override + public void resendUnsentEvents() { + mVectorMessageListFragment.resendUnsentMessages(); + } + + @Override + public void deleteUnsentEvents() { + mVectorMessageListFragment.deleteUnsentEvents(); + } + + @Override + public void closeScreen() { + setResult(Activity.RESULT_OK); + finish(); + } + + @Override + public void jumpToBottom() { + if (mReadMarkerManager != null) { + mReadMarkerManager.handleJumpToBottom(); + } else { + mVectorMessageListFragment.scrollToBottom(0); + } + } + }); + } + // use a toolbar instead of the actionbar // to be able to display an expandable header configureToolbar(); @@ -1048,6 +1408,8 @@ private void checkIfUserHasBeenKicked() { if ((!TextUtils.isEmpty(mEventId) || (null != sRoomPreviewData)) || hasBeenKicked) { if (!mIsUnreadPreviewMode || hasBeenKicked) { mNotificationsArea.setVisibility(View.GONE); + if (BuildConfig.IS_SABA) + mNotificationsAreaHead.setVisibility(View.GONE); mBottomSeparator.setVisibility(View.GONE); findViewById(R.id.room_notification_separator).setVisibility(View.GONE); } @@ -1286,6 +1648,7 @@ protected void onActivityResult(int requestCode, int resultCode, final Intent da case TAKE_IMAGE_REQUEST_CODE: case RECORD_AUDIO_REQUEST_CODE: sendMediasIntent(data); + break; case RequestCodesKt.STICKER_PICKER_ACTIVITY_REQUEST_CODE: sendSticker(data); @@ -1430,6 +1793,9 @@ public void onScrollStateChanged(int scrollState) { if (mNotificationsArea != null) { mNotificationsArea.setScrollState(scrollState); } + if (mNotificationsAreaHead != null) { + mNotificationsAreaHead.setScrollState(scrollState); + } } @Override @@ -1506,7 +1872,8 @@ public boolean onPrepareOptionsMenu(Menu menu) { searchInRoomMenuItem.setVisible(!mRoom.isEncrypted()); } if (useMatrixAppsMenuItem != null) { - useMatrixAppsMenuItem.setVisible(hasIntegrationManager && TextUtils.isEmpty(mEventId) && null == sRoomPreviewData); + useMatrixAppsMenuItem.setVisible(false); + //useMatrixAppsMenuItem.setVisible(hasIntegrationManager && TextUtils.isEmpty(mEventId) && null == sRoomPreviewData); } if (resendUnsentMenuItem != null) { resendUnsentMenuItem.setVisible(mHasUnsentEvents); @@ -1725,32 +2092,43 @@ private void onCallItemClicked(int which) { isVideoCall = false; permissions = PermissionsToolsKt.PERMISSIONS_FOR_AUDIO_IP_CALL; requestCode = PermissionsToolsKt.PERMISSION_REQUEST_CODE_AUDIO_CALL; + if (BuildConfig.IS_SABA) { + if (PermissionsToolsKt.checkPermissions(permissions, VectorRoomActivity.this, requestCode)) { + startIpCall(PreferencesManager.useJitsiConfCall(VectorRoomActivity.this), isVideoCall); + } + } } else { isVideoCall = true; permissions = PermissionsToolsKt.PERMISSIONS_FOR_VIDEO_IP_CALL; requestCode = PermissionsToolsKt.PERMISSION_REQUEST_CODE_VIDEO_CALL; + if (BuildConfig.IS_SABA) { + if (PermissionsToolsKt.checkPermissions(permissions, VectorRoomActivity.this, requestCode)) { + startIpCall(PreferencesManager.useJitsiConfCall(VectorRoomActivity.this), isVideoCall); + } + } } + if (!BuildConfig.IS_SABA) { + AlertDialog.Builder builder = new AlertDialog.Builder(VectorRoomActivity.this) + .setTitle(R.string.dialog_title_confirmation); - AlertDialog.Builder builder = new AlertDialog.Builder(VectorRoomActivity.this) - .setTitle(R.string.dialog_title_confirmation); - - if (isVideoCall) { - builder.setMessage(getString(R.string.start_video_call_prompt_msg)); - } else { - builder.setMessage(getString(R.string.start_voice_call_prompt_msg)); - } + if (isVideoCall) { + builder.setMessage(getString(R.string.start_video_call_prompt_msg)); + } else { + builder.setMessage(getString(R.string.start_voice_call_prompt_msg)); + } - builder - .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (PermissionsToolsKt.checkPermissions(permissions, VectorRoomActivity.this, requestCode)) { - startIpCall(PreferencesManager.useJitsiConfCall(VectorRoomActivity.this), isVideoCall); + builder + .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (PermissionsToolsKt.checkPermissions(permissions, VectorRoomActivity.this, requestCode)) { + startIpCall(PreferencesManager.useJitsiConfCall(VectorRoomActivity.this), isVideoCall); + } } - } - }) - .setNegativeButton(R.string.cancel, null) - .show(); + }) + .setNegativeButton(R.string.cancel, null) + .show(); + } } /** @@ -2021,6 +2399,7 @@ public void sendEmote(String emote, String formattedEmote, String format) { */ @SuppressLint("NewApi") private void sendMediasIntent(Intent intent) { + // sanity check if ((null == intent) && (null == mLatestTakePictureCameraUri)) { return; @@ -2030,11 +2409,13 @@ private void sendMediasIntent(Intent intent) { if (null != intent) { sharedDataItems = new ArrayList<>(RoomMediaMessage.listRoomMediaMessages(intent)); + } // check the extras if ((0 == sharedDataItems.size()) && (null != intent)) { Bundle bundle = intent.getExtras(); + // sanity checks if (null != bundle) { if (bundle.containsKey(Intent.EXTRA_TEXT)) { @@ -2049,11 +2430,14 @@ public void run() { } } } + + boolean hasItemToShare = !sharedDataItems.isEmpty(); boolean isTextOnly = sharedDataItems.size() == 1 && "text/plain".equals(sharedDataItems.get(0).getMimeType(this)); boolean shouldPreviewMedia = PreferencesManager.previewMediaWhenSending(this); + if (hasItemToShare && !isTextOnly && shouldPreviewMedia) { if (null != intent) { intent.setClass(this, MediaPreviewerActivity.class); @@ -2076,7 +2460,7 @@ public void run() { } mVectorRoomMediasSender.sendMedias(sharedDataItems); } - +// Toast.makeText(this, sharedDataItems.size(), Toast.LENGTH_SHORT).show(); mLatestTakePictureCameraUri = null; } @@ -2647,17 +3031,23 @@ private void refreshNotificationsArea() { final MatrixError softResourceLimitExceededError = limitResourceState.softErrorOrNull(); NotificationAreaView.State state = NotificationAreaView.State.Default.INSTANCE; + NotificationAreaViewToolbar.State stateToolbar = NotificationAreaViewToolbar.State.Default.INSTANCE; mHasUnsentEvents = false; if (!mIsUnreadPreviewMode && !TextUtils.isEmpty(mEventId)) { state = NotificationAreaView.State.Hidden.INSTANCE; + stateToolbar = NotificationAreaViewToolbar.State.Hidden.INSTANCE; } else if (hardResourceLimitExceededError != null) { state = new NotificationAreaView.State.ResourceLimitExceededError(false, hardResourceLimitExceededError); + stateToolbar = new NotificationAreaViewToolbar.State.ResourceLimitExceededError(false, hardResourceLimitExceededError); } else if (softResourceLimitExceededError != null) { state = new NotificationAreaView.State.ResourceLimitExceededError(true, softResourceLimitExceededError); + stateToolbar = new NotificationAreaViewToolbar.State.ResourceLimitExceededError(true, softResourceLimitExceededError); } else if (!Matrix.getInstance(this).isConnected()) { state = NotificationAreaView.State.ConnectionError.INSTANCE; + stateToolbar = NotificationAreaViewToolbar.State.ConnectionError.INSTANCE; } else if (mIsUnreadPreviewMode) { state = NotificationAreaView.State.UnreadPreview.INSTANCE; + stateToolbar = NotificationAreaViewToolbar.State.UnreadPreview.INSTANCE; } else { final List undeliveredEvents = mSession.getDataHandler().getStore().getUndeliveredEvents(mRoom.getRoomId()); final List unknownDeviceEvents = mSession.getDataHandler().getStore().getUnknownDeviceEvents(mRoom.getRoomId()); @@ -2666,6 +3056,12 @@ private void refreshNotificationsArea() { if (hasUndeliverableEvents || hasUnknownDeviceEvents) { mHasUnsentEvents = true; state = new NotificationAreaView.State.UnsentEvents(hasUndeliverableEvents, hasUnknownDeviceEvents); + mNotificationsArea.setBackgroundColor(Color.WHITE); + if (findViewById(R.id.room_notification_message).getVisibility() == View.GONE) { + findViewById(R.id.room_notification_message).setVisibility(View.VISIBLE); + mNotificationsArea.setBackgroundColor(Color.WHITE); + } + } else if ((null != mIsScrolledToTheBottom) && (!mIsScrolledToTheBottom)) { int unreadCount = 0; final RoomSummary summary = mRoom.getDataHandler().getStore().getSummary(mRoom.getRoomId()); @@ -2673,8 +3069,10 @@ private void refreshNotificationsArea() { unreadCount = mRoom.getDataHandler().getStore().eventsCountAfter(mRoom.getRoomId(), summary.getReadReceiptEventId()); } state = new NotificationAreaView.State.ScrollToBottom(unreadCount, mLatestTypingMessage); + stateToolbar = new NotificationAreaViewToolbar.State.ScrollToBottom(unreadCount, mLatestTypingMessage); } else if (!TextUtils.isEmpty(mLatestTypingMessage)) { state = new NotificationAreaView.State.Typing(mLatestTypingMessage); + stateToolbar = new NotificationAreaViewToolbar.State.Typing(mLatestTypingMessage); } else if (mRoom.getState().isVersioned()) { final RoomTombstoneContent roomTombstoneContent = mRoom.getState().getRoomTombstoneContent(); final List events = mRoom.getState().getStateEvents(new HashSet<>(Arrays.asList(Event.EVENT_TYPE_STATE_ROOM_TOMBSTONE))); @@ -2685,10 +3083,17 @@ private void refreshNotificationsArea() { } state = new NotificationAreaView.State.Tombstone(roomTombstoneContent, sender); + stateToolbar = new NotificationAreaViewToolbar.State.Tombstone(roomTombstoneContent, sender); } } mNotificationsArea.render(state); + /** + * Batna ==> render state (Notification) in toolbar + */ + if (BuildConfig.IS_SABA) + mNotificationsAreaHead.render(stateToolbar); + supportInvalidateOptionsMenu(); } @@ -3044,13 +3449,34 @@ private void checkSendEventStatus() { mBottomSeparator.setVisibility(View.VISIBLE); mSendingMessagesLayout.setVisibility(View.VISIBLE); mCanNotPostTextView.setVisibility(View.GONE); + + /** + * BATNA ==> Show room_bottom_layout when user have permission send message + */ + if (BuildConfig.IS_SABA) { + RelativeLayout layout = findViewById(R.id.room_bottom_layout); + ViewGroup.LayoutParams params = layout.getLayoutParams(); + params.height = ViewGroup.LayoutParams.WRAP_CONTENT; + layout.setLayoutParams(params); + } } else if (state.isVersioned() || mSession.getDataHandler().getResourceLimitExceededError() != null) { mBottomSeparator.setVisibility(View.GONE); mBottomLayout.getLayoutParams().height = 0; } else { mBottomSeparator.setVisibility(View.GONE); mSendingMessagesLayout.setVisibility(View.GONE); - mCanNotPostTextView.setVisibility(View.VISIBLE); + + /** + * BATNA ==> Donot show room_bottom_layout when user havenot permission send message + */ + if (BuildConfig.IS_SABA) { + RelativeLayout layout = findViewById(R.id.room_bottom_layout); + ViewGroup.LayoutParams params = layout.getLayoutParams(); + params.height = 0; + layout.setLayoutParams(params); + } else { + mCanNotPostTextView.setVisibility(View.VISIBLE); + } } } } @@ -3159,8 +3585,7 @@ private void setMemberHeaderText(int activeMembersCount, int joinedMembersCount) } else if (null != sRoomPreviewData) { text = getResources().getQuantityString(R.plurals.room_title_members, joinedMembersCount, joinedMembersCount); } else { - text = activeMembersCount + "/" + - getResources().getQuantityString(R.plurals.room_header_active_members_count, joinedMembersCount, joinedMembersCount); + text = getString(R.string.room_header_online_members, joinedMembersCount, activeMembersCount); } mActionBarHeaderActiveMembersTextView.setText(text); @@ -3358,175 +3783,225 @@ public RoomPreviewData getRoomPreviewData() { */ private void manageRoomPreview() { if (null != sRoomPreviewData) { - mRoomPreviewLayout.setVisibility(View.VISIBLE); - - Button joinButton = findViewById(R.id.button_join_room); - Button declineButton = findViewById(R.id.button_decline); - final RoomEmailInvitation roomEmailInvitation = sRoomPreviewData.getRoomEmailInvitation(); - - String roomName = sRoomPreviewData.getRoomName(); - if (TextUtils.isEmpty(roomName)) { - roomName = " "; - } - - Log.d(LOG_TAG, "Preview the room " + sRoomPreviewData.getRoomId()); +/** + * BATNA==> remove preview layout + */ + if (BuildConfig.IS_SABA) { + mRoomPreviewLayout.setVisibility(View.GONE); + if (null != sRoomPreviewData) { + Room room = sRoomPreviewData.getSession().getDataHandler().getRoom(sRoomPreviewData.getRoomId()); - // if the room already exists - if (null != mRoom) { - Log.d(LOG_TAG, "manageRoomPreview : The room is known"); + String signUrl = null; + showWaitingView(); - String inviter = ""; + room.joinWithThirdPartySigned(sRoomPreviewData.getSession(), sRoomPreviewData.getRoomIdOrAlias(), signUrl, new ApiCallback() { + @Override + public void onSuccess(Void info) { + onJoined(); + } - if (null != roomEmailInvitation) { - inviter = roomEmailInvitation.inviterName; - } + private void onError(String errorMessage) { + Toast.makeText(VectorRoomActivity.this, errorMessage, Toast.LENGTH_SHORT).show(); + hideWaitingView(); + } - if (TextUtils.isEmpty(inviter)) { - mRoom.getActiveMembersAsync(new SimpleApiCallback>(this) { @Override - public void onSuccess(List members) { - String inviter = ""; + public void onNetworkError(Exception e) { + onError(e.getLocalizedMessage()); + } - for (RoomMember member : members) { - if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_JOIN)) { - inviter = TextUtils.isEmpty(member.displayname) ? member.getUserId() : member.displayname; - } + @Override + public void onMatrixError(MatrixError e) { + if (MatrixError.M_CONSENT_NOT_GIVEN.equals(e.errcode)) { + hideWaitingView(); + getConsentNotGivenHelper().displayDialog(e); + } else { + onError(e.getLocalizedMessage()); } + } - invitationTextView.setText(getString(R.string.room_preview_invitation_format, inviter)); + @Override + public void onUnexpectedError(Exception e) { + onError(e.getLocalizedMessage()); } }); - } else { - invitationTextView.setText(getString(R.string.room_preview_invitation_format, inviter)); } - declineButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Log.d(LOG_TAG, "The user clicked on decline."); + } else { - showWaitingView(); + mRoomPreviewLayout.setVisibility(View.VISIBLE); - mRoom.leave(new ApiCallback() { - @Override - public void onSuccess(Void info) { - Log.d(LOG_TAG, "The invitation is rejected"); - onDeclined(); - } + Button joinButton = findViewById(R.id.button_join_room); + Button declineButton = findViewById(R.id.button_decline); - private void onError(String errorMessage) { - Log.d(LOG_TAG, "The invitation rejection failed " + errorMessage); - Toast.makeText(VectorRoomActivity.this, errorMessage, Toast.LENGTH_SHORT).show(); - hideWaitingView(); - } + final RoomEmailInvitation roomEmailInvitation = sRoomPreviewData.getRoomEmailInvitation(); - @Override - public void onNetworkError(Exception e) { - onError(e.getLocalizedMessage()); - } + String roomName = sRoomPreviewData.getRoomName(); + if (TextUtils.isEmpty(roomName)) { + roomName = " "; + } + + Log.d(LOG_TAG, "Preview the room " + sRoomPreviewData.getRoomId()); + + + // if the room already exists + if (null != mRoom) { + Log.d(LOG_TAG, "manageRoomPreview : The room is known"); + String inviter = ""; + + if (null != roomEmailInvitation) { + inviter = roomEmailInvitation.inviterName; + } + + if (TextUtils.isEmpty(inviter)) { + mRoom.getActiveMembersAsync(new SimpleApiCallback>(this) { @Override - public void onMatrixError(MatrixError e) { - if (MatrixError.M_CONSENT_NOT_GIVEN.equals(e.errcode)) { - hideWaitingView(); - getConsentNotGivenHelper().displayDialog(e); - } else { - onError(e.getLocalizedMessage()); + public void onSuccess(List members) { + String inviter = ""; + + for (RoomMember member : members) { + if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_JOIN)) { + inviter = TextUtils.isEmpty(member.displayname) ? member.getUserId() : member.displayname; + } } - } - @Override - public void onUnexpectedError(Exception e) { - onError(e.getLocalizedMessage()); + invitationTextView.setText(getString(R.string.room_preview_invitation_format, inviter)); } }); + } else { + invitationTextView.setText(getString(R.string.room_preview_invitation_format, inviter)); } - }); - } else { - if ((null != roomEmailInvitation) && !TextUtils.isEmpty(roomEmailInvitation.email)) { - invitationTextView.setText(getString(R.string.room_preview_invitation_format, roomEmailInvitation.inviterName)); - subInvitationTextView.setText(getString(R.string.room_preview_unlinked_email_warning, roomEmailInvitation.email)); - } else { - invitationTextView.setText(getString(R.string.room_preview_try_join_an_unknown_room, - TextUtils.isEmpty(sRoomPreviewData.getRoomName()) ? getString(R.string.room_preview_try_join_an_unknown_room_default) : roomName)); + declineButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d(LOG_TAG, "The user clicked on decline."); - // the room preview has some messages - if ((null != sRoomPreviewData.getRoomResponse()) && (null != sRoomPreviewData.getRoomResponse().messages)) { - subInvitationTextView.setText(getString(R.string.room_preview_room_interactions_disabled)); - } - } + showWaitingView(); - declineButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Log.d(LOG_TAG, "The invitation is declined (unknown room)"); + mRoom.leave(new ApiCallback() { + @Override + public void onSuccess(Void info) { + Log.d(LOG_TAG, "The invitation is rejected"); + onDeclined(); + } - sRoomPreviewData = null; - finish(); - } - }); - } + private void onError(String errorMessage) { + Log.d(LOG_TAG, "The invitation rejection failed " + errorMessage); + Toast.makeText(VectorRoomActivity.this, errorMessage, Toast.LENGTH_SHORT).show(); + hideWaitingView(); + } - joinButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Log.d(LOG_TAG, "The user clicked on Join."); + @Override + public void onNetworkError(Exception e) { + onError(e.getLocalizedMessage()); + } - if (null != sRoomPreviewData) { - Room room = sRoomPreviewData.getSession().getDataHandler().getRoom(sRoomPreviewData.getRoomId()); + @Override + public void onMatrixError(MatrixError e) { + if (MatrixError.M_CONSENT_NOT_GIVEN.equals(e.errcode)) { + hideWaitingView(); + getConsentNotGivenHelper().displayDialog(e); + } else { + onError(e.getLocalizedMessage()); + } + } - String signUrl = null; + @Override + public void onUnexpectedError(Exception e) { + onError(e.getLocalizedMessage()); + } + }); + } + }); - if (null != roomEmailInvitation) { - signUrl = roomEmailInvitation.signUrl; + } else { + if ((null != roomEmailInvitation) && !TextUtils.isEmpty(roomEmailInvitation.email)) { + invitationTextView.setText(getString(R.string.room_preview_invitation_format, roomEmailInvitation.inviterName)); + subInvitationTextView.setText(getString(R.string.room_preview_unlinked_email_warning, roomEmailInvitation.email)); + } else { + invitationTextView.setText(getString(R.string.room_preview_try_join_an_unknown_room, + TextUtils.isEmpty(sRoomPreviewData.getRoomName()) ? getString(R.string.room_preview_try_join_an_unknown_room_default) : roomName)); + + // the room preview has some messages + if ((null != sRoomPreviewData.getRoomResponse()) && (null != sRoomPreviewData.getRoomResponse().messages)) { + subInvitationTextView.setText(getString(R.string.room_preview_room_interactions_disabled)); } + } - showWaitingView(); + declineButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d(LOG_TAG, "The invitation is declined (unknown room)"); - room.joinWithThirdPartySigned(sRoomPreviewData.getSession(), sRoomPreviewData.getRoomIdOrAlias(), signUrl, new ApiCallback() { - @Override - public void onSuccess(Void info) { - onJoined(); - } + sRoomPreviewData = null; + finish(); + } + }); + } - private void onError(String errorMessage) { - Toast.makeText(VectorRoomActivity.this, errorMessage, Toast.LENGTH_SHORT).show(); - hideWaitingView(); - } + joinButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d(LOG_TAG, "The user clicked on Join."); - @Override - public void onNetworkError(Exception e) { - onError(e.getLocalizedMessage()); + if (null != sRoomPreviewData) { + Room room = sRoomPreviewData.getSession().getDataHandler().getRoom(sRoomPreviewData.getRoomId()); + + String signUrl = null; + + if (null != roomEmailInvitation) { + signUrl = roomEmailInvitation.signUrl; } - @Override - public void onMatrixError(MatrixError e) { - if (MatrixError.M_CONSENT_NOT_GIVEN.equals(e.errcode)) { + showWaitingView(); + + room.joinWithThirdPartySigned(sRoomPreviewData.getSession(), sRoomPreviewData.getRoomIdOrAlias(), signUrl, new ApiCallback() { + @Override + public void onSuccess(Void info) { + onJoined(); + } + + private void onError(String errorMessage) { + Toast.makeText(VectorRoomActivity.this, errorMessage, Toast.LENGTH_SHORT).show(); hideWaitingView(); - getConsentNotGivenHelper().displayDialog(e); - } else { + } + + @Override + public void onNetworkError(Exception e) { onError(e.getLocalizedMessage()); } - } - @Override - public void onUnexpectedError(Exception e) { - onError(e.getLocalizedMessage()); - } - }); - } else { - finish(); + @Override + public void onMatrixError(MatrixError e) { + if (MatrixError.M_CONSENT_NOT_GIVEN.equals(e.errcode)) { + hideWaitingView(); + getConsentNotGivenHelper().displayDialog(e); + } else { + onError(e.getLocalizedMessage()); + } + } + + @Override + public void onUnexpectedError(Exception e) { + onError(e.getLocalizedMessage()); + } + }); + } else { + finish(); + } } - } - }); + }); - enableActionBarHeader(SHOW_ACTION_BAR_HEADER); + enableActionBarHeader(SHOW_ACTION_BAR_HEADER); + } } else { mRoomPreviewLayout.setVisibility(View.GONE); + } } @@ -3726,6 +4201,7 @@ public void onUnexpectedError(Exception e) { * Assume he wants to update it. */ private void onRoomTopicClick() { + if (mRoom == null) { return; } @@ -3882,6 +4358,7 @@ void onEditTextClick() { private void chooseMediaSource(boolean useNativeCamera, boolean isVoiceFeatureEnabled) { // hide the header room + enableActionBarHeader(HIDE_ACTION_BAR_HEADER); final List items = new ArrayList<>(); @@ -3918,6 +4395,7 @@ public void onClick(DialogInterface dialog, int which) { .show(); } + @OnClick(R.id.room_send_image_view) void onSendClick() { if (!TextUtils.isEmpty(mEditText.getText()) && !PreferencesManager.sendMessageWithEnter(this)) { @@ -3975,6 +4453,7 @@ boolean onLongClick() { } private void onSendChoiceClicked(DialogListItem dialogListItem) { + if (dialogListItem instanceof DialogListItem.SendFile) { launchFileSelectionIntent(); } else if (dialogListItem instanceof DialogListItem.SendVoice) { diff --git a/vector/src/main/java/im/vector/activity/VectorRoomCreationActivity.java b/vector/src/main/java/im/vector/activity/VectorRoomCreationActivity.java index a6a0d9553d..ca3eab8e89 100755 --- a/vector/src/main/java/im/vector/activity/VectorRoomCreationActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorRoomCreationActivity.java @@ -19,6 +19,7 @@ package im.vector.activity; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.text.TextUtils; @@ -34,6 +35,7 @@ import org.matrix.androidsdk.core.callback.ApiCallback; import org.matrix.androidsdk.core.callback.SimpleApiCallback; import org.matrix.androidsdk.core.model.MatrixError; +import org.matrix.androidsdk.crypto.CryptoConstantsKt; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.features.identityserver.IdentityServerNotConfiguredException; @@ -51,6 +53,7 @@ import im.vector.adapters.ParticipantAdapterItem; import im.vector.adapters.VectorRoomCreationAdapter; import kotlin.Pair; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; public class VectorRoomCreationActivity extends MXCActionBarActivity { // tags @@ -119,6 +122,11 @@ public void onUnexpectedError(final Exception e) { // displayed participants private List mParticipants = new ArrayList<>(); + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_vector_room_creation; @@ -326,7 +334,7 @@ public void onSuccess(String existingRoomId) { } else { // direct message flow showWaitingView(); - mSession.createDirectMessageRoom(otherUserId, mCreateDirectMessageCallBack); + mSession.createDirectMessageRoom(otherUserId, CryptoConstantsKt.MXCRYPTO_ALGORITHM_MEGOLM, mCreateDirectMessageCallBack); } } diff --git a/vector/src/main/java/im/vector/activity/VectorRoomDetailsActivity.java b/vector/src/main/java/im/vector/activity/VectorRoomDetailsActivity.java index 8553118c82..8690aafec5 100755 --- a/vector/src/main/java/im/vector/activity/VectorRoomDetailsActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorRoomDetailsActivity.java @@ -18,6 +18,7 @@ package im.vector.activity; import android.Manifest; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; @@ -43,6 +44,7 @@ import im.vector.fragments.VectorRoomSettingsFragment; import im.vector.fragments.VectorSearchRoomFilesListFragment; import im.vector.util.PermissionsToolsKt; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * This class implements the room details screen, using a tab UI pattern. @@ -103,6 +105,11 @@ public void run() { } }; + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_vector_room_details; diff --git a/vector/src/main/java/im/vector/activity/VectorRoomInviteMembersActivity.java b/vector/src/main/java/im/vector/activity/VectorRoomInviteMembersActivity.java index 0d28e1519b..85bd750919 100755 --- a/vector/src/main/java/im/vector/activity/VectorRoomInviteMembersActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorRoomInviteMembersActivity.java @@ -18,6 +18,7 @@ package im.vector.activity; import android.app.Activity; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; @@ -31,7 +32,9 @@ import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; +import androidx.lifecycle.ViewModelProviders; +import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.core.Log; import org.matrix.androidsdk.core.MXPatterns; import org.matrix.androidsdk.core.callback.SimpleApiCallback; @@ -57,10 +60,15 @@ import im.vector.adapters.VectorParticipantsAdapter; import im.vector.contacts.Contact; import im.vector.contacts.ContactsManager; +import im.vector.fragments.terms.AcceptTermsFragment; +import im.vector.fragments.terms.AcceptTermsViewModel; +import im.vector.fragments.terms.ServiceTermsArgs; import im.vector.util.PermissionsToolsKt; import im.vector.util.VectorUtils; import im.vector.view.VectorAutoCompleteTextView; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; +import static android.provider.DocumentsContract.EXTRA_INFO; /** * This class provides a way to search other user to invite them in a dedicated room */ @@ -85,6 +93,8 @@ public class VectorRoomInviteMembersActivity extends VectorBaseSearchActivity { // account data private String mMatrixId; + private VectorRoomInviteMembersActivity activity; + // main UI items @BindView(R.id.room_details_members_list) ExpandableListView mListView; @@ -126,9 +136,29 @@ public void run() { @Override public void onIdentityServerTermsNotSigned(String token) { - startActivityForResult(ReviewTermsActivity.Companion.intent(VectorRoomInviteMembersActivity.this, - TermsManager.ServiceType.IdentityService, mSession.getIdentityServerManager().getIdentityServerUrl() /* cannot be null */, token), - RequestCodesKt.TERMS_REQUEST_CODE); + try { + // Trying to accept terms on user's behalf without showing the dialog! + Log.v("Terms accepted: ", "running my own code"); + AcceptTermsViewModel viewModel = ViewModelProviders.of(activity).get(AcceptTermsViewModel.class); + Intent intent = new Intent(); + intent.putExtra(EXTRA_INFO, new ServiceTermsArgs(TermsManager.ServiceType.IdentityService, mSession.getIdentityServerManager().getIdentityServerUrl() /* Cannot be null */, token)); + viewModel.termsArgs = intent.getParcelableExtra(EXTRA_INFO); + MXSession session; + String matrixId = null; + if (intent.hasExtra(EXTRA_MATRIX_ID)) { + matrixId = intent.getStringExtra(EXTRA_MATRIX_ID); + } + session = Matrix.getInstance(getApplicationContext()).getSession(matrixId); + viewModel.initSession(session); + AcceptTermsFragment acceptTermsFragment = new AcceptTermsFragment(); + acceptTermsFragment.initialize(activity); + onActivityResult(RequestCodesKt.TERMS_REQUEST_CODE, Activity.RESULT_OK, null); + } catch (Exception e) { + Log.e("Error in ", "onIdentityServerTermsNotSigned-- " + e.getMessage()); + startActivityForResult(ReviewTermsActivity.Companion.intent(VectorRoomInviteMembersActivity.this, + TermsManager.ServiceType.IdentityService, mSession.getIdentityServerManager().getIdentityServerUrl() /* cannot be null */, token), + RequestCodesKt.TERMS_REQUEST_CODE); + } } @Override @@ -167,6 +197,11 @@ public void run() { } }; + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_vector_invite_members; @@ -175,7 +210,7 @@ public int getLayoutRes() { @Override public void initUiAndData() { super.initUiAndData(); - + activity = this; if (CommonActivityUtils.shouldRestartApp(this)) { Log.e(LOG_TAG, "Restart the application."); CommonActivityUtils.restartApp(this); @@ -308,6 +343,12 @@ protected void onPatternUpdate(boolean isTypingUpdate) { return; } + // By default the user will see all Matrix users, but if she enters anything, the program will search for that value + // if (pattern.isEmpty()) { + // // saba is part of every username in our server (in the domain part), so searching for + // // it shows all users in our home server + // pattern = "saba"; + //} mAdapter.setSearchedPattern(pattern, null, new VectorParticipantsAdapter.OnParticipantsSearchListener() { @Override public void onSearchEnd(final int count) { @@ -326,6 +367,8 @@ public void run() { }); } + + /** * Display a selection confirmation dialog. * diff --git a/vector/src/main/java/im/vector/activity/VectorSharedFilesActivity.java b/vector/src/main/java/im/vector/activity/VectorSharedFilesActivity.java index d152024460..4eeb5cd512 100644 --- a/vector/src/main/java/im/vector/activity/VectorSharedFilesActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorSharedFilesActivity.java @@ -17,6 +17,7 @@ package im.vector.activity; +import android.content.Context; import android.content.Intent; import org.matrix.androidsdk.MXSession; @@ -30,11 +31,18 @@ import im.vector.Matrix; import im.vector.R; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * Dummy activity used to manage the shared */ public class VectorSharedFilesActivity extends VectorAppCompatActivity { + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + private static final String LOG_TAG = VectorSharedFilesActivity.class.getSimpleName(); private final String SHARED_FOLDER = "VectorShared"; diff --git a/vector/src/main/java/im/vector/activity/VectorUnifiedSearchActivity.java b/vector/src/main/java/im/vector/activity/VectorUnifiedSearchActivity.java index d6d7cee5c5..fc299d9d19 100644 --- a/vector/src/main/java/im/vector/activity/VectorUnifiedSearchActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorUnifiedSearchActivity.java @@ -18,6 +18,7 @@ package im.vector.activity; import android.annotation.SuppressLint; +import android.content.Context; import android.content.pm.PackageManager; import android.os.Bundle; import android.text.TextUtils; @@ -40,6 +41,7 @@ import im.vector.adapters.VectorUnifiedSearchFragmentPagerAdapter; import im.vector.contacts.ContactsManager; import im.vector.util.PermissionsToolsKt; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * Displays a generic activity search method @@ -73,6 +75,11 @@ public class VectorUnifiedSearchActivity extends VectorBaseSearchActivity implem private int mPosition; + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { return R.layout.activity_vector_unified_search; diff --git a/vector/src/main/java/im/vector/activity/VectorUniversalLinkActivity.java b/vector/src/main/java/im/vector/activity/VectorUniversalLinkActivity.java index f00f20067d..0bf758bab6 100644 --- a/vector/src/main/java/im/vector/activity/VectorUniversalLinkActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorUniversalLinkActivity.java @@ -44,6 +44,7 @@ import im.vector.receiver.LoginConfig; import im.vector.receiver.VectorRegistrationReceiver; import im.vector.receiver.VectorUniversalLinkReceiver; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; /** * Dummy activity used to dispatch the vector URL links. @@ -54,6 +55,11 @@ public class VectorUniversalLinkActivity extends VectorAppCompatActivity { private static final String SUPPORTED_PATH_CONFIG = "/config/config"; + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + @Override public int getLayoutRes() { // display a spinner while binding the email diff --git a/vector/src/main/java/im/vector/adapters/RoomAdapter.java b/vector/src/main/java/im/vector/adapters/RoomAdapter.java index 04ea702a2b..e9a5c72a60 100644 --- a/vector/src/main/java/im/vector/adapters/RoomAdapter.java +++ b/vector/src/main/java/im/vector/adapters/RoomAdapter.java @@ -81,7 +81,7 @@ public RoomAdapter(final Context context, mPublicRoomsSection.setEmptyViewPlaceholder(context.getString(R.string.no_public_room_placeholder), context.getString(R.string.no_result_placeholder)); addSection(mRoomsSection); - addSection(mPublicRoomsSection); + // addSection(mPublicRoomsSection); } /* @@ -265,5 +265,7 @@ public interface OnSelectItemListener { void onSelectItem(Room item, int position); void onSelectItem(PublicRoom publicRoom); + + void onSelectItem(ParticipantAdapterItem contact, int position); } } diff --git a/vector/src/main/java/im/vector/adapters/SabaPeopleAdapter.java b/vector/src/main/java/im/vector/adapters/SabaPeopleAdapter.java new file mode 100644 index 0000000000..51b14b5848 --- /dev/null +++ b/vector/src/main/java/im/vector/adapters/SabaPeopleAdapter.java @@ -0,0 +1,451 @@ +/* + * Copyright 2017 Vector Creations Ltd + * Copyright 2018 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.adapters; + +import android.content.Context; +import android.graphics.Color; +//import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.util.Pair; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +//import org.matrix.androidsdk.MXPatterns; +import org.matrix.androidsdk.core.Log; +import org.matrix.androidsdk.core.MXPatterns; +import org.matrix.androidsdk.core.callback.SimpleApiCallback; +import org.matrix.androidsdk.data.Room; +//import org.matrix.androidsdk.rest.callback.SimpleApiCallback; +import org.matrix.androidsdk.rest.model.User; +//import org.matrix.androidsdk.util.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import im.vector.R; +import im.vector.contacts.ContactsManager; +import im.vector.settings.VectorLocale; +import im.vector.util.RoomUtils; +import im.vector.util.VectorUtils; + +public class SabaPeopleAdapter extends AbsAdapter { + + private static final String LOG_TAG = PeopleAdapter.class.getSimpleName(); + + private static final int TYPE_HEADER_LOCAL_CONTACTS = 0; + + private static final int TYPE_CONTACT = 1; + + private AdapterSection mDirectChatsSection; + private AdapterSection mLocalContactsSection; + private KnownContactsAdapterSection mKnownContactsSection; + + private OnSelectItemListener mListener; + + private String mNoContactAccessPlaceholder; + private String mNoResultPlaceholder; + + + + /* + * ********************************************************************************************* + * Constructor + * ********************************************************************************************* + */ + + public SabaPeopleAdapter(final Context context, + final OnSelectItemListener listener, + final RoomInvitationListener invitationListener, + final MoreRoomActionListener moreActionListener) { + super(context, invitationListener, moreActionListener); + mListener = listener; + + // ButterKnife.bind(this); cannot be applied here + mNoContactAccessPlaceholder = context.getString(R.string.no_contact_access_placeholder); + mNoResultPlaceholder = context.getString(R.string.no_result_placeholder); + + mDirectChatsSection = new AdapterSection<>(context, + context.getString(R.string.direct_chats_header), + -1, + R.layout.adapter_item_room_view, + TYPE_HEADER_DEFAULT, + TYPE_ROOM, + new ArrayList(), + RoomUtils.getRoomsDateComparator(mSession, false)); + mDirectChatsSection.setEmptyViewPlaceholder(context.getString(R.string.no_conversation_placeholder), context.getString(R.string.no_result_placeholder)); + + mLocalContactsSection = new AdapterSection<>(context, + context.getString(R.string.local_address_book_header), + R.layout.adapter_local_contacts_sticky_header_subview, + R.layout.adapter_item_contact_view, + TYPE_HEADER_LOCAL_CONTACTS, TYPE_CONTACT, + new ArrayList(), + ParticipantAdapterItem.alphaComparator); + mLocalContactsSection.setEmptyViewPlaceholder(!ContactsManager.getInstance().isContactBookAccessAllowed() ? + mNoContactAccessPlaceholder : mNoResultPlaceholder); + + mKnownContactsSection = new KnownContactsAdapterSection(context, context.getString(R.string.user_directory_header), -1, + R.layout.adapter_item_contact_view, TYPE_HEADER_DEFAULT, TYPE_CONTACT, new ArrayList(), null); + mKnownContactsSection.setEmptyViewPlaceholder(null, context.getString(R.string.no_result_placeholder)); + mKnownContactsSection.setIsHiddenWhenNoFilter(true); + + addSection(mDirectChatsSection); +// addSection(mLocalContactsSection); +// addSection(mKnownContactsSection); + } + + SabaPeopleAdapter(Context context, RoomInvitationListener invitationListener, MoreRoomActionListener moreActionListener) { + super(context, invitationListener, moreActionListener); + } + + // these followings are for roomAdapter + + + + + /* + * ********************************************************************************************* + * Abstract methods implementation + * ********************************************************************************************* + */ + + @Override + protected RecyclerView.ViewHolder createSubViewHolder(ViewGroup viewGroup, int viewType) { + final LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext()); + + View itemView; + + if (viewType == TYPE_HEADER_LOCAL_CONTACTS) { + //TODO replace by a empty view ? + itemView = inflater.inflate(R.layout.adapter_section_header_local, viewGroup, false); + itemView.setBackgroundColor(Color.MAGENTA); + return new HeaderViewHolder(itemView); + } else { + switch (viewType) { + case TYPE_ROOM: + itemView = inflater.inflate(R.layout.adapter_item_room_view, viewGroup, false); + return new RoomViewHolder(itemView); + case TYPE_CONTACT: + itemView = inflater.inflate(R.layout.adapter_item_contact_view, viewGroup, false); + return new ContactViewHolder(itemView); + } + } + return null; + } + + @Override + protected void populateViewHolder(int viewType, RecyclerView.ViewHolder viewHolder, int position) { + switch (viewType) { + case TYPE_HEADER_LOCAL_CONTACTS: + // Local header + final HeaderViewHolder headerViewHolder = (HeaderViewHolder) viewHolder; + for (Pair adapterSection : getSectionsArray()) { + if (adapterSection.first == position) { + headerViewHolder.populateViews(adapterSection.second); + break; + } + } + break; + case TYPE_ROOM: + final RoomViewHolder roomViewHolder = (RoomViewHolder) viewHolder; + final Room room = (Room) getItemForPosition(position); + roomViewHolder.populateViews(mContext, mSession, room, true, false, mMoreRoomActionListener); + roomViewHolder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mListener.onSelectItem(room, -1); + } + }); + break; + case TYPE_CONTACT: + final ContactViewHolder contactViewHolder = (ContactViewHolder) viewHolder; + final ParticipantAdapterItem item = (ParticipantAdapterItem) getItemForPosition(position); + contactViewHolder.populateViews(item, position); + break; + } + } + + @Override + protected int applyFilter(String pattern) { + int nbResults = 0; + nbResults += filterRoomSection(mDirectChatsSection, pattern); + nbResults += filterLocalContacts(pattern); + + // if there is no pattern, use the local search + if (TextUtils.isEmpty(pattern)) { + nbResults += filterKnownContacts(pattern); + } + return nbResults; + } + + /* + * ********************************************************************************************* + * Public methods + * ********************************************************************************************* + */ + + public void setRooms(final List rooms) { + mDirectChatsSection.setItems(rooms, mCurrentFilterPattern); + if (!TextUtils.isEmpty(mCurrentFilterPattern)) { + filterRoomSection(mDirectChatsSection, String.valueOf(mCurrentFilterPattern)); + } + updateSections(); + } + + public void setLocalContacts(final List localContacts) { + // updates the placeholder according to the local contacts permissions + mLocalContactsSection.setEmptyViewPlaceholder(!ContactsManager.getInstance().isContactBookAccessAllowed() ? + mNoContactAccessPlaceholder : mNoResultPlaceholder); + mLocalContactsSection.setItems(localContacts, mCurrentFilterPattern); + if (!TextUtils.isEmpty(mCurrentFilterPattern)) { + filterLocalContacts(String.valueOf(mCurrentFilterPattern)); + } + updateSections(); + } + + public void setKnownContacts(final List knownContacts) { + mKnownContactsSection.setItems(knownContacts, mCurrentFilterPattern); + if (!TextUtils.isEmpty(mCurrentFilterPattern)) { + filterKnownContacts(String.valueOf(mCurrentFilterPattern)); + } else { + filterKnownContacts(null); + } + updateSections(); + } + + public void setFilteredKnownContacts(List filteredKnownContacts, String pattern) { + Collections.sort(filteredKnownContacts, ParticipantAdapterItem.getComparator(mSession)); + mKnownContactsSection.setFilteredItems(filteredKnownContacts, pattern); + updateSections(); + } + + public void setKnownContactsLimited(boolean isLimited) { + mKnownContactsSection.setIsLimited(isLimited); + } + + public void setKnownContactsExtraTitle(String extraTitle) { + mKnownContactsSection.setCustomHeaderExtra(extraTitle); + } + + /** + * Update the known contact corresponding to the given user id + * + * @param user + */ + public void updateKnownContact(final User user) { + int headerPos = getSectionHeaderPosition(mKnownContactsSection) + 1; + List knownContacts = mKnownContactsSection.getFilteredItems(); + for (int i = 0; i < knownContacts.size(); i++) { + ParticipantAdapterItem item = knownContacts.get(i); + if (TextUtils.equals(user.user_id, item.mUserId)) { + notifyItemChanged(headerPos + i); + } + } + } + + /* + * ********************************************************************************************* + * Private methods + * ********************************************************************************************* + */ + + /** + * Filter the local contacts with the given pattern + * + * @param pattern + * @return nb of items matching the filter + */ + private int filterLocalContacts(final String pattern) { + if (!TextUtils.isEmpty(pattern)) { + List filteredLocalContacts = new ArrayList<>(); + final String formattedPattern = pattern.toLowerCase(VectorLocale.INSTANCE.getApplicationLocale()).trim(); + + List sectionItems = new ArrayList<>(mLocalContactsSection.getItems()); + for (final ParticipantAdapterItem item : sectionItems) { + if (item.startsWith(formattedPattern)) { + filteredLocalContacts.add(item); + } + } + mLocalContactsSection.setFilteredItems(filteredLocalContacts, pattern); + } else { + mLocalContactsSection.resetFilter(); + } + + return mLocalContactsSection.getFilteredItems().size(); + } + + /** + * Filter the known contacts known by this account. + * + * @param pattern the pattern to search + */ + public void filterAccountKnownContacts(final String pattern) { + filterKnownContacts(pattern); + updateSections(); + } + + /** + * Filter the known contacts with the given pattern + * + * @param pattern + * @return nb of items matching the filter + */ + private int filterKnownContacts(final String pattern) { + List filteredKnownContacts = new ArrayList<>(); + if (!TextUtils.isEmpty(pattern)) { + final String formattedPattern = pattern.trim().toLowerCase(VectorLocale.INSTANCE.getApplicationLocale()); + List sectionItems = new ArrayList<>(mKnownContactsSection.getItems()); + for (final ParticipantAdapterItem item : sectionItems) { + if (item.startsWith(formattedPattern)) { + filteredKnownContacts.add(item); + } + } + + } + + // The sort is done in the adapter to save loading time + // see PeopleFragment.initKnownContacts + Collections.sort(filteredKnownContacts, ParticipantAdapterItem.getComparator(mSession)); + mKnownContactsSection.setFilteredItems(filteredKnownContacts, pattern); + + setKnownContactsLimited(false); + setKnownContactsExtraTitle(null); + + return filteredKnownContacts.size(); + } + + /** + * Remove the room of the given id from the adapter + * + * @param roomId + */ + public void removeDirectChat(final String roomId) { + Room room = mSession.getDataHandler().getRoom(roomId); + if (mDirectChatsSection.removeItem(room)) { + updateSections(); + } + } + + /* + * ********************************************************************************************* + * View holder + * ********************************************************************************************* + */ + + class ContactViewHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.adapter_item_contact_avatar) + ImageView vContactAvatar; + + @BindView(R.id.contact_badge) + ImageView vContactBadge; + + @BindView(R.id.contact_name) + TextView vContactName; + + @BindView(R.id.contact_desc) + TextView vContactDesc; + + private ContactViewHolder(final View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + + private void populateViews(final ParticipantAdapterItem participant, final int position) { + if (null == participant) { + Log.e(LOG_TAG, "## populateViews() : null participant"); + return; + } + + if (position >= getItemCount()) { + Log.e(LOG_TAG, "## populateViews() : position out of bound " + position + " / " + getItemCount()); + return; + } + + participant.displayAvatar(mSession, vContactAvatar); + vContactName.setText(participant.getUniqueDisplayName(null)); + + /* + * Get the description to be displayed below the name + * For local contact, it is the medium (email, phone number) + * For other contacts, it is the presence + */ + if (participant.mContact != null) { + boolean isMatrixUserId = MXPatterns.isUserId(participant.mUserId); + vContactBadge.setVisibility(isMatrixUserId ? View.VISIBLE : View.GONE); + + if (participant.mContact.getEmails().size() > 0) { + vContactDesc.setText(participant.mContact.getEmails().get(0)); + } else { + vContactDesc.setText(participant.mContact.getPhonenumbers().get(0).mRawPhoneNumber); + } + } else { + loadContactPresence(vContactDesc, participant, position); + vContactBadge.setVisibility(View.GONE); + } + + itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mListener.onSelectItem(participant, -1); + } + }); + } + + /** + * Get the presence for the given contact + * + * @param textView + * @param item + * @param position + */ + private void loadContactPresence(final TextView textView, final ParticipantAdapterItem item, + final int position) { + final String presence = VectorUtils.getUserOnlineStatus(mContext, mSession, item.mUserId, new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + if (textView != null) { + textView.setText(VectorUtils.getUserOnlineStatus(mContext, mSession, item.mUserId, null)); + notifyItemChanged(position); + } + } + }); + textView.setText(presence); + } + } + + /* + * ********************************************************************************************* + * Inner classes + * ********************************************************************************************* + */ + + public interface OnSelectItemListener { + void onSelectItem(Room item, int position); + + void onSelectItem(ParticipantAdapterItem item, int position); + } +} diff --git a/vector/src/main/java/im/vector/adapters/VectorMediaViewerAdapter.java b/vector/src/main/java/im/vector/adapters/VectorMediaViewerAdapter.java index 489b02f583..95be5b9971 100755 --- a/vector/src/main/java/im/vector/adapters/VectorMediaViewerAdapter.java +++ b/vector/src/main/java/im/vector/adapters/VectorMediaViewerAdapter.java @@ -28,6 +28,8 @@ import android.view.ViewGroup; import android.webkit.MimeTypeMap; import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.MediaController; import android.widget.Toast; import android.widget.VideoView; @@ -54,6 +56,7 @@ import java.util.ArrayList; import java.util.List; +import im.vector.BuildConfig; import im.vector.R; import im.vector.util.SlidableMediaInfo; import im.vector.view.PieFractionView; @@ -87,6 +90,7 @@ public class VectorMediaViewerAdapter extends PagerAdapter { private VideoView mPlayingVideoView = null; private int mAutoPlayItemAt = -1; + private MediaController mediaController; public VectorMediaViewerAdapter(Context context, MXSession session, @@ -542,60 +546,125 @@ public void stopPlayingVideo() { * @param videoMimeType the video mime type */ private void playVideo(View pageView, VideoView videoView, File videoFile, String videoMimeType) { + if ((null != videoFile) && videoFile.exists()) { try { - stopPlayingVideo(); - String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(videoMimeType); + if (!(videoView.getCurrentPosition() > 0)) { - if (null != extension) { - extension += "." + extension; - } + stopPlayingVideo(); + String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(videoMimeType); - // copy the media to ensure that it is deleted while playing - File dstFile = new File(mContext.getCacheDir(), "sliderMedia" + extension); - if (dstFile.exists()) { - dstFile.delete(); - } + if (null != extension) { + extension += "." + extension; + } - // Copy source file to destination - FileInputStream inputStream = null; - FileOutputStream outputStream = null; - try { - // create only the - if (!dstFile.exists()) { - dstFile.createNewFile(); - - inputStream = new FileInputStream(videoFile); - outputStream = new FileOutputStream(dstFile); - - byte[] buffer = new byte[1024 * 10]; - int len; - while ((len = inputStream.read(buffer)) != -1) { - outputStream.write(buffer, 0, len); - } + // copy the media to ensure that it is deleted while playing + File dstFile = new File(mContext.getCacheDir(), "sliderMedia" + extension); + if (dstFile.exists()) { + dstFile.delete(); } - } catch (Exception e) { - Log.e(LOG_TAG, "## playVideo() : failed " + e.getMessage(), e); - dstFile = null; - } finally { - // Close resources + + // Copy source file to destination + FileInputStream inputStream = null; + FileOutputStream outputStream = null; try { - if (inputStream != null) inputStream.close(); - if (outputStream != null) outputStream.close(); + // create only the + if (!dstFile.exists()) { + dstFile.createNewFile(); + + inputStream = new FileInputStream(videoFile); + outputStream = new FileOutputStream(dstFile); + + byte[] buffer = new byte[1024 * 10]; + int len; + while ((len = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, len); + } + } } catch (Exception e) { Log.e(LOG_TAG, "## playVideo() : failed " + e.getMessage(), e); + dstFile = null; + } finally { + // Close resources + try { + if (inputStream != null) inputStream.close(); + if (outputStream != null) outputStream.close(); + } catch (Exception e) { + Log.e(LOG_TAG, "## playVideo() : failed " + e.getMessage(), e); + } } - } - // update the source - videoView.setVideoPath(dstFile.getAbsolutePath()); - // hide the thumbnail - displayVideoThumbnail(pageView, false); + // update the source + videoView.setVideoPath(dstFile.getAbsolutePath()); + // hide the thumbnail + displayVideoThumbnail(pageView, false); + + + // let's playing + mPlayingVideoView = videoView; + - // let's playing - mPlayingVideoView = videoView; - videoView.start(); + /** + * BATNA ===> set media controller when start video view + */ + if (BuildConfig.IS_SABA) { + mediaController = new MediaController(mContext, false) { + @Override + public void show() { + super.show(); + if (videoView.isPlaying()) { + pageView.findViewById(R.id.media_slider_video_play).setVisibility(View.GONE); + pageView.findViewById(R.id.media_slider_video_pause).setVisibility(View.VISIBLE); + + pageView.findViewById(R.id.media_slider_video_pause).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + videoView.pause(); + pageView.findViewById(R.id.media_slider_video_pause).setVisibility(View.GONE); + pageView.findViewById(R.id.media_slider_video_play).setVisibility(View.VISIBLE); + } + }); + } else { + if (videoView.getCurrentPosition() > 0) + pageView.findViewById(R.id.media_slider_video_play).setVisibility(View.VISIBLE); + else + pageView.findViewById(R.id.media_slider_video_pause).setVisibility(View.VISIBLE); + } + } + + @Override + public void hide() { + super.hide(); + pageView.findViewById(R.id.media_slider_video_pause).setVisibility(View.GONE); + pageView.findViewById(R.id.media_slider_video_play).setVisibility(View.GONE); + } + }; + + videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer pMp) { + LinearLayout viewGroupLevel1 = (LinearLayout) mediaController.getChildAt(0); + LinearLayout viewGroupLevel2 = (LinearLayout) viewGroupLevel1.getChildAt(0); + View view = viewGroupLevel2.getChildAt(2); + view.setVisibility(View.GONE); + mediaController.show(); + } + }); + videoView.setMediaController(mediaController); + mediaController.setMediaPlayer(videoView); + videoView.requestFocus(); + } + videoView.start(); + } else { + if (pageView.findViewById(R.id.media_slider_video_play).getVisibility() == View.VISIBLE) { + pageView.findViewById(R.id.media_slider_video_play).setVisibility(View.GONE); + pageView.findViewById(R.id.media_slider_video_pause).setVisibility(View.VISIBLE); + videoView.seekTo(videoView.getCurrentPosition()); + videoView.start(); + } + + } } catch (Exception e) { Log.e(LOG_TAG, "## playVideo() : videoView.start(); failed " + e.getMessage(), e); } @@ -634,8 +703,19 @@ public void onCompletion(MediaPlayer mp) { ((View) videoView.getParent()).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - stopPlayingVideo(); - displayVideoThumbnail(view, true); + if (!videoView.isPlaying()) { + if (videoView.getCurrentPosition() > 0) { +// videoView.seekTo(videoView.getCurrentPosition()); +// videoView.start(); + } else { + stopPlayingVideo(); + displayVideoThumbnail(view, true); + } + } else if (videoView.canPause()) { +// + } else { +// + } } }); diff --git a/vector/src/main/java/im/vector/adapters/VectorMessagesAdapter.java b/vector/src/main/java/im/vector/adapters/VectorMessagesAdapter.java index 25932139d8..7726cb8106 100755 --- a/vector/src/main/java/im/vector/adapters/VectorMessagesAdapter.java +++ b/vector/src/main/java/im/vector/adapters/VectorMessagesAdapter.java @@ -24,6 +24,7 @@ import android.graphics.Point; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.media.MediaPlayer; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -50,6 +51,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupMenu; +import android.widget.ProgressBar; import android.widget.TextView; import androidx.annotation.Nullable; @@ -82,6 +84,7 @@ import org.matrix.androidsdk.rest.model.message.StickerMessage; import org.matrix.androidsdk.view.HtmlTagHandler; +import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.text.SimpleDateFormat; @@ -97,9 +100,12 @@ import java.util.Map; import java.util.Set; +import im.vector.BuildConfig; import im.vector.R; import im.vector.VectorApp; +import im.vector.activity.VectorRoomActivity; import im.vector.extensions.MatrixSdkExtensionsKt; +import im.vector.fragments.VectorMessageListFragment; import im.vector.listeners.IMessagesAdapterActionsListener; import im.vector.settings.VectorLocale; import im.vector.ui.VectorQuoteSpan; @@ -121,13 +127,18 @@ public class VectorMessagesAdapter extends AbstractMessagesAdapter { private static final String LOG_TAG = VectorMessagesAdapter.class.getSimpleName(); // an event is selected when the user taps on it - private Event mSelectedEvent; + public static Event mSelectedEvent; + private String fileName; // events listeners IMessagesAdapterActionsListener mVectorMessagesAdapterEventsListener = null; // current date : used to compute the day header private Date mReferenceDate = new Date(); + private static Handler myHandler = new Handler(); + private static boolean isRemainderVoice; + @SuppressLint("StaticFieldLeak") + private static ImageView vectorMessagesAdapterImageTypeView; // day date of each message // the hours, minutes and seconds are removed @@ -227,6 +238,9 @@ public class VectorMessagesAdapter extends AbstractMessagesAdapter { private final Drawable mPadlockDrawable; private VectorImageGetter mImageGetter; + private VectorRoomActivity vectorRoomActivity; + private VectorMessageListFragment vectorMessageListFragment; + private HtmlToolbox mHtmlToolbox = new HtmlToolbox() { HtmlTagHandler mHtmlTagHandler; @@ -270,6 +284,26 @@ public Html.TagHandler getTagHandler(String html) { /** * Creates a messages adapter with the default layouts. */ + public VectorMessagesAdapter(MXSession session, Context context, MXMediaCache mediasCache, VectorRoomActivity vectorRoomActivity, VectorMessageListFragment vectorMessageListFragment) { + this(session, context, + R.layout.adapter_item_vector_message_text_emote_notice, + R.layout.adapter_item_vector_message_image_video, + R.layout.adapter_item_vector_message_text_emote_notice, + R.layout.adapter_item_vector_message_room_member, + R.layout.adapter_item_vector_message_text_emote_notice, + R.layout.adapter_item_vector_message_file, + R.layout.adapter_item_vector_message_merge, + R.layout.adapter_item_vector_message_image_video, + R.layout.adapter_item_vector_message_emoji, + R.layout.adapter_item_vector_message_code, + R.layout.adapter_item_vector_message_image_video, + R.layout.adapter_item_vector_message_redact, + R.layout.adapter_item_vector_message_room_versioned, + mediasCache); + this.vectorRoomActivity = vectorRoomActivity; + this.vectorMessageListFragment = vectorMessageListFragment; + } + public VectorMessagesAdapter(MXSession session, Context context, MXMediaCache mediasCache) { this(session, context, R.layout.adapter_item_vector_message_text_emote_notice, @@ -286,6 +320,7 @@ public VectorMessagesAdapter(MXSession session, Context context, MXMediaCache me R.layout.adapter_item_vector_message_redact, R.layout.adapter_item_vector_message_room_versioned, mediasCache); + } /** @@ -1149,15 +1184,53 @@ public boolean onLongClick(View v) { if (row.getEvent().isUndelivered() || row.getEvent().isUnknownDevice()) { tsTextView.setTextColor(mNotSentMessageTextColor); } else { - tsTextView.setTextColor(ThemeUtils.INSTANCE.getColor(mContext, android.R.attr.textColorSecondary)); + /** + * BATNA ==> change text color + */ + tsTextView.setTextColor(Color.BLACK); + } - tsTextView.setVisibility((((position + 1) == getCount()) || mIsSearchMode || mAlwaysShowTimeStamps) ? View.VISIBLE : View.GONE); + tsTextView.setTextColor(Color.BLACK); + } // Sender avatar View avatarView = mHelper.setSenderAvatar(convertView, row, isMergedView); + /** + * BATNA ==> (Esmaeeil Moradi) change LayoutDirection messagesAdapter_body_view + */ + + if (BuildConfig.IS_SABA) { + final String userId = event.getSender(); + if (userId.equals(mSession.getMyUserId())) { + try { + convertView.findViewById(R.id.messagesAdapter_body_view).setLayoutDirection(View.LAYOUT_DIRECTION_RTL); + if ((ROW_TYPE_IMAGE != msgType) && (ROW_TYPE_FILE != msgType) && (ROW_TYPE_VIDEO != msgType) && (ROW_TYPE_STICKER != msgType)) { + convertView.findViewById(R.id.messagesAdapter_text_layout).setBackground(ContextCompat.getDrawable(mContext, R.drawable.out_message_shape)); + } else { + convertView.findViewById(R.id.layout_item_vector_message).setBackground(ContextCompat.getDrawable(mContext, R.drawable.out_message_shape)); + } + } catch (Exception e) { + e.printStackTrace(); + } + + } else { + try { + convertView.findViewById(R.id.messagesAdapter_body_view).setLayoutDirection(View.LAYOUT_DIRECTION_LTR); + if ((ROW_TYPE_IMAGE != msgType) && (ROW_TYPE_FILE != msgType) && (ROW_TYPE_VIDEO != msgType) && (ROW_TYPE_STICKER != msgType)) { + convertView.findViewById(R.id.messagesAdapter_text_layout).setBackground(ContextCompat.getDrawable(mContext, R.drawable.in_message_shape)); + } else { + convertView.findViewById(R.id.layout_item_vector_message).setBackground(ContextCompat.getDrawable(mContext, R.drawable.in_message_shape)); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + // if the messages are merged // the thumbnail is hidden // and the subview must be moved to be aligned with the previous body @@ -1254,6 +1327,13 @@ private View getTextView(final int viewType, final int position, View convertVie textColor = mNotSentMessageTextColor; } else { textColor = shouldHighlighted ? mHighlightMessageTextColor : mDefaultMessageTextColor; + /** + * Developed by BATNA (Esmaeeil Moradi) + */ + //change reply color in Group + if (BuildConfig.IS_SABA) { + textColor = Color.DKGRAY; + } } for (final TextView tv : textViews) { @@ -1551,6 +1631,14 @@ private View getEmoteView(final int position, View convertView, ViewGroup parent return convertView; } + public static void setRemainderVoice(boolean isRemainderVoice) { + VectorMessagesAdapter.isRemainderVoice = isRemainderVoice; + } + + public static ImageView getVectorMessagesAdapterImageTypeView() { + return vectorMessagesAdapterImageTypeView; + } + /** * File message management * @@ -1559,13 +1647,16 @@ private View getEmoteView(final int position, View convertView, ViewGroup parent * @param parent the parent view * @return the updated text view. */ + private View getFileView(final int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mLayoutInflater.inflate(mRowTypeToLayoutId.get(ROW_TYPE_FILE), parent, false); } try { + ProgressBar progressBar = convertView.findViewById(R.id.download_progressBar); MessageRow row = getItem(position); + assert row != null; Event event = row.getEvent(); final FileMessage fileMessage = JsonUtils.toFileMessage(event.getContent()); @@ -1582,26 +1673,147 @@ private View getFileView(final int position, View convertView, ViewGroup parent) // display the right message type icon. // Audio and File messages are managed by the same method final ImageView imageTypeView = convertView.findViewById(R.id.messagesAdapter_image_type); - if (null != imageTypeView) { imageTypeView.setImageResource(Message.MSGTYPE_AUDIO.equals(fileMessage.msgtype) ? R.drawable.filetype_audio : R.drawable.filetype_attachment); } - imageTypeView.setBackgroundColor(Color.TRANSPARENT); + + String filePath = VectorRoomActivity.voicePath + fileMessage.body; + File file = new File(filePath); + if (fileMessage.body.contains("3gp") || fileMessage.body.contains("mp3") || fileMessage.body.contains("aac")) { + if (file.exists()) { + assert imageTypeView != null; + imageTypeView.setImageResource(R.drawable.play); + } else if (!file.exists()) { + assert imageTypeView != null; + imageTypeView.setImageResource(R.drawable.ic_down_arrow); + } + if (file.exists() && progressBar.getVisibility() == View.VISIBLE) { + progressBar.setVisibility(View.GONE); + assert imageTypeView != null; + imageTypeView.setVisibility(View.VISIBLE); + notifyDataSetChanged(); + } + } + + + if (fileMessage.body.equalsIgnoreCase(fileName) && VectorRoomActivity.getMediaPlayer().isPlaying()) { + assert imageTypeView != null; + imageTypeView.setImageResource(R.drawable.pause); + if (vectorMessagesAdapterImageTypeView != null) { + vectorMessagesAdapterImageTypeView.setImageResource(R.drawable.pause); + } + } + + VectorRoomActivity.getMediaPlayer().setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + try { + if (imageTypeView != null) { + imageTypeView.setImageResource(R.drawable.play); + VectorRoomActivity.getLinearLayout().setVisibility(View.GONE); + notifyDataSetChanged(); + isRemainderVoice = false; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + assert imageTypeView != null; + imageTypeView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (fileMessage.body.contains("3gp") || fileMessage.body.contains("mp3") || fileMessage.body.contains("aac")) { + if (!file.exists()) { + File dir = new File(VectorRoomActivity.voicePath); + if (dir.isDirectory()) { + String[] voices = dir.list(); + for (String voice : voices) { + new File(dir, voice).delete(); + } + } + progressBar.setVisibility(View.VISIBLE); + imageTypeView.setVisibility(View.GONE); + VectorRoomActivity.getMediaPlayer().stop(); + VectorRoomActivity.getLinearLayout().setVisibility(View.GONE); + playBack(imageTypeView, position, fileMessage); + } else if (file.exists()) { +// progressBar.setVisibility(View.GONE); + playBack(imageTypeView, position, fileMessage); + } + } + } + }); + imageTypeView.setBackgroundColor(Color.TRANSPARENT); mMediasHelper.managePendingFileDownload(convertView, event, fileMessage, position); mMediasHelper.managePendingUpload(convertView, event, ROW_TYPE_FILE, fileMessage.url); - View fileLayout = convertView.findViewById(R.id.messagesAdapter_file_layout); manageSubView(position, convertView, fileLayout, ROW_TYPE_FILE); - addContentViewListeners(convertView, fileTextView, position, ROW_TYPE_FILE); } catch (Exception e) { Log.e(LOG_TAG, "## getFileView() failed " + e.getMessage(), e); } - return convertView; } + private void playBack(ImageView imageTypeView, int position, FileMessage fileMessage) { + vectorMessagesAdapterImageTypeView = imageTypeView; + + String filePath = VectorRoomActivity.voicePath + fileMessage.body; + File file = new File(filePath); + if (imageTypeView.getDrawable().getConstantState() == vectorRoomActivity.getResources().getDrawable(R.drawable.ic_down_arrow).getConstantState()) { + vectorMessageListFragment.onContentClick(position); + imageTypeView.setImageResource(R.drawable.play); + } + + if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { + vectorMessageListFragment.onContentClick(position); + imageTypeView.setImageResource(R.drawable.play); + } + + if (file.exists()) { + if (!VectorRoomActivity.getMediaPlayer().isPlaying() && !fileMessage.body.equalsIgnoreCase(fileName) || VectorRoomActivity.getLinearLayout().getVisibility() == View.GONE) { + if (VectorRoomActivity.getMediaPlayer().isPlaying() && VectorRoomActivity.getMediaPlayer().getCurrentPosition() <= 500) + return; + isRemainderVoice = true; + VectorRoomActivity.getPause().setVisibility(View.VISIBLE); + VectorRoomActivity.getPlay().setVisibility(View.GONE); + vectorRoomActivity.playBack(filePath, false); + imageTypeView.setImageResource(R.drawable.pause); + + notifyDataSetChanged(); + + } else if (!VectorRoomActivity.getMediaPlayer().isPlaying() && fileMessage.body.equalsIgnoreCase(fileName) && !(VectorRoomActivity.getLinearLayout().getVisibility() == View.GONE) + ) { + if (VectorRoomActivity.getMediaPlayer().isPlaying() && VectorRoomActivity.getMediaPlayer().getCurrentPosition() <= 500) + return; + VectorRoomActivity.getMediaPlayer().start(); + imageTypeView.setImageResource(R.drawable.pause); + VectorRoomActivity.getPause().setVisibility(View.VISIBLE); + VectorRoomActivity.getPlay().setVisibility(View.GONE); + notifyDataSetChanged(); + + } else if (VectorRoomActivity.getMediaPlayer().isPlaying() && fileMessage.body.equalsIgnoreCase(fileName)) { + VectorRoomActivity.getMediaPlayer().pause(); + VectorRoomActivity.getPause().setVisibility(View.GONE); + VectorRoomActivity.getPlay().setVisibility(View.VISIBLE); + imageTypeView.setImageResource(R.drawable.play); + notifyDataSetChanged(); + + } else if (VectorRoomActivity.getMediaPlayer().isPlaying() && !fileMessage.body.equalsIgnoreCase(fileName)) { + if (VectorRoomActivity.getMediaPlayer().isPlaying() && VectorRoomActivity.getMediaPlayer().getCurrentPosition() <= 500) + return; + vectorRoomActivity.playBack(filePath, false); + imageTypeView.setImageResource(R.drawable.play); + VectorRoomActivity.getPause().setVisibility(View.VISIBLE); + VectorRoomActivity.getPlay().setVisibility(View.GONE); + notifyDataSetChanged(); + } + } + fileName = fileMessage.body; + } + /** * Hidden message management. * @@ -2052,10 +2264,23 @@ private void addContentViewListeners(final View convertView, final View contentV contentView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + MessageRow row = getItem(position); + Event event = row.getEvent(); + final FileMessage fileMessage = JsonUtils.toFileMessage(event.getContent()); + if (null != mVectorMessagesAdapterEventsListener) { // GA issue if (position < getCount()) { - mVectorMessagesAdapterEventsListener.onContentClick(position); + try { + if (fileMessage.body.contains("3gp") || fileMessage.body.contains("mp3") || fileMessage.body.contains("aac")) { + final ImageView imageTypeView = convertView.findViewById(R.id.messagesAdapter_image_type); + vectorMessagesAdapterImageTypeView = imageTypeView; + fileName = fileMessage.body; + } + mVectorMessagesAdapterEventsListener.onContentClick(position); + } catch (Exception ignored) { + + } } } } @@ -2220,6 +2445,9 @@ private void manageCryptoEvents() { // oneself event if (event.mSentState != Event.SentState.SENT) { e2eIconByEventId.put(event.eventId, R.drawable.e2e_verified); + if (BuildConfig.IS_SABA) { + e2eIconByEventId.put(event.eventId, R.drawable.e2e_verified_batna); + } } // not encrypted event else if (!event.isEncrypted()) { @@ -2234,6 +2462,10 @@ else if (null != event.getCryptoError()) { if (TextUtils.equals(mSession.getCredentials().deviceId, encryptedEventContent.device_id) && TextUtils.equals(mSession.getMyUserId(), event.getSender())) { e2eIconByEventId.put(event.eventId, R.drawable.e2e_verified); + if (BuildConfig.IS_SABA) { + e2eIconByEventId.put(event.eventId, R.drawable.e2e_verified_batna); + } + MXDeviceInfo deviceInfo = mSession.getCrypto() .deviceWithIdentityKey(encryptedEventContent.sender_key, encryptedEventContent.algorithm); @@ -2249,6 +2481,9 @@ else if (null != event.getCryptoError()) { e2eDeviceInfoByEventId.put(event.eventId, deviceInfo); if (deviceInfo.isVerified()) { e2eIconByEventId.put(event.eventId, R.drawable.e2e_verified); + if (BuildConfig.IS_SABA) { + e2eIconByEventId.put(event.eventId, R.drawable.e2e_verified_batna); + } } else if (deviceInfo.isBlocked()) { e2eIconByEventId.put(event.eventId, R.drawable.e2e_blocked); } else { @@ -2511,10 +2746,11 @@ private void onMessageClick(final Event event, final String textMsg, final View for (int i = 0; i < menu.size(); i++) { menu.getItem(i).setVisible(false); } - - menu.findItem(R.id.ic_action_view_source).setVisible(true); - menu.findItem(R.id.ic_action_view_decrypted_source).setVisible(event.isEncrypted() && (null != event.getClearEvent())); - menu.findItem(R.id.ic_action_vector_permalink).setVisible(true); + menu.findItem(R.id.ic_action_vector_reply).setVisible(true); + menu.findItem(R.id.ic_action_view_source).setVisible(false); +// menu.findItem(R.id.ic_action_view_decrypted_source).setVisible(event.isEncrypted() && (null != event.getClearEvent())); + menu.findItem(R.id.ic_action_view_decrypted_source).setVisible(false); + menu.findItem(R.id.ic_action_vector_permalink).setVisible(false); if (!TextUtils.isEmpty(textMsg)) { menu.findItem(R.id.ic_action_vector_copy).setVisible(true); @@ -2589,7 +2825,7 @@ public boolean onMenuItemClick(final MenuItem item) { } // disable the selection - cancelSelectionMode(); +// cancelSelectionMode(); return true; } diff --git a/vector/src/main/java/im/vector/adapters/VectorMessagesAdapterHelper.java b/vector/src/main/java/im/vector/adapters/VectorMessagesAdapterHelper.java index 5aeea3216c..83bf5d0a22 100755 --- a/vector/src/main/java/im/vector/adapters/VectorMessagesAdapterHelper.java +++ b/vector/src/main/java/im/vector/adapters/VectorMessagesAdapterHelper.java @@ -75,6 +75,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import im.vector.BuildConfig; import im.vector.R; import im.vector.listeners.IMessagesAdapterActionsListener; import im.vector.settings.VectorLocale; @@ -182,8 +183,22 @@ public void setSenderValue(View convertView, MessageRow row, boolean isMergedVie || Event.EVENT_TYPE_MESSAGE_ENCRYPTION.equals(eventType)) { senderTextView.setVisibility(View.GONE); } else { - senderTextView.setVisibility(View.VISIBLE); - senderTextView.setText(row.getSenderDisplayName()); + /** + * BATNA ==> remove MyName from message + */ + if (BuildConfig.IS_SABA){ + + final String userId = event.getSender(); + if (userId.equals(mSession.getMyUserId())) { + senderTextView.setVisibility(View.GONE); + }else { + senderTextView.setVisibility(View.VISIBLE); + senderTextView.setText(row.getSenderDisplayName()); + } + }else { + senderTextView.setVisibility(View.VISIBLE); + senderTextView.setText(row.getSenderDisplayName()); + } final String fSenderId = event.getSender(); final String fDisplayName = (null == senderTextView.getText()) ? "" : senderTextView.getText().toString(); @@ -191,7 +206,12 @@ public void setSenderValue(View convertView, MessageRow row, boolean isMergedVie Context context = senderTextView.getContext(); int textColor = colorIndexForSender(fSenderId); senderTextView.setTextColor(context.getResources().getColor(textColor)); - + /** + * BATNA ==> (Esmaeeil Moradi ) change text color set static + */ + if (BuildConfig.IS_SABA) { + senderTextView.setTextColor(context.getResources().getColor(R.color.text_black)); + } senderTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -938,6 +958,15 @@ CharSequence highlightPattern(Spannable text, String pattern, CharacterStyle hig } SpannableStringBuilder strBuilder = new SpannableStringBuilder(text); + /** + * BATNA ==> (Esmaeeil Moradi) remove text 'In reply to' from SDK + */ + if (BuildConfig.IS_SABA) { + String totalText = strBuilder.toString(); + if (totalText.contains("In reply to")) { + strBuilder.replace(0, 11, ""); + } + } URLSpan[] urls = strBuilder.getSpans(0, text.length(), URLSpan.class); if ((null != urls) && (urls.length > 0)) { diff --git a/vector/src/main/java/im/vector/adapters/VectorMessagesAdapterMediasHelper.java b/vector/src/main/java/im/vector/adapters/VectorMessagesAdapterMediasHelper.java index 1e0530558f..03c4fd0d0c 100755 --- a/vector/src/main/java/im/vector/adapters/VectorMessagesAdapterMediasHelper.java +++ b/vector/src/main/java/im/vector/adapters/VectorMessagesAdapterMediasHelper.java @@ -56,6 +56,7 @@ import java.util.HashMap; import java.util.Map; +import im.vector.BuildConfig; import im.vector.R; import im.vector.listeners.IMessagesAdapterActionsListener; @@ -206,6 +207,16 @@ void managePendingImageVideoDownload(final View convertView, final Event event, // retrieve the common items if (message instanceof ImageMessage) { ImageMessage imageMessage = (ImageMessage) message; + /** + * BTNA ==>set text caption in ImageMessage + */ + if (BuildConfig.IS_SABA) { + final TextView txtCaption = convertView.findViewById(R.id.txt_batna_caption); + int index = imageMessage.body.indexOf("*") + 1; + StringBuffer buf = new StringBuffer(imageMessage.body); + txtCaption.setText(buf.replace(0, index, " ")); + } + imageMessage.checkMediaUrls(); // Backwards compatibility with events from before Synapse 0.6.0 @@ -236,7 +247,16 @@ void managePendingImageVideoDownload(final View convertView, final Event event, } } } else if (message instanceof VideoMessage) { - VideoMessage videoMessage = (VideoMessage) message; + VideoMessage videoMessage = (VideoMessage) message ; + /** + * BTNA ==>set text caption in VideoMessage + */ + if (BuildConfig.IS_SABA) { + final TextView txtCaption = convertView.findViewById(R.id.txt_batna_caption); + int index = videoMessage.body.indexOf("*") + 1; + StringBuffer buf = new StringBuffer(videoMessage.body); + txtCaption.setText(buf.replace(0, index, " ")); + } videoMessage.checkMediaUrls(); thumbUrl = videoMessage.getThumbnailUrl(); diff --git a/vector/src/main/java/im/vector/adapters/VectorParticipantsAdapter.java b/vector/src/main/java/im/vector/adapters/VectorParticipantsAdapter.java index c05a895965..dad60e19be 100755 --- a/vector/src/main/java/im/vector/adapters/VectorParticipantsAdapter.java +++ b/vector/src/main/java/im/vector/adapters/VectorParticipantsAdapter.java @@ -899,8 +899,16 @@ public View getGroupView(final int groupPosition, final boolean isExpanded, View matrixView.setVisibility(((groupPosition == mLocalContactsSectionPosition) && groupShouldBeExpanded) ? View.VISIBLE : View.GONE); // matrix user checkbox + // Saba Modification: the Default value which was initially set to "false", is passed as true CheckBox checkBox = convertView.findViewById(R.id.contacts_filter_checkbox); - checkBox.setChecked(PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean(KEY_FILTER_MATRIX_USERS_ONLY, false)); + checkBox.setChecked(PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean(KEY_FILTER_MATRIX_USERS_ONLY, true)); + + // Checks to see if default value is checked (which is true by default) and if so + // refreshes the screen, causing the user to see only Matrix users + if (checkBox.isChecked()) { + mShowMatrixUserOnly = true; + refresh(mFirstEntry, null); + } checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override diff --git a/vector/src/main/java/im/vector/features/hhs/ResourceLimitEventListener.kt b/vector/src/main/java/im/vector/features/hhs/ResourceLimitEventListener.kt index ac5f6ba867..092dbf2978 100644 --- a/vector/src/main/java/im/vector/features/hhs/ResourceLimitEventListener.kt +++ b/vector/src/main/java/im/vector/features/hhs/ResourceLimitEventListener.kt @@ -137,7 +137,7 @@ class ResourceLimitEventListener(private val dataHandler: MXDataHandler, private } /** - * This callback allows to alert when the state change + * This im.vector.callback allows to alert when the state change */ interface Callback { fun onResourceLimitStateChanged() diff --git a/vector/src/main/java/im/vector/fragments/HomeFragment.java b/vector/src/main/java/im/vector/fragments/HomeFragment.java index 68e13384ac..1546c6d2d5 100644 --- a/vector/src/main/java/im/vector/fragments/HomeFragment.java +++ b/vector/src/main/java/im/vector/fragments/HomeFragment.java @@ -181,12 +181,14 @@ private void initViews() { // People mDirectChatsSection.setTitle(R.string.bottom_action_people); + mDirectChatsSection.setHideIfEmpty(true); mDirectChatsSection.setPlaceholders(getString(R.string.no_conversation_placeholder), getString(R.string.no_result_placeholder)); mDirectChatsSection.setupRoomRecyclerView(new LinearLayoutManager(getActivity(), RecyclerView.HORIZONTAL, false), R.layout.adapter_item_circular_room_view, true, this, null, null); // Rooms mRoomsSection.setTitle(R.string.bottom_action_rooms); + mRoomsSection.setHideIfEmpty(true); mRoomsSection.setPlaceholders(getString(R.string.no_room_placeholder), getString(R.string.no_result_placeholder)); mRoomsSection.setupRoomRecyclerView(new LinearLayoutManager(getActivity(), RecyclerView.HORIZONTAL, false), R.layout.adapter_item_circular_room_view, true, this, null, null); diff --git a/vector/src/main/java/im/vector/fragments/PeopleFragment.java b/vector/src/main/java/im/vector/fragments/PeopleFragment.java index 08a7847a70..6e91a68384 100644 --- a/vector/src/main/java/im/vector/fragments/PeopleFragment.java +++ b/vector/src/main/java/im/vector/fragments/PeopleFragment.java @@ -31,36 +31,52 @@ import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; +import androidx.lifecycle.ViewModelProviders; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.core.Log; import org.matrix.androidsdk.core.callback.ApiCallback; import org.matrix.androidsdk.core.model.MatrixError; import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomPreviewData; import org.matrix.androidsdk.features.terms.TermsManager; import org.matrix.androidsdk.listeners.MXEventListener; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.User; +import org.matrix.androidsdk.rest.model.publicroom.PublicRoom; import org.matrix.androidsdk.rest.model.search.SearchUsersResponse; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import butterknife.BindView; +import im.vector.BuildConfig; +import im.vector.Matrix; import im.vector.R; +import im.vector.activity.CommonActivityUtils; +import im.vector.activity.MXCActionBarActivity; import im.vector.activity.ReviewTermsActivity; import im.vector.activity.VectorMemberDetailsActivity; +import im.vector.activity.VectorRoomActivity; import im.vector.activity.util.RequestCodesKt; import im.vector.adapters.ParticipantAdapterItem; import im.vector.adapters.PeopleAdapter; +import im.vector.adapters.RoomAdapter; +import im.vector.adapters.SabaPeopleAdapter; import im.vector.contacts.Contact; import im.vector.contacts.ContactsManager; import im.vector.contacts.PIDsRetriever; +import im.vector.fragments.terms.AcceptTermsFragment; +import im.vector.fragments.terms.AcceptTermsViewModel; +import im.vector.fragments.terms.ServiceTermsArgs; import im.vector.ui.themes.ThemeUtils; import im.vector.util.HomeRoomsViewModel; import im.vector.util.PermissionsToolsKt; @@ -68,6 +84,9 @@ import im.vector.view.EmptyViewItemDecoration; import im.vector.view.SimpleDividerItemDecoration; +import static android.provider.DocumentsContract.EXTRA_INFO; +import static im.vector.activity.MXCActionBarActivity.EXTRA_MATRIX_ID; + public class PeopleFragment extends AbsHomeFragment implements ContactsManager.ContactsManagerListener, AbsHomeFragment.OnRoomChangedListener { private static final String LOG_TAG = PeopleFragment.class.getSimpleName(); @@ -80,7 +99,7 @@ public class PeopleFragment extends AbsHomeFragment implements ContactsManager.C private CheckBox mMatrixUserOnlyCheckbox; - private PeopleAdapter mAdapter; + private SabaPeopleAdapter mAdapter; private List mDirectChats = new ArrayList<>(); private final List mLocalContacts = new ArrayList<>(); @@ -134,7 +153,9 @@ public void onPresenceUpdate(final Event event, final User user) { mOnRoomChangedListener = this; - mMatrixUserOnlyCheckbox.setChecked(PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(MATRIX_USER_ONLY_PREF_KEY, false)); + if (mMatrixUserOnlyCheckbox != null) { + mMatrixUserOnlyCheckbox.setChecked(PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(MATRIX_USER_ONLY_PREF_KEY, false)); + } mAdapter.onFilterDone(mCurrentFilter); @@ -249,7 +270,7 @@ private void initViews() { mRecycler.setLayoutManager(new LinearLayoutManager(getActivity(), RecyclerView.VERTICAL, false)); mRecycler.addItemDecoration(new SimpleDividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL, margin)); mRecycler.addItemDecoration(new EmptyViewItemDecoration(getActivity(), DividerItemDecoration.VERTICAL, 40, 16, 14)); - mAdapter = new PeopleAdapter(getActivity(), new PeopleAdapter.OnSelectItemListener() { + mAdapter = new SabaPeopleAdapter(getActivity(), new SabaPeopleAdapter.OnSelectItemListener() { @Override public void onSelectItem(Room room, int position) { openRoom(room); @@ -262,6 +283,23 @@ public void onSelectItem(ParticipantAdapterItem contact, int position) { }, this, this); mRecycler.setAdapter(mAdapter); + RoomAdapter rAdapter = new RoomAdapter(getActivity(), new RoomAdapter.OnSelectItemListener() { + @Override + public void onSelectItem(Room item, int position) { + openRoom(item); + } + + @Override + public void onSelectItem(PublicRoom publicRoom) { + onPublicRoomSelected(publicRoom); + } + + @Override + public void onSelectItem(ParticipantAdapterItem contact, int position) { + onContactSelected(contact); + } + }, this, this); + View checkBox = mAdapter.findSectionSubViewById(R.id.matrix_only_filter_checkbox); if (checkBox != null && checkBox instanceof CheckBox) { mMatrixUserOnlyCheckbox = (CheckBox) checkBox; @@ -285,6 +323,78 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { * ********************************************************************************************* */ + /** + * Copied from RoomAdapter fragment + */ + private void onPublicRoomSelected(final PublicRoom publicRoom) { + // sanity check + if (null != publicRoom.roomId) { + final RoomPreviewData roomPreviewData = new RoomPreviewData(mSession, publicRoom.roomId, null, publicRoom.canonicalAlias, null); + + // Check whether the room exists to handled the cases where the user is invited or he has joined. + // CAUTION: the room may exist whereas the user membership is neither invited nor joined. + final Room room = mSession.getDataHandler().getRoom(publicRoom.roomId, false); + if (null != room && room.isInvited()) { + Log.d(LOG_TAG, "onPublicRoomSelected : the user is invited -> display the preview " + getActivity()); + CommonActivityUtils.previewRoom(getActivity(), roomPreviewData); + } else if (null != room && room.isJoined()) { + Log.d(LOG_TAG, "onPublicRoomSelected : the user joined the room -> open the room"); + final Map params = new HashMap<>(); + params.put(MXCActionBarActivity.EXTRA_MATRIX_ID, mSession.getMyUserId()); + params.put(VectorRoomActivity.EXTRA_ROOM_ID, publicRoom.roomId); + + if (!TextUtils.isEmpty(publicRoom.name)) { + params.put(VectorRoomActivity.EXTRA_DEFAULT_NAME, publicRoom.name); + } + + if (!TextUtils.isEmpty(publicRoom.topic)) { + params.put(VectorRoomActivity.EXTRA_DEFAULT_TOPIC, publicRoom.topic); + } + + CommonActivityUtils.goToRoomPage(getActivity(), mSession, params); + } else { + // Display a preview by default. + Log.d(LOG_TAG, "onPublicRoomSelected : display the preview"); + mActivity.showWaitingView(); + + roomPreviewData.fetchPreviewData(new ApiCallback() { + private void onDone() { + if (null != mActivity) { + mActivity.hideWaitingView(); + CommonActivityUtils.previewRoom(getActivity(), roomPreviewData); + } + } + + @Override + public void onSuccess(Void info) { + onDone(); + } + + private void onError() { + roomPreviewData.setPublicRoom(publicRoom); + roomPreviewData.setRoomName(publicRoom.name); + onDone(); + } + + @Override + public void onNetworkError(Exception e) { + onError(); + } + + @Override + public void onMatrixError(MatrixError e) { + onError(); + } + + @Override + public void onUnexpectedError(Exception e) { + onError(); + } + }); + } + } + } + /** * Fill the local address book and known contacts adapters with data */ @@ -310,6 +420,9 @@ private void initContactsData() { * Get the known contacts list, sort it by presence and give it to adapter */ private void initKnownContacts() { + if (BuildConfig.IS_SABA) + return; + final AsyncTask asyncTask = new AsyncTask() { @Override protected Void doInBackground(Void... params) { @@ -389,7 +502,7 @@ public void onSuccess(SearchUsersResponse searchUsersResponse) { } } - mAdapter.setKnownContactsExtraTitle(null); + // mAdapter.setKnownContactsExtraTitle(null); mAdapter.setKnownContactsLimited((null != searchUsersResponse.limited) ? searchUsersResponse.limited : false); mAdapter.setFilteredKnownContacts(list, mCurrentFilter); } @@ -447,7 +560,7 @@ private void onContactSelected(final ParticipantAdapterItem item) { startRoomInfoIntent.putExtra(VectorMemberDetailsActivity.EXTRA_MEMBER_DISPLAY_NAME, item.mDisplayName); } - startRoomInfoIntent.putExtra(VectorMemberDetailsActivity.EXTRA_MATRIX_ID, mSession.getCredentials().userId); + startRoomInfoIntent.putExtra(EXTRA_MATRIX_ID, mSession.getCredentials().userId); startActivity(startRoomInfoIntent); } } @@ -524,6 +637,8 @@ private List getMatrixUsers() { * Init contacts views with data and update their display */ private void initContactsViews() { + if (BuildConfig.IS_SABA) + return; mAdapter.setLocalContacts(mMatrixUserOnlyCheckbox != null && mMatrixUserOnlyCheckbox.isChecked() ? getMatrixUsers() : mLocalContacts); @@ -567,10 +682,32 @@ public void onContactPresenceUpdate(Contact contact, String matrixId) { @Override public void onIdentityServerTermsNotSigned(String token) { - if (isAdded()) { - startActivityForResult(ReviewTermsActivity.Companion.intent(getActivity(), - TermsManager.ServiceType.IdentityService, mSession.getIdentityServerManager().getIdentityServerUrl() /* Cannot be null */, token), - RequestCodesKt.TERMS_REQUEST_CODE); + if (!BuildConfig.IS_SABA) { + try { + // Trying to accept terms on user's behalf without showing the dialog! + Log.v("Terms accepted: ", "running my own code"); + AcceptTermsViewModel viewModel = ViewModelProviders.of(this).get(AcceptTermsViewModel.class); + Intent intent = new Intent(); + intent.putExtra(EXTRA_INFO, new ServiceTermsArgs(TermsManager.ServiceType.IdentityService, mSession.getIdentityServerManager().getIdentityServerUrl() /* Cannot be null */, token)); + viewModel.termsArgs = intent.getParcelableExtra(EXTRA_INFO); + MXSession session; + String matrixId = null; + if (intent.hasExtra(EXTRA_MATRIX_ID)) { + matrixId = intent.getStringExtra(EXTRA_MATRIX_ID); + } + session = Matrix.getInstance(getContext()).getSession(matrixId); + viewModel.initSession(session); + AcceptTermsFragment acceptTermsFragment = new AcceptTermsFragment(); + acceptTermsFragment.initialize(getActivity()); + onActivityResult(RequestCodesKt.TERMS_REQUEST_CODE, Activity.RESULT_OK, null); + } catch (Exception e) { + Log.e("Error in ", "onIdentityServerTermsNotSigned-- " + e.getMessage()); + if (isAdded()) { + startActivityForResult(ReviewTermsActivity.Companion.intent(getActivity(), + TermsManager.ServiceType.IdentityService, mSession.getIdentityServerManager().getIdentityServerUrl() /* Cannot be null */, token), + RequestCodesKt.TERMS_REQUEST_CODE); + } + } } } diff --git a/vector/src/main/java/im/vector/fragments/RoomsFragment.java b/vector/src/main/java/im/vector/fragments/RoomsFragment.java index ed0ccc095a..1eeb69479e 100644 --- a/vector/src/main/java/im/vector/fragments/RoomsFragment.java +++ b/vector/src/main/java/im/vector/fragments/RoomsFragment.java @@ -53,6 +53,7 @@ import im.vector.activity.RoomDirectoryPickerActivity; import im.vector.activity.VectorRoomActivity; import im.vector.adapters.AdapterSection; +import im.vector.adapters.ParticipantAdapterItem; import im.vector.adapters.RoomAdapter; import im.vector.ui.themes.ThemeUtils; import im.vector.util.HomeRoomsViewModel; @@ -231,6 +232,10 @@ public void onSelectItem(Room room, int position) { public void onSelectItem(PublicRoom publicRoom) { onPublicRoomSelected(publicRoom); } + + @Override + public void onSelectItem(ParticipantAdapterItem contact, int position) { + } }, this, this); mRecycler.setAdapter(mAdapter); diff --git a/vector/src/main/java/im/vector/fragments/VectorMessageListFragment.java b/vector/src/main/java/im/vector/fragments/VectorMessageListFragment.java index ac59b30a8b..5e9824138f 100755 --- a/vector/src/main/java/im/vector/fragments/VectorMessageListFragment.java +++ b/vector/src/main/java/im/vector/fragments/VectorMessageListFragment.java @@ -90,7 +90,6 @@ import im.vector.extensions.MatrixSdkExtensionsKt; import im.vector.listeners.IMessagesAdapterActionsListener; import im.vector.receiver.VectorUniversalLinkReceiver; -import im.vector.ui.themes.ThemeUtils; import im.vector.util.EventGroup; import im.vector.util.ExternalApplicationsUtilKt; import im.vector.util.PermissionsToolsKt; @@ -216,9 +215,10 @@ public void onItemClick(AdapterView parent, View view, int position, long id) onRowClick(position); } }); - - v.setBackgroundColor(ThemeUtils.INSTANCE.getColor(getActivity(), android.R.attr.colorBackground)); - +/** + * BATNA ==>(Esmaeeil Moradi) set background conversation layout + */ + v.setBackgroundResource(R.drawable.background_main_conversation_shape); return v; } @@ -282,6 +282,12 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis } } + @Override + public void onStop() { + super.onStop(); + VectorRoomActivity.getMediaPlayer().stop(); + } + @Override public MXSession getSession(String matrixId) { return Matrix.getMXSession(getActivity(), matrixId); @@ -294,7 +300,7 @@ public MXMediaCache getMXMediaCache() { @Override public VectorMessagesAdapter createMessagesAdapter() { - return new VectorMessagesAdapter(mSession, getActivity(), getMXMediaCache()); + return new VectorMessagesAdapter(mSession, getActivity(), getMXMediaCache(), (VectorRoomActivity) getActivity(),this); } /** @@ -584,7 +590,12 @@ public void run() { resend(event); } }); - } else if (action == R.id.ic_action_vector_redact_message) { + cancelSelectionMode(); + } + else if (action == R.id.ic_action_vector_reply){ +// VectorMessagesAdapter.mSelectedEvent = null; + } + else if (action == R.id.ic_action_vector_redact_message) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { @@ -609,6 +620,7 @@ public void onClick(DialogInterface dialog, int id) { }) .setNegativeButton(R.string.cancel, null) .show(); + cancelSelectionMode(); } }); } else if (action == R.id.ic_action_vector_copy) { @@ -618,6 +630,7 @@ public void run() { SystemUtilsKt.copyToClipboard(getActivity(), textMsg); } }); + cancelSelectionMode(); } else if ((action == R.id.ic_action_vector_cancel_upload) || (action == R.id.ic_action_vector_cancel_download)) { getActivity().runOnUiThread(new Runnable() { @Override @@ -642,6 +655,7 @@ public void run() { .show(); } }); + cancelSelectionMode(); } else if (action == R.id.ic_action_vector_quote) { Activity attachedActivity = getActivity(); @@ -660,6 +674,7 @@ public void run() { } ((VectorRoomActivity) attachedActivity).insertQuoteInTextEditor(quotedTextMsg + "\n\n"); } + cancelSelectionMode(); } else if ((action == R.id.ic_action_vector_share) || (action == R.id.ic_action_vector_forward) || (action == R.id.ic_action_vector_save)) { // Message message = JsonUtils.toMessage(event.getContent()); @@ -708,10 +723,13 @@ public void run() { startActivity(sendIntent); } } + cancelSelectionMode(); } else if (action == R.id.ic_action_vector_permalink) { SystemUtilsKt.copyToClipboard(getActivity(), PermalinkUtils.createPermalink(event)); + cancelSelectionMode(); } else if (action == R.id.ic_action_vector_report) { onMessageReport(event); + cancelSelectionMode(); } else if ((action == R.id.ic_action_view_source) || (action == R.id.ic_action_view_decrypted_source)) { getActivity().runOnUiThread(new Runnable() { @Override @@ -736,8 +754,10 @@ public void onClick(DialogInterface dialog, int id) { .show(); } }); + cancelSelectionMode(); } else if (action == R.id.ic_action_device_verification) { onE2eIconClick(event, mAdapter.getDeviceInfo(event.eventId)); + cancelSelectionMode(); } else if (action == R.id.ic_action_re_request_e2e_key) { mSession.getCrypto().reRequestRoomKeyForEvent(event); @@ -866,6 +886,12 @@ public void onSuccess(Void info) { .setNegativeButton(R.string.cancel, null) .show(); } + private boolean isExist(String filename){ + String filePath = VectorRoomActivity.voicePath + filename; + File file = new File(filePath); + return file.exists(); + + } /*** * Manage save / share / forward actions on a media file @@ -882,7 +908,29 @@ void onMediaAction(final int menuAction, final EncryptedFileInfo encryptedFileInfo) { // Sanitize file name in case `m.body` contains a path. final String trimmedFileName = new File(filename).getName(); + VectorRoomActivity vectorRoomActivity = (VectorRoomActivity) getActivity(); + if (filename.contains(".3gp")|| filename.contains(".mp3") || filename.contains(".aac")){ + File file1=new File(VectorRoomActivity.voicePath+filename); + if (file1.exists() ) { + return; + } + if (!file1.exists() ) { + File dir = new File(VectorRoomActivity.voicePath); + if (dir.isDirectory()) + { + String[] voices = dir.list(); + for (String voice : voices) { + new File(dir, voice).delete(); + } + assert vectorRoomActivity != null; + } + } + if (isExist(filename)) ; + { + mAdapter.notifyDataSetChanged(); + } + } final MXMediaCache mediasCache = Matrix.getInstance(getActivity()).getMediaCache(); // check if the media has already been downloaded if (mediasCache.isMediaCached(mediaUrl, mediaMimeType)) { @@ -904,6 +952,15 @@ public void onSuccess(String savedMediaPath) { if (menuAction == ACTION_VECTOR_SAVE) { Toast.makeText(getActivity(), getText(R.string.media_slider_saved), Toast.LENGTH_LONG).show(); } else { + if (savedMediaPath.contains(".3gp")|| savedMediaPath.contains(".mp3") || savedMediaPath.contains(".aac")){ + + assert vectorRoomActivity != null; + vectorRoomActivity.playBack(savedMediaPath,false); + if (isExist(filename));{ + mAdapter.notifyDataSetChanged(); + } + + }else ExternalApplicationsUtilKt.openMedia(getActivity(), savedMediaPath, mediaMimeType); } } @@ -1114,9 +1171,8 @@ public void onRowClick(int position) { try { MessageRow row = mAdapter.getItem(position); Event event = row.getEvent(); - // toggle selection mode - mAdapter.onEventTap(event); + mAdapter.onEventTap(null); } catch (Exception e) { Log.e(LOG_TAG, "## onRowClick() failed " + e.getMessage(), e); } @@ -1127,7 +1183,6 @@ public void onContentClick(int position) { try { MessageRow row = mAdapter.getItem(position); Event event = row.getEvent(); - if (mAdapter.isInSelectionMode()) { // cancel the selection mode. mAdapter.onEventTap(null); @@ -1160,7 +1215,7 @@ public void onContentClick(int position) { } } else { // toggle selection mode - mAdapter.onEventTap(event); + mAdapter.onEventTap(null); } } catch (Exception e) { Log.e(LOG_TAG, "## onContentClick() failed " + e.getMessage(), e); diff --git a/vector/src/main/java/im/vector/fragments/VectorRoomSettingsFragment.java b/vector/src/main/java/im/vector/fragments/VectorRoomSettingsFragment.java index 50d22bcf0c..4c97b6350e 100755 --- a/vector/src/main/java/im/vector/fragments/VectorRoomSettingsFragment.java +++ b/vector/src/main/java/im/vector/fragments/VectorRoomSettingsFragment.java @@ -78,6 +78,7 @@ import java.util.Comparator; import java.util.List; +import im.vector.BuildConfig; import im.vector.Matrix; import im.vector.R; import im.vector.activity.CommonActivityUtils; @@ -542,7 +543,6 @@ private void enableSharedPreferenceListener(boolean aIsListenerEnabled) { mIsUiUpdateSkipped = !aIsListenerEnabled; try { - //SharedPreferences prefMgr = getActivity().getSharedPreferences("VectorSettingsFile", Context.MODE_PRIVATE); SharedPreferences prefMgr = PreferenceManager.getDefaultSharedPreferences(getActivity()); if (aIsListenerEnabled) { @@ -757,13 +757,6 @@ private void updatePreferenceUiValues() { mRoomTopicEditTxt.setText(value); } - // update room directory visibility -// if (null != mRoomDirectoryVisibilitySwitch) { -// boolean isRoomPublic = TextUtils.equals(mRoom.getVisibility()/*getState().visibility ou .isPublic()*/, RoomState.DIRECTORY_VISIBILITY_PUBLIC); -// if (isRoomPublic !isRoomPublic= mRoomDirectoryVisibilitySwitch.isChecked()) -// mRoomDirectoryVisibilitySwitch.setChecked(isRoomPublic); -// } - // check if fragment is added to its Activity if (!isAdded()) { Log.e(LOG_TAG, "## updatePreferenceUiValues(): fragment not added to Activity - isAdded()=false"); @@ -819,11 +812,6 @@ private void updatePreferenceUiValues() { value = RoomTag.ROOM_TAG_FAVOURITE; } else if (null != mRoom.getAccountData().roomTag(RoomTag.ROOM_TAG_LOW_PRIORITY)) { value = RoomTag.ROOM_TAG_LOW_PRIORITY; - /* For further use in case of multiple tags support - } else if (!mRoom.getAccountData().getKeys().isEmpty()) { - for (String tag : customTagList){ - summary += (!summary.isEmpty()?" ":"") + tag; - }*/ } else { // no tag associated to the room value = RoomTag.ROOM_TAG_NO_TAG; @@ -1710,7 +1698,7 @@ public void onSuccess(Void info) { /** * Refresh the addresses section */ - private void refreshEndToEnd() { + public void refreshEndToEnd() { // encrypt to unverified devices final SwitchPreference sendToUnverifiedDevicesPref = (SwitchPreference) findPreference(getString(R.string.room_settings_never_send_to_unverified_devices_title)); @@ -1794,6 +1782,12 @@ public void onSuccess(Void info) { isEncryptedPreference.setTitle(R.string.room_settings_addresses_e2e_enabled); isEncryptedPreference.setKey(key); isEncryptedPreference.setIcon(getResources().getDrawable(R.drawable.e2e_verified)); + /** + * BATNA ==> (Esmaeeil Moradi) change icon lock + */ + if (BuildConfig.IS_SABA){ + isEncryptedPreference.setIcon(getResources().getDrawable(R.drawable.e2e_verified_batna)); + } mAdvancedSettingsCategory.addPreference(isEncryptedPreference); } else { PowerLevels powerLevels = mRoom.getState().getPowerLevels(); @@ -1819,7 +1813,7 @@ public void onSuccess(Void info) { encryptSwitchPreference.setKey(key); encryptSwitchPreference.setIcon(ThemeUtils.INSTANCE.tintDrawable(getActivity(), getResources().getDrawable(R.drawable.e2e_unencrypted), R.attr.vctr_settings_icon_tint_color)); - encryptSwitchPreference.setChecked(false); + encryptSwitchPreference.setChecked(true); mAdvancedSettingsCategory.addPreference(encryptSwitchPreference); encryptSwitchPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @@ -1861,8 +1855,8 @@ public void onUnexpectedError(Exception e) { return true; } }); - } } } + } diff --git a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt index 37c96aa7f8..c354a12df1 100755 --- a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt +++ b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt @@ -186,6 +186,11 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref findPreference(PreferencesManager.SETTINGS_CONTACTS_PHONEBOOK_COUNTRY_PREFERENCE_KEY) } + // User Interface + private val mLanguageSettingCategory by lazy{ + findPreference(PreferencesManager.SETTINGS_USER_INTERFACE_KEY) as PreferenceCategory + } + // Group Flairs private val mGroupsFlairCategory by lazy { findPreference(PreferencesManager.SETTINGS_GROUPS_FLAIR_KEY) as PreferenceCategory @@ -867,7 +872,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref private fun refreshIntegrationManagerSettings() { val integrationAllowed = mSession.integrationManager.integrationAllowed - (findPreference(PreferencesManager.SETTINGS_INTEGRATION_ALLOW) as SwitchPreference).let { + (findPreference(PreferencesManager.SETTINGS_INTEGRATION_ALLOW) as? SwitchPreference)?.let { val savedListener = it.onPreferenceChangeListener it.onPreferenceChangeListener = null it.isChecked = integrationAllowed @@ -1757,6 +1762,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref /** * Refresh the ignored users list */ + @SuppressLint("StringFormatInvalid") private fun refreshIgnoredUsersList() { val ignoredUsersList = mSession.dataHandler.ignoredUserIds @@ -2426,6 +2432,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref selectedLanguagePreference.summary = VectorLocale.localeToLocalisedString(VectorLocale.applicationLocale) selectedLanguagePreference.onPreferenceClickListener = Preference.OnPreferenceClickListener { + //test if it will work like mContactPhonebookCountryPreference when it is visible startActivityForResult(LanguagePickerActivity.getIntent(activity), REQUEST_LOCALE) true } diff --git a/vector/src/main/java/im/vector/fragments/VectorUnknownDevicesFragment.java b/vector/src/main/java/im/vector/fragments/VectorUnknownDevicesFragment.java index f54d25c11e..0fbb67d3f2 100755 --- a/vector/src/main/java/im/vector/fragments/VectorUnknownDevicesFragment.java +++ b/vector/src/main/java/im/vector/fragments/VectorUnknownDevicesFragment.java @@ -261,8 +261,10 @@ public void run() { .setView(v) .setTitle(R.string.unknown_devices_alert_title); + mIsSendAnywayTapped = false; + if (null != mListener) { - // Add action buttons + //Add action buttons int messageResId = mIsForCalling ? R.string.call_anyway : R.string.send_anyway; builder.setPositiveButton(messageResId, new DialogInterface.OnClickListener() { @Override @@ -278,19 +280,20 @@ public void onClick(DialogInterface dialog, int id) { }); } else { - // Add action buttons + //Add action buttons builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { - // nothing : everything will be done on onDismiss() + //nothing : everything will be done on onDismiss() } }); } - return builder.create(); - } + builder.create().dismiss(); + return builder.create(); + } @Override public void dismissAllowingStateLoss() { // reported by GA diff --git a/vector/src/main/java/im/vector/fragments/keysbackup/setup/KeysBackupSetupSharedViewModel.kt b/vector/src/main/java/im/vector/fragments/keysbackup/setup/KeysBackupSetupSharedViewModel.kt index 9c54b55892..dd035ca5b9 100644 --- a/vector/src/main/java/im/vector/fragments/keysbackup/setup/KeysBackupSetupSharedViewModel.kt +++ b/vector/src/main/java/im/vector/fragments/keysbackup/setup/KeysBackupSetupSharedViewModel.kt @@ -20,6 +20,7 @@ import android.content.Context import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.nulabinc.zxcvbn.Strength +import im.vector.callback.OnRecoveryKeyListener import im.vector.R import im.vector.activity.util.WaitingViewData import im.vector.ui.arch.LiveEvent @@ -155,6 +156,70 @@ class KeysBackupSetupSharedViewModel : ViewModel() { } } + fun prepareRecoveryKey(context: Context, session: MXSession?, withPassphrase: String?, onRecoveryKeyListener: OnRecoveryKeyListener) { + // Update requestId + currentRequestId.value = System.currentTimeMillis() + isCreatingBackupVersion.value = true + + // Ensure passphrase is hidden during the process + showPasswordMode.value = false + + recoveryKey.value = null + prepareRecoverFailError.value = null + session?.let { mxSession -> + val requestedId = currentRequestId.value!! + + mxSession.crypto?.keysBackup?.prepareKeysBackupVersion(withPassphrase, + object : ProgressListener { + override fun onProgress(progress: Int, total: Int) { + if (requestedId != currentRequestId.value) { + //this is an old request, we can't cancel but we can ignore + return + } + + loadingStatus.value = WaitingViewData(context.getString(R.string.keys_backup_setup_step3_generating_key_status), + progress, + total) + } + }, + object : SuccessErrorCallback { + override fun onSuccess(info: MegolmBackupCreationInfo) { + if (requestedId != currentRequestId.value) { + //this is an old request, we can't cancel but we can ignore + return + } + recoveryKey.value = info.recoveryKey + megolmBackupCreationInfo = info + copyHasBeenMade = false + + val keyBackup = session.crypto?.keysBackup + if (keyBackup != null) { + createKeysBackup(context, keyBackup) + } else { + loadingStatus.value = null + + isCreatingBackupVersion.value = false + prepareRecoverFailError.value = Exception() + } + onRecoveryKeyListener.onRecoveryKeyGenerated(); + } + + override fun onUnexpectedError(e: java.lang.Exception?) { + if (requestedId != currentRequestId.value) { + //this is an old request, we can't cancel but we can ignore + return + } + + loadingStatus.value = null + + isCreatingBackupVersion.value = false + prepareRecoverFailError.value = e ?: Exception() + onRecoveryKeyListener.onRecoveryKeyFailed(e); + } + }) + } + } + fun forceCreateKeyBackup(context: Context) { val keyBackup = session.crypto?.keysBackup if (keyBackup != null) { diff --git a/vector/src/main/java/im/vector/fragments/terms/AcceptTermsFragment.kt b/vector/src/main/java/im/vector/fragments/terms/AcceptTermsFragment.kt index 719d9abe23..de2b45d53c 100644 --- a/vector/src/main/java/im/vector/fragments/terms/AcceptTermsFragment.kt +++ b/vector/src/main/java/im/vector/fragments/terms/AcceptTermsFragment.kt @@ -17,15 +17,19 @@ package im.vector.fragments.terms import android.app.Activity import android.os.Bundle +import android.util.Log import android.view.ViewGroup import android.widget.Button import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible +import androidx.fragment.app.FragmentActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import butterknife.BindView import butterknife.OnClick import com.airbnb.epoxy.EpoxyRecyclerView +import im.vector.BuildConfig import im.vector.R import im.vector.fragments.VectorBaseFragment import im.vector.util.openUrlInExternalBrowser @@ -54,6 +58,7 @@ class AcceptTermsFragment : VectorBaseFragment(), TermsController.Listener { lateinit var bottomBar: ViewGroup override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) viewModel = ViewModelProviders.of(requireActivity()).get(AcceptTermsViewModel::class.java) @@ -153,4 +158,94 @@ class AcceptTermsFragment : VectorBaseFragment(), TermsController.Listener { fun onDeclineButton() { activity?.finish() } + + fun initialize(fragmentActivity: FragmentActivity) { + viewModel = ViewModelProviders.of(fragmentActivity).get(AcceptTermsViewModel::class.java) + + val description = when (viewModel.termsArgs.type) { + TermsManager.ServiceType.IdentityService -> getString(R.string.terms_description_for_identity_server) + TermsManager.ServiceType.IntegrationManager -> getString(R.string.terms_description_for_integration_manager) + } + + termsController = TermsController(description, this) + termsList.setController(termsController) + termsController + viewModel.loadTerms(getString(R.string.resources_language)) + + viewModel.termsList.observe(this, Observer { terms -> + when (terms) { + is MxAsync.Loading -> { + Log.v("MxAsync: ", "is loading") + } + is MxAsync.Error -> { + Log.v("MxAsync: ", "Error in AcceptTermsFragment.kt in viewModel.termsList") + } + is MxAsync.Success -> { + updateState(terms.value) + for (term in terms.value) setChecked(term, true) + viewModel.acceptTerms() + } + } + }) + + viewModel.acceptTerms.observe(this, Observer { request -> + when (request) { + is MxAsync.Loading -> { + } + is MxAsync.Error -> { + Log.v("MxAsync: ", "Error in AcceptTermsFragment.kt in viewModel.acceptTerms") + } + is MxAsync.Success -> { + Log.v("MxAsync: ", "Success") + } + } + }) + + return + } + + fun initialize(activity: AppCompatActivity) { + viewModel = ViewModelProviders.of(activity).get(AcceptTermsViewModel::class.java) + + val description = when (viewModel.termsArgs.type) { + TermsManager.ServiceType.IdentityService -> getString(R.string.terms_description_for_identity_server) + TermsManager.ServiceType.IntegrationManager -> getString(R.string.terms_description_for_integration_manager) + } + + termsController = TermsController(description, this) + termsList.setController(termsController) + termsController + viewModel.loadTerms(getString(R.string.resources_language)) + + viewModel.termsList.observe(this, Observer { terms -> + when (terms) { + is MxAsync.Loading -> { + Log.v("MxAsync: ", "is loading") + } + is MxAsync.Error -> { + Log.v("MxAsync: ", "Error in AcceptTermsFragment.kt in viewModel.termsList") + } + is MxAsync.Success -> { + updateState(terms.value) + for (term in terms.value) setChecked(term, true) + viewModel.acceptTerms() + } + } + }) + + viewModel.acceptTerms.observe(this, Observer { request -> + when (request) { + is MxAsync.Loading -> { + } + is MxAsync.Error -> { + Log.v("MxAsync: ", "Error in AcceptTermsFragment.kt in viewModel.acceptTerms") + } + is MxAsync.Success -> { + Log.v("MxAsync: ", "Success") + } + } + }) + + return + } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/fragments/terms/AcceptTermsViewModel.kt b/vector/src/main/java/im/vector/fragments/terms/AcceptTermsViewModel.kt index 27578ca3c3..067d5c8b94 100644 --- a/vector/src/main/java/im/vector/fragments/terms/AcceptTermsViewModel.kt +++ b/vector/src/main/java/im/vector/fragments/terms/AcceptTermsViewModel.kt @@ -65,6 +65,7 @@ class AcceptTermsViewModel : ViewModel() { object : ApiCallback { override fun onSuccess(info: Unit) { acceptTerms.postValue(MxAsync.Success(Unit)) + Log.v("Terms accepted: ", "Successfully") } override fun onUnexpectedError(e: java.lang.Exception?) { diff --git a/vector/src/main/java/im/vector/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/notifications/NotificationUtils.kt index 2a3dc17cc7..68e5900449 100755 --- a/vector/src/main/java/im/vector/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/notifications/NotificationUtils.kt @@ -192,10 +192,19 @@ object NotificationUtils { val pi = PendingIntent.getActivity(context, 0, i, 0) val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color) + /** + * Batna ==>change notification icon + */ + var notificationIcon: Int + if (BuildConfig.IS_SABA) { + notificationIcon = R.drawable.notification_icon + } else { + notificationIcon = R.mipmap.ic_launcher + } val builder = NotificationCompat.Builder(context, LISTENING_FOR_EVENTS_NOTIFICATION_CHANNEL_ID) .setContentTitle(context.getString(subTitleResId)) - .setSmallIcon(R.drawable.sync) + .setSmallIcon(notificationIcon) .setCategory(NotificationCompat.CATEGORY_SERVICE) .setColor(accentColor) .setContentIntent(pi) @@ -377,7 +386,15 @@ object NotificationUtils { val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color) // Build the pending intent for when the notification is clicked val openRoomIntent = buildOpenRoomIntent(context, roomInfo.roomId) - val smallIcon = if (roomInfo.shouldBing) R.drawable.icon_notif_important else R.drawable.logo_transparent + /** + * Batna ==>change notification icon + */ + val smallIcon: Int + if (BuildConfig.IS_SABA) { + smallIcon = if (roomInfo.shouldBing) R.drawable.notification_icon else R.drawable.notification_icon + } else { + smallIcon = if (roomInfo.shouldBing) R.drawable.icon_notif_important else R.drawable.logo_transparent + } val channelID = if (roomInfo.shouldBing) NOISY_NOTIFICATION_CHANNEL_ID else SILENT_NOTIFICATION_CHANNEL_ID return NotificationCompat.Builder(context, channelID) @@ -480,7 +497,15 @@ object NotificationUtils { fun buildSimpleEventNotification(context: Context, simpleNotifiableEvent: NotifiableEvent, largeIcon: Bitmap?, matrixId: String): Notification? { val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color) // Build the pending intent for when the notification is clicked - val smallIcon = if (simpleNotifiableEvent.noisy) R.drawable.icon_notif_important else R.drawable.logo_transparent + /** + * Batna ==>change notification icon + */ + val smallIcon: Int + if (BuildConfig.IS_SABA) { + smallIcon = if (simpleNotifiableEvent.noisy) R.drawable.notification_icon else R.drawable.notification_icon + } else { + smallIcon = if (simpleNotifiableEvent.noisy) R.drawable.icon_notif_important else R.drawable.logo_transparent + } val channelID = if (simpleNotifiableEvent.noisy) NOISY_NOTIFICATION_CHANNEL_ID else SILENT_NOTIFICATION_CHANNEL_ID @@ -609,8 +634,15 @@ object NotificationUtils { noisy: Boolean, lastMessageTimestamp: Long): Notification? { val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color) - val smallIcon = if (noisy) R.drawable.icon_notif_important else R.drawable.logo_transparent - + /** + * Batna ==>change notification icon + */ + val smallIcon: Int + if (BuildConfig.IS_SABA) { + smallIcon = if (noisy) R.drawable.notification_icon else R.drawable.notification_icon + } else { + smallIcon = if (noisy) R.drawable.icon_notif_important else R.drawable.logo_transparent + } return NotificationCompat.Builder(context, if (noisy) NOISY_NOTIFICATION_CHANNEL_ID else SILENT_NOTIFICATION_CHANNEL_ID) // used in compat < N, after summary is built based on child notifications .setWhen(lastMessageTimestamp) diff --git a/vector/src/main/java/im/vector/receiver/VectorBootReceiver.java b/vector/src/main/java/im/vector/receiver/VectorBootReceiver.java index 5ae3fc602b..b604716f9c 100644 --- a/vector/src/main/java/im/vector/receiver/VectorBootReceiver.java +++ b/vector/src/main/java/im/vector/receiver/VectorBootReceiver.java @@ -19,10 +19,12 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Build; import android.text.TextUtils; import org.matrix.androidsdk.core.Log; +import im.vector.BuildConfig; import im.vector.services.EventStreamServiceX; import im.vector.util.PreferencesManager; @@ -34,7 +36,20 @@ public class VectorBootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.d(LOG_TAG, "## onReceive() : " + intent.getAction()); - + if (BuildConfig.IS_SABA) { + try { + Intent serviceIntent = new Intent(context, EventStreamServiceX.class); + serviceIntent.setAction(EventStreamServiceX.ACTION_SIMULATED_PERMANENT_LISTENING); + if (Build.VERSION.SDK_INT >= 26) { + context.startForegroundService(serviceIntent); + } else { + context.startService(serviceIntent); + } + } catch (Exception e) { + Log.v("Error in VectorBootReceiver:", e.getMessage()); + } + return; + } if (TextUtils.equals(intent.getAction(), Intent.ACTION_BOOT_COMPLETED) || TextUtils.equals(intent.getAction(), "android.intent.action.ACTION_BOOT_COMPLETED")) { if (PreferencesManager.autoStartOnBoot(context)) { diff --git a/vector/src/main/java/im/vector/repositories/ServerUrlsRepository.kt b/vector/src/main/java/im/vector/repositories/ServerUrlsRepository.kt index 16137aa5f2..8a80638e31 100644 --- a/vector/src/main/java/im/vector/repositories/ServerUrlsRepository.kt +++ b/vector/src/main/java/im/vector/repositories/ServerUrlsRepository.kt @@ -15,12 +15,14 @@ */ package im.vector.repositories - import android.content.Context import android.text.TextUtils +import android.util.Log import androidx.core.content.edit import androidx.preference.PreferenceManager +import im.vector.BuildConfig import im.vector.R +import im.vector.fetchurl.GetServerAddress /** * Object to store and retrieve home and identity server urls @@ -30,6 +32,7 @@ object ServerUrlsRepository { // Keys used to store default servers urls from the referrer private const val DEFAULT_REFERRER_HOME_SERVER_URL_PREF = "default_referrer_home_server_url" private const val DEFAULT_REFERRER_IDENTITY_SERVER_URL_PREF = "default_referrer_identity_server_url" + private const val URL_NOT_PROVIDED = "url_Not_provided" // Keys used to store current home server url and identity url const val HOME_SERVER_URL_PREF = "home_server_url" @@ -98,10 +101,35 @@ object ServerUrlsRepository { /** * Return default home server url from resources */ - fun getDefaultHomeServerUrl(context: Context): String = context.getString(R.string.default_hs_server_url) + fun getDefaultHomeServerUrl(context: Context): String { + if (BuildConfig.IS_SABA) { + if (BuildConfig.ALLOW_HOME_SERVER_CHANGE) { + return context.getString(R.string.default_hs_server_url) + } else { + if (URL_NOT_PROVIDED != getServerUrlFromMdm(context)) { + return getServerUrlFromMdm(context) + } else { + return context.getString(R.string.default_hs_server_url_saba) + } + } + } else { + return context.getString(R.string.default_hs_server_url) + } + } /** * Return default identity server url from resources */ fun getDefaultIdentityServerUrl(context: Context): String = context.getString(R.string.default_identity_server_url) + + /** + * Return Server Address from mdm-agent Application + */ + private fun getServerUrlFromMdm(context: Context): String { + val getServerAddress = GetServerAddress(context) + return if (null == getServerAddress.url) { + URL_NOT_PROVIDED + } else + getServerAddress.url + } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/services/EventStreamServiceX.kt b/vector/src/main/java/im/vector/services/EventStreamServiceX.kt index 3a21c00336..69bc3ff1ba 100755 --- a/vector/src/main/java/im/vector/services/EventStreamServiceX.kt +++ b/vector/src/main/java/im/vector/services/EventStreamServiceX.kt @@ -184,8 +184,10 @@ class EventStreamServiceX : VectorService() { } ACTION_GO_TO_FOREGROUND -> { // Stop foreground notification display - Log.i(LOG_TAG, "stopForeground") - stopForeground(true) + if (!BuildConfig.IS_SABA) { + Log.i(LOG_TAG, "stopForeground") + stopForeground(true) + } } } @@ -228,7 +230,7 @@ class EventStreamServiceX : VectorService() { ACTION_STOP, ACTION_GO_TO_BACKGROUND, ACTION_LOGOUT -> - stop() + if (!BuildConfig.IS_SABA) stop() ACTION_PUSH_RECEIVED, ACTION_SIMULATED_PUSH_RECEIVED -> { @@ -267,8 +269,10 @@ class EventStreamServiceX : VectorService() { ACTION_PUSH_UPDATE -> pushStatusUpdate() ACTION_BOOT_COMPLETE -> { // No FCM only - mSimulatePushImmediate = true - stop() + if (!BuildConfig.IS_SABA) { + mSimulatePushImmediate = true + stop() + } } ACTION_APPLICATION_UPGRADE -> { // FDroid only @@ -583,6 +587,10 @@ class EventStreamServiceX : VectorService() { Log.e(LOG_TAG, "prepareNotification : getContentAsJsonObject " + e.message, e) } + // Since This Service is always running and server does not distinguish between incoming and missed calls, + // We don't need to run CallService. FYI, SDK handles call management itself. + if (BuildConfig.IS_SABA) return + if (!TextUtils.isEmpty(callId)) { CallService.onIncomingCall(this, isVideo, @@ -605,7 +613,7 @@ class EventStreamServiceX : VectorService() { private const val ACTION_PUSH_UPDATE = "im.vector.services.EventStreamServiceX.PUSH_UPDATE" private const val ACTION_PUSH_RECEIVED = "im.vector.services.EventStreamServiceX.PUSH_RECEIVED" private const val ACTION_SIMULATED_PUSH_RECEIVED = "im.vector.services.EventStreamServiceX.SIMULATED_PUSH_RECEIVED" - private const val ACTION_SIMULATED_PERMANENT_LISTENING = "im.vector.services.EventStreamServiceX.ACTION_SIMULATED_PERMANENT_LISTENING" + public const val ACTION_SIMULATED_PERMANENT_LISTENING = "im.vector.services.EventStreamServiceX.ACTION_SIMULATED_PERMANENT_LISTENING" private const val ACTION_STOP = "im.vector.services.EventStreamServiceX.STOP" private const val ACTION_BOOT_COMPLETE = "im.vector.services.EventStreamServiceX.BOOT_COMPLETE" private const val ACTION_APPLICATION_UPGRADE = "im.vector.services.EventStreamServiceX.APPLICATION_UPGRADE" diff --git a/vector/src/main/java/im/vector/ui/VectorQuoteSpan.kt b/vector/src/main/java/im/vector/ui/VectorQuoteSpan.kt index 8070ccd276..a8ee149a74 100644 --- a/vector/src/main/java/im/vector/ui/VectorQuoteSpan.kt +++ b/vector/src/main/java/im/vector/ui/VectorQuoteSpan.kt @@ -33,8 +33,11 @@ import im.vector.R */ class VectorQuoteSpan(context: Context) : LeadingMarginSpan, LineBackgroundSpan { - private val backgroundColor = ContextCompat.getColor(context, R.color.quote_background_color) - private val stripeColor = ContextCompat.getColor(context, R.color.quote_strip_color) + /** + * BATNA ==> (Esmaeeil Moradi) change color background header message in vector message adapter + */ + private val backgroundColor = ContextCompat.getColor(context, R.color.background_header_message) + private val stripeColor = ContextCompat.getColor(context, R.color.background_header_message_divider) private val stripeWidth = context.resources.getDimension(R.dimen.quote_width) private val gap = context.resources.getDimension(R.dimen.quote_gap) diff --git a/vector/src/main/java/im/vector/util/PermissionsTools.kt b/vector/src/main/java/im/vector/util/PermissionsTools.kt index b55e7afb3b..67573b541b 100644 --- a/vector/src/main/java/im/vector/util/PermissionsTools.kt +++ b/vector/src/main/java/im/vector/util/PermissionsTools.kt @@ -60,6 +60,7 @@ private const val PERMISSIONS_EMPTY = PERMISSION_BYPASSED // Request code to ask permission to the system (arbitrary values) const val PERMISSION_REQUEST_CODE = 567 +const val MY_PERMISSIONS_REQUEST_REC_Audio = 10 const val PERMISSION_REQUEST_CODE_LAUNCH_CAMERA = 568 const val PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_CAMERA = 569 const val PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_VIDEO_CAMERA = 570 diff --git a/vector/src/main/java/im/vector/util/PreferencesManager.java b/vector/src/main/java/im/vector/util/PreferencesManager.java index fb4c7aea07..e1b716a76b 100755 --- a/vector/src/main/java/im/vector/util/PreferencesManager.java +++ b/vector/src/main/java/im/vector/util/PreferencesManager.java @@ -91,6 +91,7 @@ public class PreferencesManager { public static final String SETTINGS_ENCRYPTION_INFORMATION_DEVICE_KEY_PREFERENCE_KEY = "SETTINGS_ENCRYPTION_INFORMATION_DEVICE_KEY_PREFERENCE_KEY"; public static final String SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY = "SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY"; + public static final String SETTINGS_USER_INTERFACE_KEY = "SETTINGS_USER_INTERFACE_KEY"; // user public static final String SETTINGS_DISPLAY_NAME_PREFERENCE_KEY = "SETTINGS_DISPLAY_NAME_PREFERENCE_KEY"; @@ -315,7 +316,7 @@ public static boolean displayTimeIn12hFormat(Context context) { * @return true if the join and leave membership events should be shown in the messages list */ public static boolean showJoinLeaveMessages(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_SHOW_JOIN_LEAVE_MESSAGES_KEY, true); + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_SHOW_JOIN_LEAVE_MESSAGES_KEY, false); } /** @@ -345,7 +346,7 @@ public static boolean useNativeCamera(Context context) { * @return true if the send voice feature is enabled. */ public static boolean isSendVoiceFeatureEnabled(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY, false); + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY, true); } /** @@ -770,7 +771,7 @@ public static boolean showReadReceipts(Context context) { * @return true if the message timestamps must be always shown */ public static boolean alwaysShowTimeStamps(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_ALWAYS_SHOW_TIMESTAMPS_KEY, false); + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_ALWAYS_SHOW_TIMESTAMPS_KEY,true); } /** @@ -865,7 +866,7 @@ public static void setUseAnalytics(Context context, boolean useAnalytics) { * @return true to preview media */ public static boolean previewMediaWhenSending(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_PREVIEW_MEDIA_BEFORE_SENDING_KEY, false); + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_PREVIEW_MEDIA_BEFORE_SENDING_KEY, true); } /** @@ -885,7 +886,7 @@ public static boolean sendMessageWithEnter(Context context) { * @return true if the rage shake is used */ public static boolean useRageshake(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_USE_RAGE_SHAKE_KEY, true); + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_USE_RAGE_SHAKE_KEY, false); } /** diff --git a/vector/src/main/java/im/vector/util/VectorRoomMediasSender.java b/vector/src/main/java/im/vector/util/VectorRoomMediasSender.java index bb43a91232..38139fb01d 100755 --- a/vector/src/main/java/im/vector/util/VectorRoomMediasSender.java +++ b/vector/src/main/java/im/vector/util/VectorRoomMediasSender.java @@ -46,7 +46,9 @@ import java.util.ArrayList; import java.util.List; +import im.vector.BuildConfig; import im.vector.R; +import im.vector.activity.VectorMediaPickerActivity; import im.vector.activity.VectorRoomActivity; import im.vector.fragments.ImageSizeSelectionDialogFragment; import im.vector.fragments.VectorMessageListFragment; @@ -241,7 +243,12 @@ public void run() { mVectorRoomActivity.runOnUiThread(new Runnable() { @Override public void run() { - mVectorMessageListFragment.sendMediaMessage(sharedDataItem); + if (!BuildConfig.IS_SABA) { + mVectorMessageListFragment.sendMediaMessage(sharedDataItem); + } else { + mVectorMessageListFragment.sendMediaMessage(new RoomMediaMessage(sharedDataItem.getUri(), + sharedDataItem.getFileName(mVectorRoomActivity) + "*" + VectorMediaPickerActivity.stringCaption)); + } } }); @@ -808,8 +815,16 @@ public void run() { mVectorRoomActivity.runOnUiThread(new Runnable() { @Override public void run() { - mVectorMessageListFragment.sendMediaMessage(new RoomMediaMessage(Uri.parse(fImageUrl), - roomMediaMessage.getFileName(mVectorRoomActivity))); + if (BuildConfig.IS_SABA & VectorMediaPickerActivity.stringCaption != null) { + Log.e("Essi", "stringCaption == > " + VectorMediaPickerActivity.stringCaption); + + mVectorMessageListFragment.sendMediaMessage(new RoomMediaMessage(Uri.parse(fImageUrl), + roomMediaMessage.getFileName(mVectorRoomActivity) + "*" + VectorMediaPickerActivity.stringCaption)); + VectorMediaPickerActivity.stringCaption=""; + } else { + mVectorMessageListFragment.sendMediaMessage(new RoomMediaMessage(Uri.parse(fImageUrl), + roomMediaMessage.getFileName(mVectorRoomActivity))); + } aListener.onDone(); } }); diff --git a/vector/src/main/java/im/vector/view/KeysBackupBanner.kt b/vector/src/main/java/im/vector/view/KeysBackupBanner.kt index 9dc7e535f8..7fa9609feb 100755 --- a/vector/src/main/java/im/vector/view/KeysBackupBanner.kt +++ b/vector/src/main/java/im/vector/view/KeysBackupBanner.kt @@ -28,7 +28,10 @@ import androidx.transition.TransitionManager import butterknife.BindView import butterknife.ButterKnife import butterknife.OnClick +import im.vector.BuildConfig import im.vector.R +import im.vector.keymanager.KeyManager +import im.vector.sharedpreferences.BatnaSharedPreferences import org.jetbrains.anko.defaultSharedPreferences import org.matrix.androidsdk.core.Log @@ -180,12 +183,17 @@ class KeysBackupBanner @JvmOverloads constructor( // Do not display the setup banner if there is no keys to backup, or if the user has already closed it isVisible = false } else { - isVisible = true + if (BuildConfig.IS_SABA) { + isVisible = false - textView1.setText(R.string.keys_backup_banner_setup_line1) - textView2.isVisible = true - textView2.setText(R.string.keys_backup_banner_setup_line2) - close.isVisible = true + } else { + isVisible = true + + textView1.setText(R.string.keys_backup_banner_setup_line1) + textView2.isVisible = true + textView2.setText(R.string.keys_backup_banner_setup_line2) + close.isVisible = true + } } } @@ -193,12 +201,17 @@ class KeysBackupBanner @JvmOverloads constructor( if (version == context.defaultSharedPreferences.getString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, null)) { isVisible = false } else { - isVisible = true + if (BuildConfig.IS_SABA) { + isVisible = false - textView1.setText(R.string.keys_backup_banner_recover_line1) - textView2.isVisible = true - textView2.setText(R.string.keys_backup_banner_recover_line2) - close.isVisible = true + } else { + isVisible = true + + textView1.setText(R.string.keys_backup_banner_recover_line1) + textView2.isVisible = true + textView2.setText(R.string.keys_backup_banner_recover_line2) + close.isVisible = true + } } } @@ -206,17 +219,23 @@ class KeysBackupBanner @JvmOverloads constructor( if (version == context.defaultSharedPreferences.getString(BANNER_UPDATE_DO_NOT_SHOW_FOR_VERSION, null)) { isVisible = false } else { - isVisible = true + if (BuildConfig.IS_SABA) { + isVisible = false - textView1.setText(R.string.keys_backup_banner_update_line1) - textView2.isVisible = true - textView2.setText(R.string.keys_backup_banner_update_line2) - close.isVisible = true + } else { + isVisible = true + + textView1.setText(R.string.keys_backup_banner_update_line1) + textView2.isVisible = true + textView2.setText(R.string.keys_backup_banner_update_line2) + close.isVisible = true + } } } private fun renderBackingUp() { - isVisible = true + if (BuildConfig.IS_SABA) return + isVisible = false textView1.setText(R.string.keys_backup_banner_in_progress) loading.isVisible = true diff --git a/vector/src/main/java/im/vector/view/NotificationAreaView.kt b/vector/src/main/java/im/vector/view/NotificationAreaView.kt index 117ae3ddee..d91a321442 100644 --- a/vector/src/main/java/im/vector/view/NotificationAreaView.kt +++ b/vector/src/main/java/im/vector/view/NotificationAreaView.kt @@ -39,6 +39,7 @@ import androidx.transition.TransitionManager import butterknife.BindView import butterknife.ButterKnife import com.binaryfork.spanny.Spanny +import im.vector.BuildConfig import im.vector.R import im.vector.features.hhs.ResourceLimitErrorFormatter import im.vector.listeners.IMessagesAdapterActionsListener @@ -65,6 +66,8 @@ class NotificationAreaView @JvmOverloads constructor( lateinit var imageView: ImageView @BindView(R.id.room_notification_message) lateinit var messageView: TextView + @BindView(R.id.txt_new_message_count) + lateinit var countMessage: TextView var delegate: Delegate? = null private var state: State = State.Initial @@ -175,8 +178,13 @@ class NotificationAreaView @JvmOverloads constructor( } private fun renderTombstone(state: State.Tombstone) { + if (countMessage.visibility == View.VISIBLE) { + countMessage.visibility = View.GONE + } visibility = View.VISIBLE - imageView.setImageResource(R.drawable.error) + if (!BuildConfig.IS_SABA) { + imageView.setImageResource(R.drawable.error) + } val roomTombstoneContent = state.tombstoneContent val urlSpan = MatrixURLSpan(roomTombstoneContent.replacementRoom, state.tombstoneEventSenderId, delegate?.providesMessagesActionListener()) val textColorInt = ThemeUtils.getColor(context, R.attr.vctr_message_text_color) @@ -186,7 +194,6 @@ class NotificationAreaView @JvmOverloads constructor( .append("\n") .append(resources.getString(R.string.room_tombstone_continuation_link), urlSpan, ForegroundColorSpan(textColorInt)) messageView.movementMethod = LinkMovementMethod.getInstance() - messageView.text = message } private fun renderResourceLimitExceededError(state: State.ResourceLimitExceededError) { @@ -203,29 +210,40 @@ class NotificationAreaView @JvmOverloads constructor( } val message = resourceLimitErrorFormatter.format(state.matrixError, formatterMode, clickable = true) messageView.setTextColor(Color.WHITE) - messageView.text = message + if (!BuildConfig.IS_SABA) messageView.text = message messageView.movementMethod = LinkMovementMethod.getInstance() messageView.setLinkTextColor(Color.WHITE) setBackgroundColor(ContextCompat.getColor(context, backgroundColor)) } private fun renderConnectionError() { + if (countMessage.visibility == View.VISIBLE) { + countMessage.visibility = View.GONE + } visibility = View.VISIBLE - imageView.setImageResource(R.drawable.error) + if (!BuildConfig.IS_SABA) { + imageView.setImageResource(R.drawable.error) + } messageView.setTextColor(ContextCompat.getColor(context, R.color.vector_fuchsia_color)) - messageView.text = SpannableString(resources.getString(R.string.room_offline_notification)) + if (!BuildConfig.IS_SABA) messageView.text = SpannableString(resources.getString(R.string.room_offline_notification)) } private fun renderTyping(state: State.Typing) { visibility = visibilityForMessages - imageView.setImageResource(R.drawable.vector_typing) - messageView.text = SpannableString(state.message) + if (!BuildConfig.IS_SABA) { + imageView.setImageResource(R.drawable.vector_typing) + } + if (!BuildConfig.IS_SABA) messageView.text = SpannableString(state.message) messageView.setTextColor(ThemeUtils.getColor(context, R.attr.vctr_room_notification_text_color)) } private fun renderUnreadPreview() { visibility = visibilityForMessages - imageView.setImageResource(R.drawable.scrolldown) + if (BuildConfig.IS_SABA) { + imageView.setImageResource(R.drawable.scrolldown_saba) + } else { + imageView.setImageResource(R.drawable.scrolldown) + } messageView.setTextColor(ThemeUtils.getColor(context, R.attr.vctr_room_notification_text_color)) imageView.setOnClickListener { delegate?.closeScreen() } } @@ -233,14 +251,26 @@ class NotificationAreaView @JvmOverloads constructor( private fun renderScrollToBottom(state: State.ScrollToBottom) { visibility = visibilityForMessages if (state.unreadCount > 0) { - imageView.setImageResource(R.drawable.newmessages) + if (BuildConfig.IS_SABA) { + countMessage.visibility = View.VISIBLE + imageView.setImageResource(R.drawable.scrolldown_saba) + } else { + imageView.setImageResource(R.drawable.newmessages) + } messageView.setTextColor(ContextCompat.getColor(context, R.color.vector_fuchsia_color)) - messageView.text = SpannableString(resources.getQuantityString(R.plurals.room_new_messages_notification, state.unreadCount, state.unreadCount)) + if (!BuildConfig.IS_SABA) messageView.text = SpannableString(resources.getQuantityString(R.plurals.room_new_messages_notification, state.unreadCount, state.unreadCount)) + countMessage.text = resources.getQuantityString(R.plurals.room_new_messages_notification, state.unreadCount, state.unreadCount) } else { - imageView.setImageResource(R.drawable.scrolldown) + + if (BuildConfig.IS_SABA) { + imageView.setImageResource(R.drawable.scrolldown_saba) + countMessage.visibility = View.GONE + } else { + imageView.setImageResource(R.drawable.scrolldown) + } messageView.setTextColor(ThemeUtils.getColor(context, R.attr.vctr_room_notification_text_color)) if (!TextUtils.isEmpty(state.message)) { - messageView.text = SpannableString(state.message) + if (!BuildConfig.IS_SABA) messageView.text = SpannableString(state.message) } } messageView.setOnClickListener { delegate?.jumpToBottom() } diff --git a/vector/src/main/res/drawable/ic_baseline_pause_24.xml b/vector/src/main/res/drawable/ic_baseline_pause_24.xml new file mode 100644 index 0000000000..db52522929 --- /dev/null +++ b/vector/src/main/res/drawable/ic_baseline_pause_24.xml @@ -0,0 +1,11 @@ + + + diff --git a/vector/src/main/res/drawable/ic_launcher_background.xml b/vector/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000000..ca3826a46c --- /dev/null +++ b/vector/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vector/src/main/res/drawable/voice_download_48.xml b/vector/src/main/res/drawable/voice_download_48.xml new file mode 100644 index 0000000000..8086d14776 --- /dev/null +++ b/vector/src/main/res/drawable/voice_download_48.xml @@ -0,0 +1,5 @@ + + + diff --git a/vector/src/main/res/font/shabnam.ttf b/vector/src/main/res/font/shabnam.ttf new file mode 100644 index 0000000000..09cb4ab03b Binary files /dev/null and b/vector/src/main/res/font/shabnam.ttf differ diff --git a/vector/src/main/res/layout/adapter_item_circular_room_view.xml b/vector/src/main/res/layout/adapter_item_circular_room_view.xml index 8d672ca989..2a57e659ce 100755 --- a/vector/src/main/res/layout/adapter_item_circular_room_view.xml +++ b/vector/src/main/res/layout/adapter_item_circular_room_view.xml @@ -61,7 +61,7 @@ android:layout_alignParentRight="true" android:layout_marginEnd="15dp" android:layout_marginRight="15dp" - android:src="@drawable/e2e_verified" + android:src="@drawable/e2e_verified_batna" android:tint="?attr/colorAccent" android:visibility="invisible" tools:visibility="visible" /> diff --git a/vector/src/main/res/layout/adapter_item_member_details_devices.xml b/vector/src/main/res/layout/adapter_item_member_details_devices.xml index 294bf71126..5c65966b62 100644 --- a/vector/src/main/res/layout/adapter_item_member_details_devices.xml +++ b/vector/src/main/res/layout/adapter_item_member_details_devices.xml @@ -33,7 +33,7 @@ android:layout_alignParentRight="true" android:layout_marginEnd="16dp" android:layout_marginRight="16dp" - tools:src="@drawable/e2e_verified" /> + tools:src="@drawable/e2e_verified_batna" /> diff --git a/vector/src/main/res/layout/adapter_item_room_view.xml b/vector/src/main/res/layout/adapter_item_room_view.xml index c273421e5f..66a4213417 100644 --- a/vector/src/main/res/layout/adapter_item_room_view.xml +++ b/vector/src/main/res/layout/adapter_item_room_view.xml @@ -49,7 +49,7 @@ android:layout_alignBottom="@+id/room_avatar" android:layout_marginEnd="-4dp" android:layout_marginRight="-4dp" - android:src="@drawable/e2e_verified" + android:src="@drawable/e2e_verified_batna" android:tint="?attr/colorAccent" android:visibility="invisible" tools:visibility="visible" /> @@ -71,11 +71,14 @@ android:layout_height="wrap_content" android:layout_toStartOf="@+id/room_unread_count" android:layout_toLeftOf="@+id/room_unread_count" + android:textAlignment="viewStart" android:ellipsize="end" android:fontFamily="sans-serif-regular" android:maxLines="1" android:textSize="16sp" - tools:text="Room name a bit long to be displayed completely" /> + tools:text="Room name a bit long to be displayed completely" + tools:ignore="RtlHardcoded" + android:gravity="start" /> + tools:text="First message of the room is a bit too long to be displayed" + tools:ignore="RtlHardcoded" /> + android:src="@drawable/e2e_verified_batna" /> + android:src="@drawable/e2e_verified_batna" /> + android:src="@drawable/e2e_verified_batna" /> + android:src="@drawable/e2e_verified_batna" /> + android:orientation="vertical" + android:visibility="gone"> + android:orientation="horizontal" + android:visibility="gone"> + tools:background="?attr/colorAccent" + android:visibility="gone"/> + android:orientation="vertical" + android:visibility="gone"> + android:layout_height="wrap_content" + android:visibility="gone"> + tools:text="@string/merged_events_expand" + android:visibility="gone"/> + android:layout_height="wrap_content" + android:visibility="gone"/> @@ -62,7 +69,8 @@ android:id="@+id/messagesAdapter_merge_separator" android:layout_width="match_parent" android:layout_height="1dp" - android:background="?attr/colorAccent" /> + android:background="?attr/colorAccent" + android:visibility="gone"/> + tools:text="3 membership changes" + android:visibility="gone"/> - + - + \ No newline at end of file diff --git a/vector/src/main/res/layout/adapter_item_vector_message_room_member.xml b/vector/src/main/res/layout/adapter_item_vector_message_room_member.xml index ed02400271..d4282cad91 100644 --- a/vector/src/main/res/layout/adapter_item_vector_message_room_member.xml +++ b/vector/src/main/res/layout/adapter_item_vector_message_room_member.xml @@ -4,11 +4,14 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> + + + + layout="@layout/vector_message_header"/> + + + + tools:src="@tools:sample/avatars"/> + + android:background="#f00"/> + + + + + android:src="@drawable/e2e_verified_batna"/> + + - + + @@ -86,14 +98,19 @@ android:layout_gravity="start" android:layout_marginStart="4dp" android:layout_marginLeft="4dp" + android:paddingStart="30dp" android:layout_toStartOf="@+id/message_timestamp_layout" android:layout_toLeftOf="@+id/message_timestamp_layout" android:layout_toEndOf="@id/message_adapter_e2e_icon" android:layout_toRightOf="@id/message_adapter_e2e_icon" android:autoLink="none" android:textIsSelectable="false" - android:textSize="14sp" - tools:text="A body" /> + android:textSize="10sp" + android:textColor="#C0C0C0" + tools:text="A body" + tools:ignore="RtlSymmetry" + android:paddingLeft="30dp" /> + @@ -104,10 +121,13 @@ + layout="@layout/vector_message_receipts_list"/> + - + + - + + \ No newline at end of file diff --git a/vector/src/main/res/layout/adapter_item_vector_message_text_emote_notice.xml b/vector/src/main/res/layout/adapter_item_vector_message_text_emote_notice.xml index 40fda75c7c..3af64935e4 100644 --- a/vector/src/main/res/layout/adapter_item_vector_message_text_emote_notice.xml +++ b/vector/src/main/res/layout/adapter_item_vector_message_text_emote_notice.xml @@ -91,7 +91,7 @@ android:id="@+id/message_adapter_e2e_icon" android:layout_width="14dp" android:layout_height="14dp" - android:src="@drawable/e2e_verified" /> + android:src="@drawable/e2e_verified_batna" /> diff --git a/vector/src/main/res/layout/adapter_item_vector_search_message_room_member.xml b/vector/src/main/res/layout/adapter_item_vector_search_message_room_member.xml index ee7b28f322..87deb7b6c3 100644 --- a/vector/src/main/res/layout/adapter_item_vector_search_message_room_member.xml +++ b/vector/src/main/res/layout/adapter_item_vector_search_message_room_member.xml @@ -40,9 +40,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - + + + + android:background="?android:attr/colorBackground" + android:visibility="gone"> + + + + گرفتن نگارش پشتیبان… شکست در گرفتن آخرین نگارش کلیدهای بازیابی (%s). نگارش - + بکشید تا لغو شود + در حال ضبط… تلاش دوباره diff --git a/vector/src/main/res/values/colors.xml b/vector/src/main/res/values/colors.xml index 5cf835ea9a..858b5ee3dc 100644 --- a/vector/src/main/res/values/colors.xml +++ b/vector/src/main/res/values/colors.xml @@ -1,6 +1,7 @@ + #70BF56 #ff4b55 diff --git a/vector/src/main/res/values/dimens.xml b/vector/src/main/res/values/dimens.xml index a1920a3558..6684d1f8c2 100644 --- a/vector/src/main/res/values/dimens.xml +++ b/vector/src/main/res/values/dimens.xml @@ -16,8 +16,8 @@ 40dp 60dp - 4dp - 8dp + 8dp + 10dp 8dp 0.75 diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index d7871121ab..9fe8e2eb0d 100755 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -509,6 +509,7 @@ Invite user by ID Please enter one or more email address or Matrix ID Email or Matrix ID + %d عضو، %d آنلاین Search @@ -645,7 +646,7 @@ Troubleshooting diagnostics Run Tests Running… (%1$d of %2$d) - Basic diagnostic is OK. If you still do not receive notifications, please submit a bug report to help us investigate. + Basic diagnostic is ok. If you still do not receive notifications, please submit a bug report to help us investigate. One or more tests have failed, try suggested fix(es). One or more tests have failed, please submit a bug report to help us investigate. @@ -1024,7 +1025,7 @@ Never send encrypted messages to unverified sessions from this session. %1$d/%2$d key(s) imported with success. - Not Verified + NOT Verified Verified Blacklisted @@ -1038,8 +1039,8 @@ Unblacklist Verify session - Confirm by comparing the following with the User Settings in your other session: - "If they don't match, the security of your communication may be compromised." + To verify that this session can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this session matches the key below: + If it matches, press the verify button below. If it doesn’t, then someone else is intercepting this session and you should probably blacklist it. In the future this verification process will be more sophisticated. I verify that the keys match Riot now supports end-to-end encryption but you need to log in again to enable it.\n\nYou can do it now or later from the application settings. @@ -1461,7 +1462,7 @@ Why choose Riot.im? Never lose encrypted messages Use Key Backup - New secure message keys + New encrypted messages keys Manage in Key Backup Backing up keys… @@ -1536,7 +1537,176 @@ Why choose Riot.im? It looks like you’re trying to connect to another homeserver. Do you want to sign out? + + Edit + Reply + "Retry" + "Join a room to start using the app." + "Sent you an invitation" + Invited by %s + + You’re all caught up! + You have no more unread messages + Welcome home! + Catch up on unread messages here + Conversations + Your direct message conversations will be displayed here + Rooms + Your rooms will be displayed here + + Reactions + Agree + Like + Add Reaction + View Reactions + Reactions + + Event deleted by user + Event moderated by room admin + Last edited by %1$s on %2$s + + + Malformed event, cannot display + Create New Room + No network. Please check your Internet connection. + "Change" + "Change network" + "Please wait…" + "All Communities" + + "This room can't be previewed" + "The preview of world-readable room is not supported yet in RiotX" + + "Rooms" + "Direct Messages" + + + "New Room" + "CREATE" + "Room name" + "Public" + "Anyone will be able to join this room" + "Room Directory" + "Publish this room in the room directory" + + "An error occurred getting trust info" + "An error occurred getting keys backup data" + + Welcome to the beta! + "While RiotX is in early development, some features may be missing and you may experience bugs." + + "The latest feature list is always in the %1$s, and if you find bugs please submit a report in the top left menu of Home, and we’ll fix them as quickly as we can." + "Play Store description" + "If you find bugs please submit a report in the top left menu of Home, and we’ll fix them as quickly as we can." + + "Import e2e keys from file \"%1$s\"." + + Matrix SDK Version + Other third party notices + You are already viewing this room! + + Quick Reactions + + + General + Preferences + Security & Privacy + Expert + Push Rules + No push rules defined + No registered push gateways + + app_id: + push_key: + app_display_name: + session_name: + Url: + Format: + + Voice & Video + Help & About + + + Register token + + Make a suggestion + Please write your suggestion below. + Describe your suggestion here + Thanks, the suggestion has been successfully sent + The suggestion failed to be sent (%s) + + Show hidden events in timeline + + + RiotX - Next Generation Matrix Client + A faster and lighter client for Matrix using the latest Android frameworks + "RiotX is a new client for the Matrix protocol (Matrix.org): an open network for secure, decentralised communication. RiotX is a full rewrite of the Riot Android client, based on a full rewrite of the Matrix Android SDK. + +Disclaimer: This is a beta version. RiotX is currently in active development and contains limitations and (we hope not too many) bugs. All feedback is welcome! + +RiotX supports: +• Login to an existing account +• Create room and join public rooms +• Accept and reject invitations +• List users rooms +• View room details +• Send text messages +• Send attachment +• Read and write messages in encrypted rooms +• Crypto: E2E keys backup, advance device verification, key share request and answer +• Push notification +• Light, Dark and Black themes + +Not all features in Riot are implemented in RiotX yet. Main missing (and coming soon!) features: +• Room settings (list room members, etc.) +• Calls +• Widgets +• …" + + Direct Messages + + Waiting… + Encrypting thumbnail… + Sending thumbnail (%1$s / %2$s) + Encrypting file… + Sending file (%1$s / %2$s) + + Downloading file %1$s… + File %1$s has been downloaded! + + "(edited)" + + + %1$s to create an account. + Use the old app + + + Message Edits + No edits found + + + Filter conversations… + Can’t find what you’re looking for? + Create a new room + Send a new direct message + View the room directory + + Name or ID (#example:matrix.org) + + Enable swipe to reply in timeline + + Link copied to clipboard + + Add by matrix ID + "Creating room…" + "No result found, use Add by matrix ID to search on server." + "Start typing to get results" + "Filter by username or ID…" + + "Joining room…" + + View Edit History Terms of Service @@ -1544,6 +1714,9 @@ Why choose Riot.im? Be discoverable by others Use Bots, bridges, widgets and sticker packs + Read at + + Identity server Disconnect identity server Configure identity server @@ -1568,4 +1741,418 @@ Why choose Riot.im? You are currently sharing email addresses or phone numbers on the identity server %1$s. You will need to reconnect to %2$s to stop sharing them. Agree to the identity server (%s) Terms of Service to allow yourself to be discoverable by email address or phone number. + Enable verbose logs. + Verbose logs will help developers by providing more logs when you send a RageShake. Even when enabled, the application does not log message contents or any other private data. + + + Please retry once you have accepted the terms and conditions of your homeserver. + + Looks like the server is taking too long to respond, this can be caused by either poor connectivity or an error with the server. Please try again in a while. + + Send attachment + + Open the navigation drawer + Open the create room menu + Close the create room menu… + Create a new direct conversation + Create a new room + Close keys backup banner + Show password + Hide password + Jump to bottom + + + %1$s, %2$s and %3$d others read + %1$s, %2$s and %3$s read + %1$s and %2$s read + %s read + + 1 user read + %d users read + + + "The file '%1$s' (%2$s) is too large to upload. The limit is %3$s." + + "An error occurred while retrieving the attachment." + "File" + "Contact" + "Camera" + "Audio" + "Gallery" + "Sticker" + Couldn\'t handle share data + + "It's spam" + "It's inappropriate" + "Custom report…" + "Report this content" + "Reason for reporting this content" + "REPORT" + "BLOCK USER" + + "Content reported" + "This content was reported.\n\nIf you don't want to see any more content from this user, you can block him to hide his messages" + "Reported as spam" + "This content was reported as spam.\n\nIf you don't want to see any more content from this user, you can block him to hide his messages" + "Reported as inappropriate" + "This content was reported as inappropriate.\n\nIf you don't want to see any more content from this user, you can block him to hide his messages" + + Riot needs permission to save your E2E keys on disk.\n\nPlease allow access on the next pop-up to be able to export your keys manually. + + There is no network connection right now + + Block user + + "All messages (noisy)" + "All messages" + "Mentions only" + "Mute" + "Settings" + "Leave the room" + "%1$s made no changes" + Sends the given message as a spoiler + Spoiler + Type keywords to find a reaction. + + You are not ignoring any users + + Long click on a room to see more options + + + %1$s made the room public to whoever knows the link. + %1$s made the room invite only. + Unread messages + + Liberate your communication + Chat with people directly or in groups + Keep conversations private with encryption + Extend & customise your experience + Get started + + Select a server + Just like email, accounts have one home, although you can talk to anyone + Join millions free on the largest public server + Premium hosting for organisations + Learn more + Other + Custom & advanced settings + + Continue + + Connect to %1$s + Connect to Modular + Connect to a custom server + + Sign in to %1$s + Sign Up + Sign In + Continue with SSO + + Modular Address + Address + Premium hosting for organisations + Enter the address of the Modular Riot or Server you want to use + Enter the address of a server or a Riot you want to connect to + + An error occurred when loading the page: %1$s (%2$d) + The application is not able to signin to this homeserver. The homeserver supports the following signin type(s): %1$s.\n\nDo you want to signin using a web client? + Sorry, this server isn’t accepting new accounts. + The application is not able to create an account on this homeserver.\n\nDo you want to signup using a web client? + + This email is not associated to any account. + + + Reset password on %1$s + A verification email will be sent to your inbox to confirm setting your new password. + Next + Email + New password + + Warning! + Changing your password will reset any end-to-end encryption keys on all of your sessions, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another session before resetting your password. + Continue + + This email is not linked to any account + + Check your inbox + + A verification email was sent to %1$s. + Tap on the link to confirm your new password. Once you\'ve followed the link it contains, click below. + I have verified my email address + + Success! + Your password has been reset. + You have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, sign in again on each device. + Back to Sign In + + Warning + Your password is not yet changed.\n\nStop the password change process? + + Set email address + Set an email to recover your account. Later, you can optionally allow people you know to discover you by your email. + Email + Email (optional) + Next + + Set phone number + Set a phone number to optionally allow people you know to discover you. + Please use the international format. + Phone number + Phone number (optional) + Next + + Confirm phone number + + We just sent a code to %1$s. Enter it below to verify it’s you. + Enter code + Send again + Next + + "International phone numbers must start with '+'" + "Phone number seems invalid. Please check it" + + + Sign up to %1$s + Username or email + Password + Next + That username is taken + Warning + Your account is not created yet.\n\nStop the registration process? + + Select matrix.org + Select modular + Select a custom homeserver + Please perform the captcha challenge + Accept terms to continue + + Please check your email + We just sent an email to %1$s.\nPlease click on the link it contains to continue the account creation. + The entered code is not correct. Please check. + Outdated homeserver + This homeserver is running too old a version to connect to. Ask your homeserver admin to upgrade. + + + Too many requests have been sent. You can retry in %1$d second… + Too many requests have been sent. You can retry in %1$d seconds… + + + Seen by + + You’re signed out + It can be due to various reasons:\n\n• You’ve changed your password on another session.\n\n• You have deleted this session from another session.\n\n• The administrator of your server has invalidated your access for security reason. + Sign in again + + You’re signed out + Sign in + + Your homeserver (%1$s) admin has signed you out of your account %2$s (%3$s). + Sign in to recover encryption keys stored exclusively on this device. You need them to read all of your secure messages on any device. + Sign in + Password + Clear personal data + Warning: Your personal data (including encryption keys) is still stored on this device.\n\nClear it if you’re finished using this device, or want to sign in to another account. + Clear all data + + Clear data + Clear all data currently stored on this device?\nSign in again to access your account data and messages. + You’ll lose access to secure messages unless you sign in to recover your encryption keys. + Clear data + The current session is for user %1$s and you provide credentials for user %2$s. This is not supported by RiotX.\nPlease first clear data, then sign in again on another account. + + Your matrix.to link was malformed + The description is too short + + Initial Sync… + + See all my sessions + Advanced settings + Developer mode + The developer mode activates hidden features and may also make the application less stable. For developers only! + Rageshake + Detection threshold + Shake your phone to test the detection threshold + Shake detected! + Settings + Current session + Other sessions + + Showing only the first results, type more letters… + + Fail-fast + RiotX may crash more often when an unexpected error occurs + + Request to verify the given userID + Prepends ¯\\_(ツ)_/¯ to a plain-text message + + "Enable encryption" + "Once enabled, encryption cannot be disabled." + + Your email domain is not authorized to register on this server + + Untrusted sign in + They match + They don\'t match + Verify this user by confirming the following unique emoji appear on their screen, in the same order." + For ultimate security, use another trusted means of communication or do this in person. + Look for the green shield to ensure a user is trusted. Trust all users in a room to ensure the room is secure. + + Not secure + One of the following may be compromised:\n\n - Your homeserver\n - The homeserver the user you’re verifying is connected to\n - Yours, or the other users’ internet connection\n - Yours, or the other users’ device + + + Video. + Image. + Audio + File + + Waiting… + %s cancelled + You cancelled + %s accepted + You accepted + Verification Sent + Verification Request + + + Verify this session + Manually verify + + + You + + Scan the code with the other user\'s device to securely verify each other + Scan their code + Can\'t scan + If you\'re not in person, compare emoji instead + + Verify by comparing emojis + + Verify by Emoji + If you can’t scan the code above, verify by comparing a short, unique selection of emoji. + + QR code image + + Verify %s + Verified %s + Waiting for %s… + For extra security, verify %s by checking a one-time code on both your devices.\n\nFor maximum security, do this in person. + Messages in this room are not end-to-end encrypted. + Messages in this room are end-to-end encrypted.\n\nYour messages are secured with locks and only you and the recipient have the unique keys to unlock them. + Security + Learn more + More + Room settings + Notifications + + "One person" + "%1$d people" + + Uploads + Leave Room + "Leaving the room…" + + Admins + Moderators + Custom + Invites + Users + + Admin in %1$s + Moderator in %1$s + Custom (%1$d) in %2$s + + Jump to read receipt + + "RiotX does not handle events of type '%1$s' (yet)" + "RiotX does not handle message of type '%1$s' (yet)" + "RiotX encountered an issue when rendering content of event with id '%1$s'" + + Unignore + + This session is unable to share this verification with your other sessions.\nThe verification will be saved locally and shared in a future version of the app. + + Recent rooms + Other rooms + + Sends the given message colored as a rainbow + Sends the given emote colored as a rainbow + + + Timeline + + + Message editor + + Enable end-to-end encryption + Once enabled, encryption cannot be disabled. + + Enable encryption? + Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. + Enable encryption + + To be secure, verify %s by checking a one-time code. + To be secure, do this in person or use another way to communicate. + + Compare the unique emoji, ensuring they appear in the same order. + Compare the code with the one displayed on the other user\'s screen. + Messages with this user are end-to-end encrypted and can\'t be read by third parties. + Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted. + + + Cross-Signing + Cross-Signing is enabled\nPrivate Keys on device. + Cross-Signing is enabled\nKeys are trusted.\nPrivate keys are not known + Cross-Signing is enabled.\nKeys are not trusted + Cross-Signing is not enabled + + + Active Sessions + Show All Sessions + Manage Sessions + Sign out this session + + No cryptographic information available + + This session is trusted for secure messaging because you verified it: + Verify this session to mark it as trusted & grant it access to encrypted messages. If you didn’t sign in to this session your account may be compromised: + + + %d active session + %d active sessions + + + Verify this session + Other users may not trust it + Complete Security + + Open an existing session & use it to verify this one, granting it access to encrypted messages. If you can’t access one, use your recovery key or passphrase. + + + Verify + Verified + Warning + + Failed to get sessions + Sessions + Trusted + Not Trusted + + This session is trusted for secure messaging because %1$s (%2$s) verified it: + %1$s (%2$s) signed in using a new session: + Until this user trusts this session, messages sent to and from it are labelled with warnings. Alternatively, you can manually verify it. + + + Initialize CrossSigning + Reset Keys + + QR code + + Did the other user successfully scan the QR code? + Yes + No + + Connectivity to the server has been lost + Swipe to cancel + recording … diff --git a/vector/src/main/res/values/theme_light.xml b/vector/src/main/res/values/theme_light.xml index 24e984e6d3..fb496ece03 100644 --- a/vector/src/main/res/values/theme_light.xml +++ b/vector/src/main/res/values/theme_light.xml @@ -3,7 +3,7 @@ - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vector/src/saba/res/values/theme_dark.xml b/vector/src/saba/res/values/theme_dark.xml new file mode 100644 index 0000000000..14f9b0acfa --- /dev/null +++ b/vector/src/saba/res/values/theme_dark.xml @@ -0,0 +1,262 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vector/src/saba/res/values/theme_light.xml b/vector/src/saba/res/values/theme_light.xml new file mode 100644 index 0000000000..fb496ece03 --- /dev/null +++ b/vector/src/saba/res/values/theme_light.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +