diff --git a/app/build.gradle b/app/build.gradle index ac5be3449..45a383cbf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -65,7 +65,7 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation project(path: ':tinodesdk') + implementation project(path: ':tinui') // Don't change to 1.4.0 (requires API 31). // noinspection GradleDependency @@ -74,18 +74,14 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.1.3' // noinspection GradleDependency implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' - // Don't change to 1.4.0 (requires API 31). - // noinspection GradleDependency implementation 'androidx.fragment:fragment:1.3.1' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'androidx.exifinterface:exifinterface:1.3.3' - implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.legacy:legacy-support-v13:1.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.preference:preference:1.1.1' + implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation 'androidx.recyclerview:recyclerview-selection:1.1.0' - implementation 'androidx.vectordrawable:vectordrawable:1.1.0' - implementation 'androidx.viewpager2:viewpager2:1.0.0' // Don't change to 2.7.0 (requires API 31). // noinspection GradleDependency implementation 'androidx.work:work-runtime:2.6.0' @@ -98,8 +94,5 @@ dependencies { implementation 'com.google.firebase:firebase-messaging:23.0.0' // Don't change to 2.7182... The 2.8 is the latest. - // noinspection GradleDependency implementation 'com.squareup.picasso:picasso:2.8' - - annotationProcessor 'androidx.lifecycle:lifecycle-common-java8:2.4.0' } diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 12f0281fb..7add7fe33 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -10,7 +10,7 @@ # Add any project specific keep options here: # Classes which define json wire protocol. --keep class co.tinode.tinodesdk.model.** {*;} +-keep class co.tinode.tinsdk.model.** {*;} -keepattributes *Annotation*,EnclosingMethod,Signature -keepattributes SourceFile,LineNumberTable -keepnames class com.fasterxml.jackson.** {*;} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1abf12cc4..4d887eb16 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -40,7 +40,7 @@ + android:resource="@drawable/tinui_ic_icon_push" /> - + @@ -95,7 +94,6 @@ @@ -108,12 +106,11 @@ - + { TextView editor = ((AlertDialog) dialog).findViewById(R.id.enterPassword); diff --git a/app/src/main/java/co/tinode/tindroid/AccountInfoFragment.java b/app/src/main/java/co/tinode/tindroid/AccountInfoFragment.java index 12ec071ee..ea4996d97 100644 --- a/app/src/main/java/co/tinode/tindroid/AccountInfoFragment.java +++ b/app/src/main/java/co/tinode/tindroid/AccountInfoFragment.java @@ -17,8 +17,9 @@ import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.MeTopic; + +import co.tinode.tinsdk.MeTopic; +import co.tinode.tinui.media.VxCard; /** * Fragment for editing current user details. @@ -38,7 +39,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, return null; } // Inflate the fragment layout - View fragment = inflater.inflate(R.layout.fragment_account_info, container, false); + View fragment = inflater.inflate(R.layout.tindroid_fragment_account_info, container, false); final ActionBar bar = activity.getSupportActionBar(); if (bar != null) { bar.setDisplayHomeAsUpEnabled(true); @@ -117,7 +118,7 @@ public void updateFormValues(final FragmentActivity activity, final MeTopic= 0) { + fname = cursor.getString(displayNameIndex); + } + int sizeIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + if (sizeIndex >= 0) { + fsize = cursor.getLong(sizeIndex); + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { int idx = cursor.getColumnIndex(MediaStore.MediaColumns.ORIENTATION); if (idx >= 0) { @@ -239,7 +246,7 @@ static long enqueueDownloadAttachment(AppCompatActivity activity, Map ImageUtils.IMAGE_PREVIEW_DIM || + bmp.getHeight() > ImageUtils.IMAGE_PREVIEW_DIM)) { + previewBits = ImageUtils.bitmapToBytes(ImageUtils.scaleBitmap(bmp, + ImageUtils.IMAGE_PREVIEW_DIM, ImageUtils.IMAGE_PREVIEW_DIM), "image/jpeg"); } store.msgDraftUpdate(topic, msgId, draftyImage(args.getString(ARG_IMAGE_CAPTION), @@ -541,11 +548,11 @@ private ListenableWorker.Result uploadMessageAttachment(final Context context, f if (success) { // Success: mark message as ready for delivery. If content==null it won't be saved. store.msgReady(topic, msgId, content); - return ListenableWorker.Result.success(result.build()); + return Result.success(result.build()); } else { // Failure. Draft has been discarded earlier. We cannot discard it here because // copyStream cannot be interrupted. - return ListenableWorker.Result.failure(result.build()); + return Result.failure(result.build()); } } @@ -565,13 +572,13 @@ static PromisedReply uploadAvatar(@NotNull final VxCard pub, @Nul int width = bmp.getWidth(); int height = bmp.getHeight(); - if (width < UiUtils.MIN_AVATAR_SIZE || height < UiUtils.MIN_AVATAR_SIZE) { + if (width < ImageUtils.MIN_AVATAR_SIZE || height < ImageUtils.MIN_AVATAR_SIZE) { // FAIL. return new PromisedReply<>(new Exception("Image is too small")); } - if (width != height || width > UiUtils.MAX_AVATAR_SIZE) { - bmp = UiUtils.scaleSquareBitmap(bmp, UiUtils.MAX_AVATAR_SIZE); + if (width != height || width > ImageUtils.MAX_AVATAR_SIZE) { + bmp = ImageUtils.scaleSquareBitmap(bmp, ImageUtils.MAX_AVATAR_SIZE); width = bmp.getWidth(); height = bmp.getHeight(); } @@ -583,13 +590,13 @@ static PromisedReply uploadAvatar(@NotNull final VxCard pub, @Nul pub.photo.height = height; PromisedReply result; - try (InputStream is = UiUtils.bitmapToStream(bmp, mimeType)) { + try (InputStream is = ImageUtils.bitmapToStream(bmp, mimeType)) { long fileSize = is.available(); - if (fileSize > UiUtils.MAX_INBAND_AVATAR_SIZE) { + if (fileSize > ImageUtils.MAX_INBAND_AVATAR_SIZE) { // Sending avatar out of band. // Generate small avatar preview. - pub.photo.data = UiUtils.bitmapToBytes(UiUtils.scaleSquareBitmap(bmp, UiUtils.AVATAR_THUMBNAIL_DIM), mimeType); + pub.photo.data = ImageUtils.bitmapToBytes(ImageUtils.scaleSquareBitmap(bmp, ImageUtils.AVATAR_THUMBNAIL_DIM), mimeType); // Upload then return result with a link. This is a long-running blocking call. LargeFileHelper uploader = Cache.getTinode().getFileUploader(); result = uploader.uploadFuture(is, System.currentTimeMillis() + ".png", mimeType, fileSize, null) @@ -604,7 +611,7 @@ public PromisedReply onSuccess(ServerMessage msg) { }); } else { // Can send a small avatar in-band. - pub.photo.data = UiUtils.bitmapToBytes(UiUtils.scaleSquareBitmap(bmp, UiUtils.AVATAR_THUMBNAIL_DIM), mimeType); + pub.photo.data = ImageUtils.bitmapToBytes(ImageUtils.scaleSquareBitmap(bmp, ImageUtils.AVATAR_THUMBNAIL_DIM), mimeType); result = new PromisedReply<>((ServerMessage) null); } } catch (IOException | IllegalArgumentException ex) { @@ -629,10 +636,10 @@ private static Bitmap prepareImage(ContentResolver r, Uri src, UploadDetails upl } // Make sure the image dimensions are not too large. - if (bmp.getWidth() > UiUtils.MAX_BITMAP_SIZE || bmp.getHeight() > UiUtils.MAX_BITMAP_SIZE) { - bmp = UiUtils.scaleBitmap(bmp, UiUtils.MAX_BITMAP_SIZE, UiUtils.MAX_BITMAP_SIZE); + if (bmp.getWidth() > ImageUtils.MAX_BITMAP_SIZE || bmp.getHeight() > ImageUtils.MAX_BITMAP_SIZE) { + bmp = ImageUtils.scaleBitmap(bmp, ImageUtils.MAX_BITMAP_SIZE, ImageUtils.MAX_BITMAP_SIZE); - byte[] bits = UiUtils.bitmapToBytes(bmp, uploadDetails.mimeType); + byte[] bits = ImageUtils.bitmapToBytes(bmp, uploadDetails.mimeType); uploadDetails.fileSize = bits.length; } @@ -669,7 +676,7 @@ private static Bitmap prepareImage(ContentResolver r, Uri src, UploadDetails upl switch (orientation) { default: // Rotate image to ensure correct orientation. - bmp = UiUtils.rotateBitmap(bmp, orientation); + bmp = ImageUtils.rotateBitmap(bmp, orientation); break; case ExifInterface.ORIENTATION_NORMAL: break; diff --git a/app/src/main/java/co/tinode/tindroid/Cache.java b/app/src/main/java/co/tinode/tindroid/Cache.java index d9572be6c..14c3b332e 100644 --- a/app/src/main/java/co/tinode/tindroid/Cache.java +++ b/app/src/main/java/co/tinode/tindroid/Cache.java @@ -1,32 +1,47 @@ package co.tinode.tindroid; +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Context; +import android.content.SharedPreferences; import android.os.Build; +import android.text.TextUtils; +import android.util.Log; + +import androidx.preference.PreferenceManager; import com.google.firebase.messaging.FirebaseMessaging; import java.util.Locale; -import co.tinode.tindroid.db.BaseDb; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.FndTopic; -import co.tinode.tinodesdk.MeTopic; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.model.PrivateType; -import co.tinode.tinodesdk.model.ServerMessage; +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.FndTopic; +import co.tinode.tinsdk.MeTopic; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.Topic; +import co.tinode.tinsdk.model.MsgGetMeta; +import co.tinode.tinsdk.model.PrivateType; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinui.TinodeClient; +import co.tinode.tinui.account.Utils; +import co.tinode.tinui.db.BaseDb; +import co.tinode.tinui.media.VxCard; /** * Shared resources. */ public class Cache { + private static final String TAG = "Cache"; private static final String API_KEY = "AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K"; private static Tinode sTinode = null; - public static Tinode getTinode() { + public static void buildTinode() { if (sTinode == null) { - sTinode = new Tinode("Tindroid/" + TindroidApp.getAppVersion(), API_KEY, - BaseDb.getInstance().getStore(), null); + sTinode = new TinodeClient.Builder("Tindroid/" + TindroidApp.getAppVersion(), API_KEY) + .setStorage(new BaseDb.Builder(TindroidApp.getAppContext()).build().getStore()) + .build(); sTinode.setOsString(Build.VERSION.RELEASE); // Default types for parsing Public, Private fields of messages @@ -40,6 +55,12 @@ public static Tinode getTinode() { // Keep in app to prevent garbage collection. TindroidApp.retainTinodeCache(sTinode); } + } + + public static Tinode getTinode() { + if (sTinode == null) { + throw new IllegalStateException("Cache::buildTinode() must be called before obtaining Tinode instance"); + } FirebaseMessaging fbId = FirebaseMessaging.getInstance(); //noinspection ConstantConditions: Google lies about getInstance not returning null. @@ -96,4 +117,151 @@ static PromisedReply attachFndTopic(FndTopic.FndListener return new PromisedReply<>((ServerMessage) null); } } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private static boolean loginNow(Context context) { + String uid = BaseDb.getInstance().getUid(); + if (TextUtils.isEmpty(uid)) { + Log.w(TAG, "Data fetch failed: no login credentials"); + // Unknown if data is available, assuming it is. + return false; + } + + final AccountManager am = AccountManager.get(context); + final Account account = Utils.getSavedAccount(am, uid); + if (account == null) { + Log.w(TAG, "Data fetch failed: account not found"); + return false; + } + + final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + String hostName = sharedPref.getString(Utils.PREFS_HOST_NAME, TindroidApp.getDefaultHostName(context)); + boolean tls = sharedPref.getBoolean(Utils.PREFS_USE_TLS, TindroidApp.getDefaultTLS()); + + final Tinode tinode = Cache.getTinode(); + + try { + + String token = AccountManager.get(context).blockingGetAuthToken(account, Utils.TOKEN_TYPE, false); + // Will return immediately if it's already connected. + tinode.connect(hostName, tls, true).getResult(); + tinode.loginToken(token).getResult(); + } catch (Exception ex) { + Log.w(TAG, "Failed to connect to server", ex); + return false; + } + + return true; + } + + /** + * Fetch messages (and maybe topic description and subscriptions) in background. + *

+ * This method SHOULD NOT be called on UI thread. + * + * @param context context to use for resources. + * @param topicName name of the topic to sync. + * @param seq sequence ID of the new message to fetch. + * @return true if new data was available or data status was unknown, false if no data was available. + */ + public static boolean backgroundDataFetch(Context context, String topicName, int seq) { + Log.d(TAG, "Fetching messages for " + topicName); + + final Tinode tinode = Cache.getTinode(); + + // noinspection unchecked + ComTopic topic = (ComTopic) tinode.getTopic(topicName); + Topic.MetaGetBuilder builder; + if (topic == null) { + // New topic. Create it. + // noinspection unchecked + topic = (ComTopic) tinode.newTopic(topicName, null); + builder = topic.getMetaGetBuilder().withDesc().withSub(); + } else { + // Existing topic. + builder = topic.getMetaGetBuilder(); + } + + if (topic.isAttached()) { + Log.d(TAG, "Topic is already attached"); + // No need to fetch: topic is already subscribed and got data through normal channel. + // Assuming that data was available. + return true; + } + + boolean dataAvailable = false; + if (topic.getSeq() < seq) { + if (!loginNow(context)) { + return false; + } + dataAvailable = true; + PromisedReply result = null; + // Check if contacts have been synced already. + if (tinode.getTopicsUpdated() == null) { + // Background sync of contacts. + result = Cache.attachMeTopic(null); + } + + // Check again if topic has attached while we tried to connect. It does not guarantee that there + // is no race condition to subscribe. + if (!topic.isAttached()) { + // Fully asynchronous. We don't need to do anything with the result. + // The new data will be automatically saved. + topic.subscribe(null, builder.build()); + topic.getMeta(builder.reset().withLaterData(24).build()); + result = topic.getMeta(builder.reset().withLaterDel(24).build()); + topic.leave(); + } + if (result != null) { + try { + // Wait for result before disconnecting. + result.getResult(); + } catch (Exception ignored) { + } + } + tinode.disconnect(true); + } + return dataAvailable; + } + + /** + * Fetch description of a previously unknown topic or user in background. + * Fetch subscriptions for GRP topics. + *

+ * This method SHOULD NOT be called on UI thread. + * + * @param context context to use for resources. + * @param topicName name of the topic to sync. + */ + public static void backgroundMetaFetch(Context context, String topicName) { + Log.d(TAG, "Fetching description for " + topicName); + + final Tinode tinode = Cache.getTinode(); + + if (tinode.getTopic(topicName) != null) { + // Ignoring notification for a known topic. + return; + } + + if (!loginNow(context)) { + // Failed to connect or to login. + return; + } + + // Fetch description without subscribing. + try { + // Check if contacts have been synced already. + if (tinode.getTopicsUpdated() == null) { + // Background sync of all contacts. + Cache.attachMeTopic(null).getResult(); + tinode.getMeTopic().leave(); + } + + // Request description, wait for result. Tinode will save new topic to DB. + tinode.getMeta(topicName, MsgGetMeta.desc()).getResult(); + } catch (Exception ex) { + Log.i(TAG, "Background Meta fetch failed", ex); + } + tinode.disconnect(true); + } } diff --git a/app/src/main/java/co/tinode/tindroid/ChatsActivity.java b/app/src/main/java/co/tinode/tindroid/ChatsActivity.java index 118a104cf..bd43c6864 100644 --- a/app/src/main/java/co/tinode/tindroid/ChatsActivity.java +++ b/app/src/main/java/co/tinode/tindroid/ChatsActivity.java @@ -7,28 +7,28 @@ import android.graphics.Bitmap; import android.os.Bundle; import android.text.TextUtils; -import android.util.Log; import android.view.Menu; -import java.util.List; - import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; -import co.tinode.tindroid.account.ContactsManager; -import co.tinode.tindroid.account.Utils; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.MeTopic; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.Topic; -import co.tinode.tinodesdk.model.Credential; -import co.tinode.tinodesdk.model.Description; -import co.tinode.tinodesdk.model.MsgServerInfo; -import co.tinode.tinodesdk.model.MsgServerPres; -import co.tinode.tinodesdk.model.PrivateType; -import co.tinode.tinodesdk.model.Subscription; + +import java.util.List; + +import co.tinode.tinsdk.MeTopic; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.Topic; +import co.tinode.tinsdk.model.Credential; +import co.tinode.tinsdk.model.Description; +import co.tinode.tinsdk.model.MsgServerInfo; +import co.tinode.tinsdk.model.MsgServerPres; +import co.tinode.tinsdk.model.PrivateType; +import co.tinode.tinsdk.model.Subscription; +import co.tinode.tinui.account.ContactsManager; +import co.tinode.tinui.account.Utils; +import co.tinode.tinui.media.VxCard; /** * This activity owns 'me' topic. @@ -61,7 +61,7 @@ public class ChatsActivity extends AppCompatActivity protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_contacts); + setContentView(R.layout.tindroid_activity_contacts); setSupportActionBar(findViewById(R.id.toolbar)); diff --git a/app/src/main/java/co/tinode/tindroid/ChatsAdapter.java b/app/src/main/java/co/tinode/tindroid/ChatsAdapter.java index 1f53db473..6c8343d2b 100644 --- a/app/src/main/java/co/tinode/tindroid/ChatsAdapter.java +++ b/app/src/main/java/co/tinode/tindroid/ChatsAdapter.java @@ -11,11 +11,6 @@ import android.widget.ImageView; import android.widget.TextView; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatImageView; @@ -24,12 +19,18 @@ import androidx.recyclerview.selection.ItemKeyProvider; import androidx.recyclerview.selection.SelectionTracker; import androidx.recyclerview.widget.RecyclerView; -import co.tinode.tindroid.db.StoredTopic; -import co.tinode.tindroid.format.PreviewFormatter; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.Storage; -import co.tinode.tinodesdk.model.Drafty; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.Storage; +import co.tinode.tinsdk.model.Drafty; +import co.tinode.tinui.db.StoredTopic; +import co.tinode.tinui.format.PreviewFormatter; +import co.tinode.tinui.media.VxCard; /** * Handling active chats, i.e. 'me' topic. @@ -88,7 +89,7 @@ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - if (holder.viewType == R.layout.contact) { + if (holder.viewType == R.layout.tindroid_contact) { if (mTopics.size() <= position) { // Looks like there is a race condition here. return; @@ -131,9 +132,9 @@ public int getItemCount() { @Override public int getItemViewType(int position) { if (getActualItemCount() == 0) { - return R.layout.contact_empty; + return R.layout.tindroid_contact_empty; } - return R.layout.contact; + return R.layout.tindroid_contact; } void setSelectionTracker(SelectionTracker selectionTracker) { @@ -227,7 +228,7 @@ static class ViewHolder extends RecyclerView.ViewHolder { super(item); this.viewType = viewType; - if (viewType == R.layout.contact) { + if (viewType == R.layout.tindroid_contact) { name = item.findViewById(R.id.contactName); unreadCount = item.findViewById(R.id.unreadCount); priv = item.findViewById(R.id.contactPriv); @@ -311,7 +312,7 @@ void bind(int position, final ComTopic topic, Storage.Message msg, boole blocked.setVisibility(!topic.isJoiner() ? View.VISIBLE : View.GONE); if (selected) { - itemView.setBackgroundResource(R.drawable.contact_background); + itemView.setBackgroundResource(R.drawable.tinui_contact_background); itemView.setOnClickListener(null); itemView.setActivated(true); diff --git a/app/src/main/java/co/tinode/tindroid/ChatsFragment.java b/app/src/main/java/co/tinode/tindroid/ChatsFragment.java index c77bb9eef..67c420849 100644 --- a/app/src/main/java/co/tinode/tindroid/ChatsFragment.java +++ b/app/src/main/java/co/tinode/tindroid/ChatsFragment.java @@ -25,13 +25,14 @@ import androidx.recyclerview.selection.StorageStrategy; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tindroid.widgets.CircleProgressView; -import co.tinode.tindroid.widgets.HorizontalListDivider; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.NotConnectedException; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.model.ServerMessage; + +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.NotConnectedException; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinui.media.VxCard; +import co.tinode.tinui.widgets.CircleProgressView; +import co.tinode.tinui.widgets.HorizontalListDivider; public class ChatsFragment extends Fragment implements ActionMode.Callback, UiUtils.ProgressIndicator { @@ -62,7 +63,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c setHasOptionsMenu(!mIsBanned); - return inflater.inflate(mIsArchive ? R.layout.fragment_archive : R.layout.fragment_chats, + return inflater.inflate(mIsArchive ? R.layout.tindroid_fragment_archive : R.layout.tindroid_fragment_chats, container, false); } @@ -191,7 +192,7 @@ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflat // super.onCreateOptionsMenu(menu, inflater); menu.clear(); - inflater.inflate(R.menu.menu_chats, menu); + inflater.inflate(R.menu.tindroid_menu_chats, menu); menu.setGroupVisible(R.id.not_archive, !mIsArchive); } @@ -219,7 +220,7 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { - mode.getMenuInflater().inflate(R.menu.menu_chats_selected, menu); + mode.getMenuInflater().inflate(R.menu.tindroid_menu_chats_selected, menu); return true; } diff --git a/app/src/main/java/co/tinode/tindroid/ContactsAdapter.java b/app/src/main/java/co/tinode/tindroid/ContactsAdapter.java index d428270ef..c09556f25 100644 --- a/app/src/main/java/co/tinode/tindroid/ContactsAdapter.java +++ b/app/src/main/java/co/tinode/tindroid/ContactsAdapter.java @@ -16,13 +16,13 @@ import android.widget.SectionIndexer; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + import com.squareup.picasso.Picasso; import java.util.HashMap; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - /** * This is a subclass of CursorAdapter that supports binding Cursor columns to a view layout. * If those items are part of search results, the search string is marked by highlighting the @@ -80,7 +80,7 @@ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { */ @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - if (holder.viewType == R.layout.contact_basic) { + if (holder.viewType == R.layout.tindroid_contact_basic) { holder.bind(mCursor, position); } } @@ -128,10 +128,10 @@ public int getItemCount() { public int getItemViewType(int position) { if (getActualItemCount() == 0) { - return mPermissionGranted ? R.layout.contact_empty : R.layout.no_permission; + return mPermissionGranted ? R.layout.tindroid_contact_empty : R.layout.tindroid_no_permission; } - return R.layout.contact_basic; + return R.layout.tindroid_contact_basic; } @Override @@ -212,13 +212,13 @@ class ViewHolder extends RecyclerView.ViewHolder { super(view); this.viewType = viewType; - if (viewType == R.layout.contact_basic) { + if (viewType == R.layout.tindroid_contact_basic) { Context context = view.getContext(); text1 = view.findViewById(android.R.id.text1); text2 = view.findViewById(android.R.id.text2); switcher = view.findViewById(R.id.icon_switcher); - switcher.setInAnimation(context, R.anim.flip_in); - switcher.setOutAnimation(context, R.anim.flip_out); + switcher.setInAnimation(context, R.anim.tinui_flip_in); + switcher.setOutAnimation(context, R.anim.tinui_flip_out); } } @@ -272,8 +272,8 @@ void bind(Cursor cursor, final int position) { } if (isSelected(unique)) { - ((ImageView) switcher.getCurrentView()).setImageResource(R.drawable.ic_selected); - itemView.setBackgroundResource(R.drawable.contact_background); + ((ImageView) switcher.getCurrentView()).setImageResource(R.drawable.tinui_ic_selected); + itemView.setBackgroundResource(R.drawable.tinui_contact_background); itemView.setActivated(true); } else { @@ -282,8 +282,8 @@ void bind(Cursor cursor, final int position) { // Clear the icon then load the thumbnail from photoUri background. Picasso.get() .load(photoUri) - .placeholder(R.drawable.disk) - .error(R.drawable.ic_broken_image_round) + .placeholder(R.drawable.tinui_disk) + .error(R.drawable.tinui_ic_broken_image_round) .fit().into(icon); } else { icon.setImageDrawable( @@ -302,12 +302,12 @@ void bind(Cursor cursor, final int position) { itemView.setOnClickListener(view -> { mClickListener.onClick(position, unique, displayName, photoUri); if (isSelected(unique)) { - ViewHolder.this.switcher.setImageResource(R.drawable.ic_selected); + ViewHolder.this.switcher.setImageResource(R.drawable.tinui_ic_selected); } else if (photoUri != null) { Picasso.get() .load(photoUri) - .placeholder(R.drawable.disk) - .error(R.drawable.ic_broken_image_round) + .placeholder(R.drawable.tinui_disk) + .error(R.drawable.tinui_ic_broken_image_round) .fit() .into((ImageView) switcher.getNextView()); } else { diff --git a/app/src/main/java/co/tinode/tindroid/ContactsLoaderCallback.java b/app/src/main/java/co/tinode/tindroid/ContactsLoaderCallback.java index 1d574febc..926686ebb 100644 --- a/app/src/main/java/co/tinode/tindroid/ContactsLoaderCallback.java +++ b/app/src/main/java/co/tinode/tindroid/ContactsLoaderCallback.java @@ -10,7 +10,8 @@ import androidx.loader.app.LoaderManager; import androidx.loader.content.CursorLoader; import androidx.loader.content.Loader; -import co.tinode.tindroid.account.Utils; + +import co.tinode.tinui.account.Utils; class ContactsLoaderCallback implements LoaderManager.LoaderCallbacks { static final String ARG_SEARCH_TERM = "searchTerm"; @@ -72,7 +73,7 @@ public void onLoaderReset(@NonNull Loader loader) { /** * This interface defines constants for the Cursor and CursorLoader, based on constants defined - * in the {@link android.provider.ContactsContract.Contacts} class. + * in the {@link ContactsContract.Contacts} class. */ interface ContactsQuery { // A content URI for the Contacts table diff --git a/app/src/main/java/co/tinode/tindroid/CreateGroupFragment.java b/app/src/main/java/co/tinode/tindroid/CreateGroupFragment.java index 15dc90ab7..ac440b6a9 100644 --- a/app/src/main/java/co/tinode/tindroid/CreateGroupFragment.java +++ b/app/src/main/java/co/tinode/tindroid/CreateGroupFragment.java @@ -5,10 +5,8 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; -import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -16,12 +14,6 @@ import android.widget.ImageView; import android.widget.Toast; -import com.google.android.flexbox.FlexDirection; -import com.google.android.flexbox.FlexboxLayoutManager; -import com.google.android.flexbox.JustifyContent; - -import java.util.Map; - import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; @@ -33,12 +25,18 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tindroid.widgets.HorizontalListDivider; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.NotConnectedException; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.model.ServerMessage; +import com.google.android.flexbox.FlexDirection; +import com.google.android.flexbox.FlexboxLayoutManager; +import com.google.android.flexbox.JustifyContent; + +import java.util.Map; + +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.NotConnectedException; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinui.media.VxCard; +import co.tinode.tinui.widgets.HorizontalListDivider; /** * Fragment for adding/editing a group topic @@ -96,7 +94,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setHasOptionsMenu(true); - return inflater.inflate(R.layout.fragment_add_group, container, false); + return inflater.inflate(R.layout.tindroid_fragment_add_group, container, false); } @Override diff --git a/app/src/main/java/co/tinode/tindroid/CredentialsFragment.java b/app/src/main/java/co/tinode/tindroid/CredentialsFragment.java index c42b71e11..3dba19015 100644 --- a/app/src/main/java/co/tinode/tindroid/CredentialsFragment.java +++ b/app/src/main/java/co/tinode/tindroid/CredentialsFragment.java @@ -12,11 +12,12 @@ import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.fragment.app.Fragment; -import co.tinode.tindroid.db.BaseDb; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.model.Credential; -import co.tinode.tinodesdk.model.ServerMessage; + +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.model.Credential; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinui.db.BaseDb; /** * A placeholder fragment containing a simple view. @@ -44,7 +45,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, bar.setDisplayHomeAsUpEnabled(true); } - View fragment = inflater.inflate(R.layout.fragment_validate, container, false); + View fragment = inflater.inflate(R.layout.tindroid_fragment_validate, container, false); fragment.findViewById(R.id.confirm).setOnClickListener(this); fragment.findViewById(R.id.cancel).setOnClickListener(v -> parent.showFragment(LoginActivity.FRAGMENT_LOGIN, null)); diff --git a/app/src/main/java/co/tinode/tindroid/EditMembersFragment.java b/app/src/main/java/co/tinode/tindroid/EditMembersFragment.java index 752047d9d..c8fab3205 100644 --- a/app/src/main/java/co/tinode/tindroid/EditMembersFragment.java +++ b/app/src/main/java/co/tinode/tindroid/EditMembersFragment.java @@ -2,7 +2,6 @@ import android.Manifest; import android.app.Activity; -import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -10,6 +9,15 @@ import android.view.ViewGroup; import android.widget.Toast; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.loader.app.LoaderManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.google.android.flexbox.FlexDirection; import com.google.android.flexbox.FlexboxLayoutManager; import com.google.android.flexbox.JustifyContent; @@ -19,23 +27,15 @@ import java.util.List; import java.util.Map; -import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts; -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; -import androidx.loader.app.LoaderManager; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tindroid.widgets.HorizontalListDivider; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.NotConnectedException; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.model.PrivateType; -import co.tinode.tinodesdk.model.ServerMessage; -import co.tinode.tinodesdk.model.Subscription; +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.NotConnectedException; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.model.PrivateType; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinsdk.model.Subscription; +import co.tinode.tinui.media.VxCard; +import co.tinode.tinui.widgets.HorizontalListDivider; /** * Fragment for editing group members @@ -82,7 +82,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstance) { setHasOptionsMenu(true); - return inflater.inflate(R.layout.fragment_edit_members, container, false); + return inflater.inflate(R.layout.tindroid_fragment_edit_members, container, false); } @Override diff --git a/app/src/main/java/co/tinode/tindroid/FilePreviewFragment.java b/app/src/main/java/co/tinode/tindroid/FilePreviewFragment.java index db2bedc4c..6ac59d97f 100644 --- a/app/src/main/java/co/tinode/tindroid/FilePreviewFragment.java +++ b/app/src/main/java/co/tinode/tindroid/FilePreviewFragment.java @@ -13,28 +13,28 @@ import android.widget.ImageView; import android.widget.TextView; -import java.util.HashMap; -import java.util.Map; - import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.core.content.res.ResourcesCompat; import androidx.fragment.app.Fragment; +import java.util.HashMap; +import java.util.Map; + public class FilePreviewFragment extends Fragment { private static final String TAG = "FilePreviewFragment"; // Icon ID for mime type. Add more mime type to icon mappings here. private static final Map sMime2Icon; - private static final int DEFAULT_ICON_ID = R.drawable.ic_file; - private static final int INVALID_ICON_ID = R.drawable.ic_file_alert; + private static final int DEFAULT_ICON_ID = R.drawable.tinui_ic_file; + private static final int INVALID_ICON_ID = R.drawable.tinui_ic_file_alert; static { sMime2Icon = new HashMap<>(); - sMime2Icon.put("image", R.drawable.ic_image); - sMime2Icon.put("text", R.drawable.ic_text_file); - sMime2Icon.put("video", R.drawable.ic_movie); + sMime2Icon.put("image", R.drawable.tinui_ic_image); + sMime2Icon.put("text", R.drawable.tinui_ic_text_file); + sMime2Icon.put("video", R.drawable.tinui_ic_movie); } private ImageView mImageView; @@ -72,7 +72,7 @@ private static int getIconIdForMimeType(String mime) { @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_file_preview, container, false); + View view = inflater.inflate(R.layout.tindroid_fragment_file_preview, container, false); mImageView = view.findViewById(R.id.image); // Send message on button click. diff --git a/app/src/main/java/co/tinode/tindroid/FindAdapter.java b/app/src/main/java/co/tinode/tindroid/FindAdapter.java index c129ec936..13f4d1a34 100644 --- a/app/src/main/java/co/tinode/tindroid/FindAdapter.java +++ b/app/src/main/java/co/tinode/tindroid/FindAdapter.java @@ -14,16 +14,17 @@ import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + import com.squareup.picasso.Picasso; import java.util.Collection; import java.util.LinkedList; import java.util.List; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.model.Subscription; +import co.tinode.tinsdk.model.Subscription; +import co.tinode.tinui.media.VxCard; /** * FindAdapter merges results from searching local Contacts with remote 'fnd' topic. @@ -96,11 +97,11 @@ public void swapCursor(Cursor newCursor, String searchTerm) { public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { final LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(viewType, parent, false); - if (viewType == R.layout.not_found || - viewType == R.layout.no_permission || - viewType == R.layout.no_search_query) { + if (viewType == R.layout.tindroid_not_found || + viewType == R.layout.tindroid_no_permission || + viewType == R.layout.tindroid_no_search_query) { return new ViewHolderEmpty(view); - } else if (viewType == R.layout.contact_section) { + } else if (viewType == R.layout.tindroid_contact_section) { return new ViewHolderSection(view); } @@ -115,7 +116,7 @@ public void onBindViewHolder(@NonNull ViewHolder holder, int position) { @Override public int getItemViewType(int position) { if (position == 0) { - return R.layout.contact_section; + return R.layout.tindroid_contact_section; } position--; @@ -124,28 +125,28 @@ public int getItemViewType(int position) { if (count == 0) { if (position == 0) { // The 'empty' element in the 'PHONE CONTACTS' section. - return mPermissionGranted ? R.layout.not_found : R.layout.no_permission; + return mPermissionGranted ? R.layout.tindroid_not_found : R.layout.tindroid_no_permission; } // One 'empty' element count = 1; } else if (position < count) { - return R.layout.contact; + return R.layout.tindroid_contact; } position -= count; if (position == 0) { - return R.layout.contact_section; + return R.layout.tindroid_contact_section; } position--; count = getFoundItemCount(); if (count == 0 && position == 0) { - return TextUtils.isEmpty(mSearchTerm) ? R.layout.no_search_query : R.layout.not_found; + return TextUtils.isEmpty(mSearchTerm) ? R.layout.tindroid_no_search_query : R.layout.tindroid_not_found; } - return R.layout.contact; + return R.layout.tindroid_contact; } @Override @@ -367,8 +368,8 @@ private void bind(final Cursor cursor) { if (photoUri != null) { Picasso.get() .load(photoUri) - .placeholder(R.drawable.disk) - .error(R.drawable.ic_broken_image_round) + .placeholder(R.drawable.tinui_disk) + .error(R.drawable.tinui_ic_broken_image_round) .fit() .into(avatar); } else { diff --git a/app/src/main/java/co/tinode/tindroid/FindFragment.java b/app/src/main/java/co/tinode/tindroid/FindFragment.java index 3231b384d..35e79e983 100644 --- a/app/src/main/java/co/tinode/tindroid/FindFragment.java +++ b/app/src/main/java/co/tinode/tindroid/FindFragment.java @@ -18,8 +18,6 @@ import android.widget.SearchView; import android.widget.Toast; -import java.util.Map; - import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; @@ -31,17 +29,20 @@ import androidx.loader.app.LoaderManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tindroid.widgets.CircleProgressView; -import co.tinode.tindroid.widgets.HorizontalListDivider; -import co.tinode.tinodesdk.FndTopic; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.model.MetaSetDesc; -import co.tinode.tinodesdk.model.MsgGetMeta; -import co.tinode.tinodesdk.model.MsgSetMeta; -import co.tinode.tinodesdk.model.ServerMessage; -import co.tinode.tinodesdk.model.Subscription; + +import java.util.Map; + +import co.tinode.tinsdk.FndTopic; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.model.MetaSetDesc; +import co.tinode.tinsdk.model.MsgGetMeta; +import co.tinode.tinsdk.model.MsgSetMeta; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinsdk.model.Subscription; +import co.tinode.tinui.media.VxCard; +import co.tinode.tinui.widgets.CircleProgressView; +import co.tinode.tinui.widgets.HorizontalListDivider; /** * FindFragment contains a RecyclerView with results from searching local Contacts and remote 'fnd' topic. @@ -101,7 +102,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c @Nullable Bundle savedInstanceState) { setHasOptionsMenu(true); - return inflater.inflate(R.layout.fragment_contacts, container, false); + return inflater.inflate(R.layout.tindroid_fragment_contacts, container, false); } @Override @@ -175,7 +176,7 @@ public void onSaveInstanceState(@NonNull Bundle outState) { @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { menu.clear(); - inflater.inflate(R.menu.menu_contacts, menu); + inflater.inflate(R.menu.tindroid_menu_contacts, menu); final FragmentActivity activity = getActivity(); if (activity == null || activity.isFinishing() || activity.isDestroyed()) { diff --git a/app/src/main/java/co/tinode/tindroid/ForwardToFragment.java b/app/src/main/java/co/tinode/tindroid/ForwardToFragment.java index 1facd9119..9f285384e 100644 --- a/app/src/main/java/co/tinode/tindroid/ForwardToFragment.java +++ b/app/src/main/java/co/tinode/tindroid/ForwardToFragment.java @@ -13,20 +13,20 @@ import android.view.ViewGroup; import android.widget.EditText; -import com.google.android.material.bottomsheet.BottomSheetDialogFragment; - -import java.util.Locale; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tindroid.widgets.HorizontalListDivider; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.model.Drafty; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; + +import java.util.Locale; + +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.model.Drafty; +import co.tinode.tinui.media.VxCard; +import co.tinode.tinui.widgets.HorizontalListDivider; public class ForwardToFragment extends BottomSheetDialogFragment implements MessageActivity.DataSetChangeListener { @@ -49,7 +49,7 @@ public class ForwardToFragment extends BottomSheetDialogFragment implements Mess @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_forward_to, container, false); + return inflater.inflate(R.layout.tindroid_fragment_forward_to, container, false); } @Override diff --git a/app/src/main/java/co/tinode/tindroid/ImageViewFragment.java b/app/src/main/java/co/tinode/tindroid/ImageViewFragment.java index 5768f8a57..2228b5304 100644 --- a/app/src/main/java/co/tinode/tindroid/ImageViewFragment.java +++ b/app/src/main/java/co/tinode/tindroid/ImageViewFragment.java @@ -29,18 +29,20 @@ import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.res.ResourcesCompat; +import androidx.exifinterface.media.ExifInterface; +import androidx.fragment.app.Fragment; + import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; import java.io.IOException; import java.io.InputStream; -import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.content.res.ResourcesCompat; -import androidx.exifinterface.media.ExifInterface; -import androidx.fragment.app.Fragment; -import co.tinode.tindroid.widgets.OverlaidImageView; +import co.tinode.tinui.ImageUtils; +import co.tinode.tinui.widgets.OverlaidImageView; /** * Fragment for expanded display of an image: being attached or received. @@ -79,7 +81,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final Activity activity = getActivity(); - View view = inflater.inflate(R.layout.fragment_view_image, container, false); + View view = inflater.inflate(R.layout.tindroid_fragment_view_image, container, false); mMatrix = new Matrix(); mImageView = view.findViewById(R.id.image); mImageView.setImageMatrix(mMatrix); @@ -225,7 +227,7 @@ public void onResume() { int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); if (bmp != null) { - bmp = UiUtils.rotateBitmap(bmp, orientation); + bmp = ImageUtils.rotateBitmap(bmp, orientation); } is.close(); } @@ -238,8 +240,8 @@ public void onResume() { final String fn = fileName; mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); Picasso.get().load(ref) - .placeholder(R.drawable.ic_image) - .error(R.drawable.ic_broken_image) + .placeholder(R.drawable.tinui_ic_image) + .error(R.drawable.tinui_ic_broken_image) .centerInside().fit().into(mImageView, new Callback() { @Override public void onSuccess() { @@ -299,7 +301,7 @@ public void onError(Exception e) { // Show broken image. mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); mImageView.setImageDrawable(ResourcesCompat.getDrawable(activity.getResources(), - R.drawable.ic_broken_image, null)); + R.drawable.tinui_ic_broken_image, null)); activity.findViewById(R.id.metaPanel).setVisibility(View.INVISIBLE); setHasOptionsMenu(false); @@ -388,7 +390,7 @@ private void setupImagePostview(final Activity activity, Bundle args, String fil @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { // Inflate the menu; this adds items to the action bar if it is present. - inflater.inflate(R.menu.menu_image, menu); + inflater.inflate(R.menu.tindroid_menu_image, menu); } @Override @@ -460,7 +462,7 @@ private void acceptAvatar() { RectF cutOut = new RectF(mCutOutRect); inverse.mapRect(cutOut); - if (cutOut.width() < UiUtils.MIN_AVATAR_SIZE || cutOut.height() < UiUtils.MIN_AVATAR_SIZE) { + if (cutOut.width() < ImageUtils.MIN_AVATAR_SIZE || cutOut.height() < ImageUtils.MIN_AVATAR_SIZE) { // Avatar is too small. Toast.makeText(activity, R.string.image_too_small, Toast.LENGTH_SHORT).show(); return; diff --git a/app/src/main/java/co/tinode/tindroid/InvalidTopicFragment.java b/app/src/main/java/co/tinode/tindroid/InvalidTopicFragment.java index bf3587b19..e91db9b8e 100644 --- a/app/src/main/java/co/tinode/tindroid/InvalidTopicFragment.java +++ b/app/src/main/java/co/tinode/tindroid/InvalidTopicFragment.java @@ -16,6 +16,6 @@ public InvalidTopicFragment() { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setHasOptionsMenu(false); - return inflater.inflate(R.layout.fragment_invalid_topic, container, false); + return inflater.inflate(R.layout.tindroid_fragment_invalid_topic, container, false); } } diff --git a/app/src/main/java/co/tinode/tindroid/LoginActivity.java b/app/src/main/java/co/tinode/tindroid/LoginActivity.java index 55b83afcf..a2a863634 100644 --- a/app/src/main/java/co/tinode/tindroid/LoginActivity.java +++ b/app/src/main/java/co/tinode/tindroid/LoginActivity.java @@ -19,7 +19,8 @@ import androidx.fragment.app.FragmentTransaction; import androidx.lifecycle.ViewModelProvider; import androidx.preference.PreferenceManager; -import co.tinode.tindroid.db.BaseDb; + +import co.tinode.tinui.db.BaseDb; /** * LoginActivity is a FrameLayout which switches between fragments: @@ -67,7 +68,7 @@ public class LoginActivity extends AppCompatActivity implements ImageViewFragmen protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_login); + setContentView(R.layout.tindroid_activity_login); PreferenceManager.setDefaultValues(this, R.xml.login_preferences, false); diff --git a/app/src/main/java/co/tinode/tindroid/LoginFragment.java b/app/src/main/java/co/tinode/tindroid/LoginFragment.java index 2619f1840..4ec8659a0 100644 --- a/app/src/main/java/co/tinode/tindroid/LoginFragment.java +++ b/app/src/main/java/co/tinode/tindroid/LoginFragment.java @@ -18,11 +18,12 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.preference.PreferenceManager; -import co.tinode.tindroid.account.Utils; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.model.AuthScheme; -import co.tinode.tinodesdk.model.ServerMessage; + +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.model.AuthScheme; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinui.account.Utils; /** * A placeholder fragment containing a simple view. @@ -48,7 +49,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, bar.setTitle(R.string.app_name); } - View fragment = inflater.inflate(R.layout.fragment_login, container, false); + View fragment = inflater.inflate(R.layout.tindroid_fragment_login, container, false); final SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getActivity()); String login = pref.getString(LoginActivity.PREFS_LAST_LOGIN, null); @@ -70,7 +71,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { // Inflate the menu; this adds items to the action bar if it is present. - inflater.inflate(R.menu.menu_login, menu); + inflater.inflate(R.menu.tindroid_menu_login, menu); super.onCreateOptionsMenu(menu, inflater); } diff --git a/app/src/main/java/co/tinode/tindroid/MembersAdapter.java b/app/src/main/java/co/tinode/tindroid/MembersAdapter.java index 72dfadce7..f9b8b676c 100644 --- a/app/src/main/java/co/tinode/tindroid/MembersAdapter.java +++ b/app/src/main/java/co/tinode/tindroid/MembersAdapter.java @@ -8,16 +8,17 @@ import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.recyclerview.widget.RecyclerView; + import com.squareup.picasso.Picasso; import java.util.ArrayList; import java.util.HashMap; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.widget.AppCompatImageButton; -import androidx.recyclerview.widget.RecyclerView; -import co.tinode.tindroid.media.VxCard; +import co.tinode.tinui.media.VxCard; /** * In-memory adapter keeps selected members of the group: initial members before the editing, @@ -63,7 +64,7 @@ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - if (holder.viewType == R.layout.group_member_chip) { + if (holder.viewType == R.layout.tindroid_group_member_chip) { holder.bind(position); } } @@ -75,9 +76,9 @@ private int getActualItemCount() { @Override public int getItemViewType(int position) { if (getActualItemCount() == 0) { - return R.layout.group_member_chip_empty; + return R.layout.tindroid_group_member_chip_empty; } - return R.layout.group_member_chip; + return R.layout.tindroid_group_member_chip; } @Override @@ -207,7 +208,7 @@ class ViewHolder extends RecyclerView.ViewHolder { super(itemView); this.viewType = viewType; - if (viewType == R.layout.group_member_chip) { + if (viewType == R.layout.tindroid_group_member_chip) { avatar = itemView.findViewById(android.R.id.icon); displayName = itemView.findViewById(android.R.id.text1); close = itemView.findViewById(android.R.id.closeButton); @@ -221,8 +222,8 @@ void bind(int pos) { } else if (user.avatarUri != null) { Picasso.get() .load(user.avatarUri) - .placeholder(R.drawable.disk) - .error(R.drawable.ic_broken_image_round) + .placeholder(R.drawable.tinui_disk) + .error(R.drawable.tinui_ic_broken_image_round) .into(avatar); } else { avatar.setImageDrawable( diff --git a/app/src/main/java/co/tinode/tindroid/MessageActivity.java b/app/src/main/java/co/tinode/tindroid/MessageActivity.java index 5d08c8300..2557a28ba 100644 --- a/app/src/main/java/co/tinode/tindroid/MessageActivity.java +++ b/app/src/main/java/co/tinode/tindroid/MessageActivity.java @@ -23,6 +23,16 @@ import android.view.MenuItem; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.FileProvider; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.preference.PreferenceManager; + import com.google.firebase.messaging.RemoteMessage; import java.io.File; @@ -39,33 +49,24 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; -import androidx.annotation.NonNull; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import androidx.core.content.FileProvider; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; -import androidx.preference.PreferenceManager; -import co.tinode.tindroid.account.ContactsManager; -import co.tinode.tindroid.account.Utils; -import co.tinode.tindroid.db.BaseDb; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.NotConnectedException; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.ServerResponseException; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.Topic; -import co.tinode.tinodesdk.model.Description; -import co.tinode.tinodesdk.model.Drafty; -import co.tinode.tinodesdk.model.MsgServerData; -import co.tinode.tinodesdk.model.MsgServerInfo; -import co.tinode.tinodesdk.model.MsgServerPres; -import co.tinode.tinodesdk.model.PrivateType; -import co.tinode.tinodesdk.model.ServerMessage; -import co.tinode.tinodesdk.model.Subscription; +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.NotConnectedException; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.ServerResponseException; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.Topic; +import co.tinode.tinsdk.model.Description; +import co.tinode.tinsdk.model.Drafty; +import co.tinode.tinsdk.model.MsgServerData; +import co.tinode.tinsdk.model.MsgServerInfo; +import co.tinode.tinsdk.model.MsgServerPres; +import co.tinode.tinsdk.model.PrivateType; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinsdk.model.Subscription; +import co.tinode.tinui.account.ContactsManager; +import co.tinode.tinui.account.Utils; +import co.tinode.tinui.db.BaseDb; +import co.tinode.tinui.media.VxCard; /** * View to display a single conversation @@ -112,12 +113,21 @@ public void onReceive(Context ctx, Intent intent) { query.setFilterById(downloadId); Cursor c = dm.query(query); if (c.moveToFirst()) { - int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)); + int statusIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS); + if (statusIndex < 0) { + return; + } + int status = c.getInt(statusIndex); if (DownloadManager.STATUS_SUCCESSFUL == status) { - URI fileUri = URI.create(c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))); - String mimeType = c.getString(c.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE)); + int fileUriIndex = c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI); + int mimeTypeIndex = c.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE); + if (fileUriIndex < 0 || mimeTypeIndex < 0) { + return; + } + URI fileUri = URI.create(c.getString(fileUriIndex)); + String mimeType = c.getString(mimeTypeIndex); intent = new Intent(); - intent.setAction(android.content.Intent.ACTION_VIEW); + intent.setAction(Intent.ACTION_VIEW); intent.setDataAndType(FileProvider.getUriForFile(MessageActivity.this, "co.tinode.tindroid.provider", new File(fileUri)), mimeType); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); @@ -127,7 +137,11 @@ public void onReceive(Context ctx, Intent intent) { startActivity(new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)); } } else if (DownloadManager.STATUS_FAILED == status) { - int reason = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_REASON)); + int reasonIndex = c.getColumnIndex(DownloadManager.COLUMN_REASON); + if (reasonIndex < 0) { + return; + } + int reason = c.getInt(reasonIndex); Log.w(TAG, "Download failed. Reason: " + reason); Toast.makeText(MessageActivity.this, R.string.failed_to_download, Toast.LENGTH_SHORT).show(); @@ -162,7 +176,7 @@ protected void onCreate(Bundle savedInstanceState) { mTopicName = savedInstanceState.getString(TOPIC_NAME); } - setContentView(R.layout.activity_messages); + setContentView(R.layout.tindroid_activity_messages); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); @@ -355,7 +369,10 @@ private String readTopicNameFromIntent(Intent intent) { new String[]{Utils.DATA_PID}, null, null, null); if (cursor != null) { if (cursor.moveToFirst()) { - name = cursor.getString(cursor.getColumnIndex(Utils.DATA_PID)); + int nameIndex = cursor.getColumnIndex(Utils.DATA_PID); + if (nameIndex >= 0) { + name = cursor.getString(nameIndex); + } } cursor.close(); } diff --git a/app/src/main/java/co/tinode/tindroid/MessagesAdapter.java b/app/src/main/java/co/tinode/tindroid/MessagesAdapter.java index 695a6ec74..9ba72a495 100644 --- a/app/src/main/java/co/tinode/tindroid/MessagesAdapter.java +++ b/app/src/main/java/co/tinode/tindroid/MessagesAdapter.java @@ -37,16 +37,6 @@ import android.widget.TextView; import android.widget.Toast; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; @@ -61,22 +51,35 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.work.WorkInfo; import androidx.work.WorkManager; -import co.tinode.tindroid.db.BaseDb; -import co.tinode.tindroid.db.MessageDb; -import co.tinode.tindroid.db.StoredMessage; -import co.tinode.tindroid.format.CopyFormatter; -import co.tinode.tindroid.format.FullFormatter; -import co.tinode.tindroid.format.QuoteFormatter; -import co.tinode.tindroid.format.ThumbnailTransformer; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Storage; -import co.tinode.tinodesdk.Topic; -import co.tinode.tinodesdk.model.Drafty; -import co.tinode.tinodesdk.model.MsgRange; -import co.tinode.tinodesdk.model.ServerMessage; -import co.tinode.tinodesdk.model.Subscription; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; + +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.Storage; +import co.tinode.tinsdk.Topic; +import co.tinode.tinsdk.model.Drafty; +import co.tinode.tinsdk.model.MsgRange; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinsdk.model.Subscription; +import co.tinode.tinui.ImageUtils; +import co.tinode.tinui.db.BaseDb; +import co.tinode.tinui.db.MessageDb; +import co.tinode.tinui.db.StoredMessage; +import co.tinode.tinui.format.CopyFormatter; +import co.tinode.tinui.format.FullFormatter; +import co.tinode.tinui.format.QuoteFormatter; +import co.tinode.tinui.format.ThumbnailTransformer; +import co.tinode.tinui.media.VxCard; +import co.tinode.tinui.widgets.RippleFrameLayout; /** * Handle display of a conversation @@ -160,7 +163,7 @@ public void onDestroyActionMode(ActionMode actionMode) { @Override public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { - mActivity.getMenuInflater().inflate(R.menu.menu_message_selected, menu); + mActivity.getMenuInflater().inflate(R.menu.tindroid_menu_message_selected, menu); menu.findItem(R.id.action_delete).setVisible(!ComTopic.isChannel(mTopicName)); return true; } @@ -212,7 +215,7 @@ private static Spanned serviceContentSpanned(Context ctx, int iconId, int messag span.setSpan(new ForegroundColorSpan(Color.rgb(0x75, 0x75, 0x75)), 0, span.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Drawable icon = AppCompatResources.getDrawable(ctx, iconId); - span.setSpan(new IconMarginSpan(UiUtils.bitmapFromDrawable(icon), 24), + span.setSpan(new IconMarginSpan(ImageUtils.bitmapFromDrawable(icon), 24), 0, span.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return span; } @@ -432,31 +435,31 @@ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { switch (viewType) { case VIEWTYPE_CENTER: - v = LayoutInflater.from(parent.getContext()).inflate(R.layout.meta_message, + v = LayoutInflater.from(parent.getContext()).inflate(R.layout.tindroid_meta_message, parent, false); break; case VIEWTYPE_FULL_LEFT: - v = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_left_single, + v = LayoutInflater.from(parent.getContext()).inflate(R.layout.tindroid_message_left_single, parent, false); break; case VIEWTYPE_FULL_AVATAR: - v = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_left_single_avatar, + v = LayoutInflater.from(parent.getContext()).inflate(R.layout.tindroid_message_left_single_avatar, parent, false); break; case VIEWTYPE_FULL_RIGHT: - v = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_right_single, + v = LayoutInflater.from(parent.getContext()).inflate(R.layout.tindroid_message_right_single, parent, false); break; case VIEWTYPE_SIMPLE_LEFT: - v = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_left, + v = LayoutInflater.from(parent.getContext()).inflate(R.layout.tindroid_message_left, parent, false); break; case VIEWTYPE_SIMPLE_AVATAR: - v = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_left_avatar, + v = LayoutInflater.from(parent.getContext()).inflate(R.layout.tindroid_message_left_avatar, parent, false); break; case VIEWTYPE_SIMPLE_RIGHT: - v = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_right, + v = LayoutInflater.from(parent.getContext()).inflate(R.layout.tindroid_message_right, parent, false); break; default: @@ -509,11 +512,11 @@ public void onBindViewHolder(@NonNull final ViewHolder holder, int position) { Spanned text = m.content.format(formatter); if (text == null || text.length() == 0) { if (m.status == BaseDb.Status.DRAFT || m.status == BaseDb.Status.QUEUED || m.status == BaseDb.Status.SENDING) { - text = serviceContentSpanned(mActivity, R.drawable.ic_schedule_gray, R.string.processing); + text = serviceContentSpanned(mActivity, R.drawable.tinui_ic_schedule_gray, R.string.processing); } else if (m.status == BaseDb.Status.FAILED) { - text = serviceContentSpanned(mActivity, R.drawable.ic_error_gray, R.string.failed); + text = serviceContentSpanned(mActivity, R.drawable.tinui_ic_error_gray, R.string.failed); } else { - text = serviceContentSpanned(mActivity, R.drawable.ic_warning_gray, R.string.invalid_content); + text = serviceContentSpanned(mActivity, R.drawable.tinui_ic_warning_gray, R.string.invalid_content); } } @@ -583,7 +586,7 @@ public void onBindViewHolder(@NonNull final ViewHolder holder, int position) { } } else { if (holder.mAvatar != null) { - holder.mAvatar.setImageResource(R.drawable.ic_person_circle); + holder.mAvatar.setImageResource(R.drawable.tinui_ic_person_circle); } if (holder.mUserName != null) { Spannable span = new SpannableString(mActivity.getString(R.string.user_not_found)); @@ -925,7 +928,11 @@ static class ViewHolder extends RecyclerView.ViewHolder { mMeta = itemView.findViewById(R.id.messageMeta); mUserName = itemView.findViewById(R.id.userName); mSelected = itemView.findViewById(R.id.selected); - mRippleOverlay = itemView.findViewById(R.id.overlay); + if (itemView instanceof RippleFrameLayout) { + mRippleOverlay = ((RippleFrameLayout) itemView).getOverlayView(); + } else { + mRippleOverlay = null; + } mProgressContainer = itemView.findViewById(R.id.progressContainer); mProgress = itemView.findViewById(R.id.progressPanel); mProgressBar = itemView.findViewById(R.id.attachmentProgressBar); diff --git a/app/src/main/java/co/tinode/tindroid/MessagesFragment.java b/app/src/main/java/co/tinode/tindroid/MessagesFragment.java index 7bcecd4a0..fdd212543 100644 --- a/app/src/main/java/co/tinode/tindroid/MessagesFragment.java +++ b/app/src/main/java/co/tinode/tindroid/MessagesFragment.java @@ -25,17 +25,6 @@ import android.widget.TextView; import android.widget.Toast; -import com.google.android.material.bottomsheet.BottomSheetDialog; - -import java.io.File; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Locale; -import java.util.Map; - import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; @@ -49,22 +38,34 @@ import androidx.work.Data; import androidx.work.WorkInfo; import androidx.work.WorkManager; -import co.tinode.tindroid.db.BaseDb; -import co.tinode.tindroid.db.StoredTopic; -import co.tinode.tindroid.format.SendForwardedFormatter; -import co.tinode.tindroid.format.SendReplyFormatter; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.model.AccessChange; -import co.tinode.tinodesdk.model.Acs; -import co.tinode.tinodesdk.model.AcsHelper; -import co.tinode.tinodesdk.model.Drafty; -import co.tinode.tinodesdk.model.MetaSetSub; -import co.tinode.tinodesdk.model.MsgSetMeta; -import co.tinode.tinodesdk.model.ServerMessage; -import co.tinode.tinodesdk.model.Subscription; + +import com.google.android.material.bottomsheet.BottomSheetDialog; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Locale; +import java.util.Map; + +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.model.AccessChange; +import co.tinode.tinsdk.model.Acs; +import co.tinode.tinsdk.model.AcsHelper; +import co.tinode.tinsdk.model.Drafty; +import co.tinode.tinsdk.model.MetaSetSub; +import co.tinode.tinsdk.model.MsgSetMeta; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinsdk.model.Subscription; +import co.tinode.tinui.db.BaseDb; +import co.tinode.tinui.db.StoredTopic; +import co.tinode.tinui.format.SendForwardedFormatter; +import co.tinode.tinui.format.SendReplyFormatter; +import co.tinode.tinui.media.VxCard; /** * Fragment handling message display and message sending. @@ -161,7 +162,7 @@ public class MessagesFragment extends Fragment { args.putParcelable(AttachmentHandler.ARG_LOCAL_URI, data.getData()); } - args.putString(AttachmentHandler.ARG_OPERATION,AttachmentHandler.ARG_OPERATION_IMAGE); + args.putString(AttachmentHandler.ARG_OPERATION, AttachmentHandler.ARG_OPERATION_IMAGE); args.putString(AttachmentHandler.ARG_TOPIC_NAME, mTopicName); // Show attachment preview. activity.showFragment(MessageActivity.FRAGMENT_VIEW_IMAGE, args, true); @@ -171,7 +172,7 @@ public class MessagesFragment extends Fragment { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setHasOptionsMenu(true); - return inflater.inflate(R.layout.fragment_messages, container, false); + return inflater.inflate(R.layout.tindroid_fragment_messages, container, false); } @Override @@ -520,7 +521,7 @@ public void onDestroy() { @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { // Inflate the menu; this adds items to the action bar if it is present. - inflater.inflate(R.menu.menu_topic, menu); + inflater.inflate(R.menu.tindroid_menu_topic, menu); } @Override @@ -611,7 +612,7 @@ private void showChatInvitationDialog() { final BottomSheetDialog invitation = new BottomSheetDialog(activity); final LayoutInflater inflater = LayoutInflater.from(invitation.getContext()); - @SuppressLint("InflateParams") final View view = inflater.inflate(R.layout.dialog_accept_chat, null); + @SuppressLint("InflateParams") final View view = inflater.inflate(R.layout.tindroid_dialog_accept_chat, null); invitation.setContentView(view); invitation.setCancelable(false); invitation.setCanceledOnTouchOutside(false); diff --git a/app/src/main/java/co/tinode/tindroid/PasswordResetFragment.java b/app/src/main/java/co/tinode/tindroid/PasswordResetFragment.java index f9cde3022..bcfbd68f3 100644 --- a/app/src/main/java/co/tinode/tindroid/PasswordResetFragment.java +++ b/app/src/main/java/co/tinode/tindroid/PasswordResetFragment.java @@ -9,16 +9,17 @@ import android.widget.EditText; import android.widget.TextView; -import com.google.android.material.textfield.TextInputLayout; - import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.fragment.app.Fragment; import androidx.preference.PreferenceManager; -import co.tinode.tindroid.account.Utils; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.model.ServerMessage; + +import com.google.android.material.textfield.TextInputLayout; + +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinui.account.Utils; public class PasswordResetFragment extends Fragment implements View.OnClickListener { private static final String ARG_KEY = "method"; @@ -47,7 +48,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, bar.setTitle(R.string.request_pass_reset_title); } - View fragment = inflater.inflate(R.layout.fragment_pass_reset, container, false); + View fragment = inflater.inflate(R.layout.tindroid_fragment_pass_reset, container, false); fragment.findViewById(R.id.confirm).setOnClickListener(this); fragment.findViewById(R.id.cancel).setOnClickListener(v -> parent.showFragment(LoginActivity.FRAGMENT_LOGIN, null)); diff --git a/app/src/main/java/co/tinode/tindroid/SendToActivity.java b/app/src/main/java/co/tinode/tindroid/SendToActivity.java index 165fd24ec..eb8671c82 100644 --- a/app/src/main/java/co/tinode/tindroid/SendToActivity.java +++ b/app/src/main/java/co/tinode/tindroid/SendToActivity.java @@ -30,7 +30,7 @@ public void onCreate(Bundle savedInstanceState) { finish(); } - setContentView(R.layout.activity_send_to); + setContentView(R.layout.tindroid_activity_send_to); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); diff --git a/app/src/main/java/co/tinode/tindroid/SignUpFragment.java b/app/src/main/java/co/tinode/tindroid/SignUpFragment.java index 030219eb3..5533c36a8 100644 --- a/app/src/main/java/co/tinode/tindroid/SignUpFragment.java +++ b/app/src/main/java/co/tinode/tindroid/SignUpFragment.java @@ -13,8 +13,6 @@ import android.widget.EditText; import android.widget.ImageView; -import java.util.Map; - import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; @@ -24,15 +22,18 @@ import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.ViewModelProvider; import androidx.preference.PreferenceManager; -import co.tinode.tindroid.account.Utils; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.ServerResponseException; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.model.AuthScheme; -import co.tinode.tinodesdk.model.Credential; -import co.tinode.tinodesdk.model.MetaSetDesc; -import co.tinode.tinodesdk.model.ServerMessage; + +import java.util.Map; + +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.ServerResponseException; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.model.AuthScheme; +import co.tinode.tinsdk.model.Credential; +import co.tinode.tinsdk.model.MetaSetDesc; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinui.account.Utils; +import co.tinode.tinui.media.VxCard; /** * Fragment for managing registration of a new account. @@ -77,7 +78,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, bar.setTitle(R.string.sign_up); } - View fragment = inflater.inflate(R.layout.fragment_signup, container, false); + View fragment = inflater.inflate(R.layout.tindroid_fragment_signup, container, false); // Get avatar from the gallery or photo camera. fragment.findViewById(R.id.uploadAvatar).setOnClickListener(v -> { diff --git a/app/src/main/java/co/tinode/tindroid/SplashActivity.java b/app/src/main/java/co/tinode/tindroid/SplashActivity.java index 9fe943bef..90be781a4 100644 --- a/app/src/main/java/co/tinode/tindroid/SplashActivity.java +++ b/app/src/main/java/co/tinode/tindroid/SplashActivity.java @@ -4,7 +4,8 @@ import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; -import co.tinode.tindroid.db.BaseDb; + +import co.tinode.tinui.db.BaseDb; /** * Splash screen on startup diff --git a/app/src/main/java/co/tinode/tindroid/StartChatActivity.java b/app/src/main/java/co/tinode/tindroid/StartChatActivity.java index e69162d01..02d06fdca 100644 --- a/app/src/main/java/co/tinode/tindroid/StartChatActivity.java +++ b/app/src/main/java/co/tinode/tindroid/StartChatActivity.java @@ -31,7 +31,7 @@ public class StartChatActivity extends AppCompatActivity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_create); + setContentView(R.layout.tindroid_activity_create); Toolbar toolbar = findViewById(R.id.toolbar); diff --git a/app/src/main/java/co/tinode/tindroid/StartChatFragment.java b/app/src/main/java/co/tinode/tindroid/StartChatFragment.java index 9587ef82b..c7354e900 100644 --- a/app/src/main/java/co/tinode/tindroid/StartChatFragment.java +++ b/app/src/main/java/co/tinode/tindroid/StartChatFragment.java @@ -6,15 +6,15 @@ import android.view.View; import android.view.ViewGroup; -import com.google.android.material.tabs.TabLayout; -import com.google.android.material.tabs.TabLayoutMediator; - import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.viewpager2.adapter.FragmentStateAdapter; import androidx.viewpager2.widget.ViewPager2; +import com.google.android.material.tabs.TabLayout; +import com.google.android.material.tabs.TabLayoutMediator; + public class StartChatFragment extends Fragment { private static final int COUNT_OF_TABS = 3; private static final int TAB_SEARCH = 0; @@ -26,7 +26,7 @@ public class StartChatFragment extends Fragment { @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_create, container, false); + return inflater.inflate(R.layout.tindroid_fragment_create, container, false); } @Override diff --git a/app/src/main/java/co/tinode/tindroid/TindroidApp.java b/app/src/main/java/co/tinode/tindroid/TindroidApp.java index 9038356ca..01c298fb2 100644 --- a/app/src/main/java/co/tinode/tindroid/TindroidApp.java +++ b/app/src/main/java/co/tinode/tindroid/TindroidApp.java @@ -30,6 +30,15 @@ import android.text.TextUtils; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; +import androidx.lifecycle.ProcessLifecycleOwner; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import androidx.preference.PreferenceManager; +import androidx.work.WorkManager; + import com.google.firebase.crashlytics.FirebaseCrashlytics; import com.squareup.picasso.OkHttp3Downloader; import com.squareup.picasso.Picasso; @@ -39,19 +48,13 @@ import java.util.Date; import java.util.Map; -import androidx.annotation.NonNull; -import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleObserver; -import androidx.lifecycle.OnLifecycleEvent; -import androidx.lifecycle.ProcessLifecycleOwner; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import androidx.preference.PreferenceManager; -import androidx.work.WorkManager; -import co.tinode.tindroid.account.ContactsObserver; -import co.tinode.tindroid.account.Utils; -import co.tinode.tindroid.db.BaseDb; -import co.tinode.tinodesdk.ServerResponseException; -import co.tinode.tinodesdk.Tinode; +import co.tinode.tinsdk.ServerResponseException; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinui.BuildConfig; +import co.tinode.tinui.TinodeClient; +import co.tinode.tinui.account.ContactsObserver; +import co.tinode.tinui.account.Utils; +import co.tinode.tinui.db.BaseDb; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -156,11 +159,11 @@ public void onCreate() { PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0); sAppVersion = pi.versionName; if (TextUtils.isEmpty(sAppVersion)) { - sAppVersion = BuildConfig.VERSION_NAME; + sAppVersion = co.tinode.tinui.BuildConfig.VERSION_NAME; } sAppBuild = pi.versionCode; if (sAppBuild <= 0) { - sAppBuild = BuildConfig.VERSION_CODE; + sAppBuild = co.tinode.tinui.BuildConfig.VERSION_CODE; } } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Failed to retrieve app version", e); @@ -216,6 +219,9 @@ public void onAvailable(@NonNull Network network) { sUseTLS = pref.getBoolean("pref_useTLS", false); } + // Initialise tinode client + Cache.buildTinode(); + // Clear completed/failed upload tasks. WorkManager.getInstance(this).pruneWork(); diff --git a/app/src/main/java/co/tinode/tindroid/TopicGeneralFragment.java b/app/src/main/java/co/tinode/tindroid/TopicGeneralFragment.java index 83da20137..37d63c436 100644 --- a/app/src/main/java/co/tinode/tindroid/TopicGeneralFragment.java +++ b/app/src/main/java/co/tinode/tindroid/TopicGeneralFragment.java @@ -15,10 +15,6 @@ import android.widget.EditText; import android.widget.TextView; -import com.google.android.flexbox.FlexboxLayout; - -import java.util.Map; - import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; @@ -26,12 +22,17 @@ import androidx.appcompat.widget.AppCompatImageView; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.model.MsgSetMeta; -import co.tinode.tinodesdk.model.PrivateType; -import co.tinode.tinodesdk.model.ServerMessage; + +import com.google.android.flexbox.FlexboxLayout; + +import java.util.Map; + +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.model.MsgSetMeta; +import co.tinode.tinsdk.model.PrivateType; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinui.media.VxCard; /** * Topic general info fragment: p2p or a group topic. @@ -67,7 +68,7 @@ public class TopicGeneralFragment extends Fragment implements UiUtils.AvatarPrev @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_tpc_general, container, false); + return inflater.inflate(R.layout.tindroid_fragment_tpc_general, container, false); } @Override @@ -129,7 +130,7 @@ public void onResume() { String[] tags = mTopic.getTags(); if (tags != null) { for (String tag : tags) { - TextView label = (TextView) inflater.inflate(R.layout.tag, tagsView, false); + TextView label = (TextView) inflater.inflate(R.layout.tindroid_tag, tagsView, false); label.setText(tag); tagsView.addView(label); } @@ -155,7 +156,7 @@ private void showEditTags() { final AlertDialog.Builder builder = new AlertDialog.Builder(activity); @SuppressLint("InflateParams") final View editor = - LayoutInflater.from(builder.getContext()).inflate(R.layout.dialog_edit_tags, null); + LayoutInflater.from(builder.getContext()).inflate(R.layout.tindroid_dialog_edit_tags, null); builder.setView(editor).setTitle(R.string.tags_management); final EditText tagsEditor = editor.findViewById(R.id.editTags); @@ -214,7 +215,7 @@ public void notifyDataSetChanged() { @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.menu_save, menu); + inflater.inflate(R.menu.tindroid_menu_save, menu); super.onCreateOptionsMenu(menu, inflater); } diff --git a/app/src/main/java/co/tinode/tindroid/TopicInfoFragment.java b/app/src/main/java/co/tinode/tindroid/TopicInfoFragment.java index e49a66108..3f299618b 100644 --- a/app/src/main/java/co/tinode/tindroid/TopicInfoFragment.java +++ b/app/src/main/java/co/tinode/tindroid/TopicInfoFragment.java @@ -23,16 +23,11 @@ import android.widget.TextView; import android.widget.Toast; -import com.google.android.material.bottomsheet.BottomSheetDialog; - -import java.util.Collection; - import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.content.res.AppCompatResources; -import androidx.appcompat.widget.AppCompatTextView; import androidx.appcompat.widget.SwitchCompat; import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.Fragment; @@ -40,17 +35,21 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import co.tinode.tindroid.account.ContactsManager; -import co.tinode.tindroid.db.StoredSubscription; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tindroid.widgets.HorizontalListDivider; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.NotConnectedException; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Topic; -import co.tinode.tinodesdk.model.PrivateType; -import co.tinode.tinodesdk.model.ServerMessage; -import co.tinode.tinodesdk.model.Subscription; +import com.google.android.material.bottomsheet.BottomSheetDialog; + +import java.util.Collection; + +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.NotConnectedException; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.Topic; +import co.tinode.tinsdk.model.PrivateType; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinsdk.model.Subscription; +import co.tinode.tinui.account.ContactsManager; +import co.tinode.tinui.db.StoredSubscription; +import co.tinode.tinui.media.VxCard; +import co.tinode.tinui.widgets.HorizontalListDivider; /** * Topic Info fragment: p2p or a group topic. @@ -73,7 +72,7 @@ public class TopicInfoFragment extends Fragment implements MessageActivity.DataS @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_topic_info, container, false); + return inflater.inflate(R.layout.tindroid_fragment_topic_info, container, false); } @Override @@ -253,7 +252,7 @@ private void showMemberAction(final String topicTitle, final String userTitle, f activity.getString(R.string.placeholder_topic_title) : topicTitle; - final LinearLayout actions = (LinearLayout) View.inflate(activity, R.layout.dialog_member_actions, null); + final LinearLayout actions = (LinearLayout) View.inflate(activity, R.layout.tindroid_dialog_member_actions, null); final BottomSheetDialog dialog = new BottomSheetDialog(activity); ((TextView) actions.findViewById(R.id.title)).setText(TextUtils.isEmpty(userTitle) ? activity.getString(R.string.placeholder_contact_title) : @@ -363,11 +362,11 @@ private void notifyContentChanged() { title.setTypeface(null, Typeface.ITALIC); title.setTextIsSelectable(false); avatar.setImageResource(Topic.isP2PType(topicName) ? - R.drawable.ic_person_circle : R.drawable.ic_group_grey); + R.drawable.tinui_ic_person_circle : R.drawable.tinui_ic_group_grey); } if (mTopic.hasChannelAccess()) { - Drawable icon = AppCompatResources.getDrawable(activity, R.drawable.ic_channel); + Drawable icon = AppCompatResources.getDrawable(activity, R.drawable.tinui_ic_channel); if (icon != null) { icon.setBounds(0, 0, 64, 64); title.setCompoundDrawables(null, null, icon, null); @@ -399,7 +398,7 @@ private void notifyContentChanged() { @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { // Inflate the menu; this adds items to the action bar if it is present. - inflater.inflate(R.menu.menu_edit, menu); + inflater.inflate(R.menu.tindroid_menu_edit, menu); super.onCreateOptionsMenu(menu, inflater); } @@ -485,7 +484,7 @@ public long getItemId(int i) { @Override public MemberViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { // create a new view - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.group_member, parent, false); + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.tindroid_group_member, parent, false); return new MemberViewHolder(v); } diff --git a/app/src/main/java/co/tinode/tindroid/TopicSecurityFragment.java b/app/src/main/java/co/tinode/tindroid/TopicSecurityFragment.java index c56f66c76..2a61ec81a 100644 --- a/app/src/main/java/co/tinode/tindroid/TopicSecurityFragment.java +++ b/app/src/main/java/co/tinode/tindroid/TopicSecurityFragment.java @@ -12,20 +12,21 @@ import android.view.ViewGroup; import android.widget.TextView; -import java.util.HashMap; - import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.model.Acs; -import co.tinode.tinodesdk.model.Drafty; -import co.tinode.tinodesdk.model.ServerMessage; -import co.tinode.tinodesdk.model.Subscription; + +import java.util.HashMap; + +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.model.Acs; +import co.tinode.tinsdk.model.Drafty; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinsdk.model.Subscription; +import co.tinode.tinui.media.VxCard; /** * Topic permissions fragment: p2p or a group topic. @@ -46,7 +47,7 @@ public class TopicSecurityFragment extends Fragment implements MessageActivity.D @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_tpc_security, container, false); + return inflater.inflate(R.layout.tindroid_fragment_tpc_security, container, false); } @Override diff --git a/app/src/main/java/co/tinode/tindroid/UiUtils.java b/app/src/main/java/co/tinode/tindroid/UiUtils.java index d2f1533c2..055ff1684 100644 --- a/app/src/main/java/co/tinode/tindroid/UiUtils.java +++ b/app/src/main/java/co/tinode/tindroid/UiUtils.java @@ -13,11 +13,8 @@ import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; @@ -42,11 +39,19 @@ import android.widget.LinearLayout; import android.widget.Toast; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; +import androidx.core.content.res.ResourcesCompat; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; + import com.squareup.picasso.Picasso; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.net.URL; import java.text.DateFormat; import java.text.DecimalFormat; @@ -63,38 +68,27 @@ import java.util.TimerTask; import java.util.concurrent.Executors; -import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.widget.Toolbar; -import androidx.core.app.ActivityCompat; -import androidx.core.content.res.ResourcesCompat; -import androidx.exifinterface.media.ExifInterface; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; - -import co.tinode.tindroid.account.ContactsManager; -import co.tinode.tindroid.account.Utils; -import co.tinode.tindroid.db.BaseDb; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tindroid.widgets.LetterTileDrawable; -import co.tinode.tindroid.widgets.OnlineDrawable; -import co.tinode.tindroid.widgets.RoundImageDrawable; - -import co.tinode.tindroid.widgets.UrlLayerDrawable; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.MeTopic; -import co.tinode.tinodesdk.NotConnectedException; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.ServerResponseException; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.Topic; -import co.tinode.tinodesdk.model.Acs; -import co.tinode.tinodesdk.model.Credential; -import co.tinode.tinodesdk.model.PrivateType; -import co.tinode.tinodesdk.model.ServerMessage; +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.MeTopic; +import co.tinode.tinsdk.NotConnectedException; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.ServerResponseException; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.Topic; +import co.tinode.tinsdk.model.Acs; +import co.tinode.tinsdk.model.Credential; +import co.tinode.tinsdk.model.PrivateType; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinui.BuildConfig; +import co.tinode.tinui.ImageUtils; +import co.tinode.tinui.account.ContactsManager; +import co.tinode.tinui.account.Utils; +import co.tinode.tinui.db.BaseDb; +import co.tinode.tinui.media.VxCard; +import co.tinode.tinui.widgets.LetterTileDrawable; +import co.tinode.tinui.widgets.OnlineDrawable; +import co.tinode.tinui.widgets.RoundImageDrawable; +import co.tinode.tinui.widgets.UrlLayerDrawable; /** * Static utilities for UI support. @@ -117,18 +111,6 @@ public class UiUtils { // Length of quoted text. public static final int QUOTED_REPLY_LENGTH = 64; - // Maximum linear dimensions of images. - static final int MAX_BITMAP_SIZE = 1024; - public static final int AVATAR_THUMBNAIL_DIM = 36; // dip - // Image thumbnail in quoted replies and reply/forward previews. - public static final int REPLY_THUMBNAIL_DIM = 36; - // Image preview size in messages. - public static final int IMAGE_PREVIEW_DIM = 64; - public static final int MIN_AVATAR_SIZE = 8; - public static final int MAX_AVATAR_SIZE = 384; - // Maximum byte size of avatar sent in-band. - public static final int MAX_INBAND_AVATAR_SIZE = 4096; - // Default tag parameters private static final int DEFAULT_MIN_TAG_LENGTH = 4; private static final int DEFAULT_MAX_TAG_LENGTH = 96; @@ -235,7 +217,7 @@ private static void constructToolbarLogo(final Activity activity, final VxCard p if (online != null) { drawables.add(new OnlineDrawable(online)); - typing = (AnimationDrawable) ResourcesCompat.getDrawable(res, R.drawable.typing_indicator, null); + typing = (AnimationDrawable) ResourcesCompat.getDrawable(res, R.drawable.tinui_typing_indicator, null); if (typing != null) { typing.setOneShot(false); typing.setVisible(false, true); @@ -251,9 +233,9 @@ private static void constructToolbarLogo(final Activity activity, final VxCard p // Use thumbnail preview if available, otherwise use default gray disk. Drawable placeholder = bmp != null ? (new RoundImageDrawable(res, bmp)) : - ResourcesCompat.getDrawable(res, R.drawable.disk, null); + ResourcesCompat.getDrawable(res, R.drawable.tinui_disk, null); layers.setUrlByLayerId(res, LOGO_LAYER_AVATAR, Cache.getTinode().toAbsoluteURL(ref).toString(), - placeholder, R.drawable.ic_broken_image_round); + placeholder, R.drawable.tinui_ic_broken_image_round); } if (online != null) { @@ -545,119 +527,6 @@ interface AvatarPreviewer { void showAvatarPreview(Bundle args); } - /** - * Ensure that the bitmap is square and no larger than the given max size. - * @param bmp bitmap to scale - * @param size maximum linear size of the bitmap. - * @return scaled bitmap or original, it it does not need ot be cropped or scaled. - */ - @NonNull - public static Bitmap scaleSquareBitmap(@NonNull Bitmap bmp, int size) { - // Sanity check - size = Math.min(size, MAX_BITMAP_SIZE); - - int width = bmp.getWidth(); - int height = bmp.getHeight(); - - // Does it need to be scaled down? - if (width > size && height > size) { - // Scale down. - if (width > height) /* landscape */ { - width = width * size / height; - height = size; - } else /* portrait or square */ { - height = height * size / width; - width = size; - } - // Scale down. - bmp = Bitmap.createScaledBitmap(bmp, width, height, true); - } - size = Math.min(width, height); - - if (width != height) { - // Bitmap is not square. Chop the square from the middle. - bmp = Bitmap.createBitmap(bmp, (width - size) / 2, (height - size) / 2, - size, size); - } - - return bmp; - } - - /** - * Scale bitmap down to be under certain liner dimensions but no less than by the given amount. - * - * @param bmp bitmap to scale. - * @param maxWidth maximum allowed bitmap width. - * @param maxHeight maximum allowed bitmap height. - * @return scaled bitmap or original, it it does not need ot be scaled. - */ - @NonNull - public static Bitmap scaleBitmap(@NonNull Bitmap bmp, final int maxWidth, final int maxHeight) { - int width = bmp.getWidth(); - int height = bmp.getHeight(); - float factor = 1.0f; - // Calculate scaling factor due to large linear dimensions. - if (width >= height) { - if (width > maxWidth) { - factor = (float) width / maxWidth; - } - } else { - if (height > maxHeight) { - factor = (float) height / maxHeight; - } - } - // Scale down. - if (factor > 1.0) { - height /= factor; - width /= factor; - return Bitmap.createScaledBitmap(bmp, width, height, true); - } - return bmp; - } - - @NonNull - static Bitmap rotateBitmap(@NonNull Bitmap bmp, int orientation) { - Matrix matrix = new Matrix(); - switch (orientation) { - case ExifInterface.ORIENTATION_FLIP_HORIZONTAL: - matrix.setScale(-1, 1); - break; - case ExifInterface.ORIENTATION_ROTATE_180: - matrix.setRotate(180); - break; - case ExifInterface.ORIENTATION_FLIP_VERTICAL: - matrix.setRotate(180); - matrix.postScale(-1, 1); - break; - case ExifInterface.ORIENTATION_TRANSPOSE: - matrix.setRotate(90); - matrix.postScale(-1, 1); - break; - case ExifInterface.ORIENTATION_ROTATE_90: - matrix.setRotate(90); - break; - case ExifInterface.ORIENTATION_TRANSVERSE: - matrix.setRotate(-90); - matrix.postScale(-1, 1); - break; - case ExifInterface.ORIENTATION_ROTATE_270: - matrix.setRotate(-90); - break; - case ExifInterface.ORIENTATION_NORMAL: - default: - return bmp; - } - - try { - Bitmap rotated = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true); - bmp.recycle(); - return rotated; - } catch (OutOfMemoryError ex) { - Log.e(TAG, "Out of memory while rotating bitmap"); - return bmp; - } - } - static void acceptAvatar(final Activity activity, final ImageView avatarContainer, final Bitmap avatar) { if (activity == null || avatarContainer == null) { return; @@ -669,7 +538,7 @@ static void acceptAvatar(final Activity activity, final ImageView avatarContaine } avatarContainer.setImageDrawable(new RoundImageDrawable(avatarContainer.getResources(), - scaleSquareBitmap(avatar, MAX_AVATAR_SIZE))); + ImageUtils.scaleSquareBitmap(avatar, ImageUtils.MAX_AVATAR_SIZE))); } // Construct avatar from VxCard and set it to the provided ImageView. @@ -688,9 +557,9 @@ static void setAvatar(ImageView avatarView, VxCard pub, String address) { Picasso .get() .load(ref.toString()) - .resize(UiUtils.MAX_AVATAR_SIZE, UiUtils.MAX_AVATAR_SIZE) + .resize(ImageUtils.MAX_AVATAR_SIZE, ImageUtils.MAX_AVATAR_SIZE) .placeholder(local) - .error(R.drawable.ic_broken_image_round) + .error(R.drawable.tinui_ic_broken_image_round) .into(avatarView); } else { avatarView.setImageDrawable(local); @@ -714,87 +583,18 @@ static Drawable avatarDrawable(Context context, Bitmap bmp, String name, String } } - @NonNull - static ByteArrayInputStream bitmapToStream(@NonNull Bitmap bmp, String mimeType) { - return new ByteArrayInputStream(bitmapToBytes(bmp, mimeType)); - } - - @NonNull - public static byte[] bitmapToBytes(@NonNull Bitmap bmp, String mimeType) { - Bitmap.CompressFormat fmt; - if ("image/jpeg".equals(mimeType)) { - fmt = Bitmap.CompressFormat.JPEG; - } else { - fmt = Bitmap.CompressFormat.PNG; - } - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - bmp.compress(fmt, 70, bos); - byte[] bits = bos.toByteArray(); - try { - bos.close(); - } catch (IOException ignored) { - } - - return bits; - } - - /** - * Convert drawable to bitmap. - * - * @param drawable vector drawable to convert to bitmap - * @return bitmap extracted from the drawable. - */ - public static Bitmap bitmapFromDrawable(Drawable drawable) { - if (drawable instanceof BitmapDrawable) { - return ((BitmapDrawable) drawable).getBitmap(); - } - - Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), - drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); - - return bitmap; - } - - // Creates LayerDrawable of the right size with gray background and 'fg' in the middle. - // Used in chat bubbled to generate placeholder and error images for Picasso. - public static Drawable getPlaceholder(Context ctx, Drawable fg, Drawable bkg, int width, int height) { - Drawable filter; - if (bkg == null) { - // Uniformly gray background with rounded corners. - bkg = ResourcesCompat.getDrawable(ctx.getResources(), R.drawable.placeholder_image_bkg, null); - // Transparent filter. - filter = new ColorDrawable(0x00000000); - } else { - // Translucent filter. - filter = new ColorDrawable(0xCCCCCCCC); - } - - final int fgWidth = fg.getIntrinsicWidth(); - final int fgHeight = fg.getIntrinsicHeight(); - final LayerDrawable result = new LayerDrawable(new Drawable[]{bkg, filter, fg}); - result.setBounds(0, 0, width, height); - // Move foreground to the center of the drawable. - int dx = Math.max((width - fgWidth) / 2, 0); - int dy = Math.max((height - fgHeight) / 2, 0); - fg.setBounds(dx, dy, dx + fgWidth, dy + fgHeight); - return result; - } - public static void setMessageStatusIcon(ImageView holder, int status, int read, int recv) { if (status <= BaseDb.Status.SENDING.value) { - holder.setImageResource(R.drawable.ic_schedule); + holder.setImageResource(R.drawable.tinui_ic_schedule); } else if (status == BaseDb.Status.FAILED.value) { - holder.setImageResource(R.drawable.ic_warning); + holder.setImageResource(R.drawable.tinui_ic_warning); } else { if (read > 0) { - holder.setImageResource(R.drawable.ic_done_all2); + holder.setImageResource(R.drawable.tinui_ic_done_all2); } else if (recv > 0) { - holder.setImageResource(R.drawable.ic_done_all); + holder.setImageResource(R.drawable.tinui_ic_done_all); } else { - holder.setImageResource(R.drawable.ic_done); + holder.setImageResource(R.drawable.tinui_ic_done); } } } @@ -867,7 +667,7 @@ static void showEditPermissions(final Activity activity, final Topic topic, final AlertDialog.Builder builder = new AlertDialog.Builder(activity); final LayoutInflater inflater = LayoutInflater.from(builder.getContext()); @SuppressLint("InflateParams") - final LinearLayout editor = (LinearLayout) inflater.inflate(R.layout.dialog_edit_permissions, null); + final LinearLayout editor = (LinearLayout) inflater.inflate(R.layout.tindroid_dialog_edit_permissions, null); builder .setView(editor) .setTitle(R.string.edit_permissions); @@ -883,7 +683,7 @@ static void showEditPermissions(final Activity activity, final Topic topic, continue; } - CheckedTextView check = (CheckedTextView) inflater.inflate(R.layout.edit_one_permission, + CheckedTextView check = (CheckedTextView) inflater.inflate(R.layout.tindroid_edit_one_permission, editor, false); check.setChecked(mode.indexOf(c) >= 0); check.setText(permissionsMap[i]); @@ -1354,7 +1154,7 @@ static class AccessModeLabel { } } - static class ToastFailureListener extends PromisedReply.FailureListener { + static class ToastFailureListener implements PromisedReply.FailureListener { private final Activity mActivity; ToastFailureListener(Activity activity) { diff --git a/app/src/main/java/co/tinode/tindroid/account/Utils.java b/app/src/main/java/co/tinode/tindroid/account/Utils.java deleted file mode 100644 index e7500d4d8..000000000 --- a/app/src/main/java/co/tinode/tindroid/account/Utils.java +++ /dev/null @@ -1,217 +0,0 @@ -package co.tinode.tindroid.account; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.content.Context; -import android.content.SharedPreferences; -import android.provider.ContactsContract; -import android.provider.ContactsContract.Data; -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.preference.PreferenceManager; -import co.tinode.tindroid.Cache; -import co.tinode.tindroid.TindroidApp; -import co.tinode.tindroid.db.BaseDb; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.Topic; -import co.tinode.tinodesdk.model.MsgGetMeta; - -/** - * Constants and misc utils - */ -public class Utils { - // Account management constants - public static final String TOKEN_TYPE = "co.tinode.token"; - public static final String TOKEN_EXPIRATION_TIME = "co.tinode.token_expires"; - public static final String ACCOUNT_TYPE = "co.tinode.account"; - public static final String SYNC_AUTHORITY = "com.android.contacts"; - public static final String TINODE_IM_PROTOCOL = "Tinode"; - // Constants for accessing shared preferences - public static final String PREFS_HOST_NAME = "pref_hostName"; - public static final String PREFS_USE_TLS = "pref_useTLS"; - /** - * MIME-type used when storing a profile {@link ContactsContract.Data} entry. - */ - public static final String MIME_TINODE_PROFILE = - "vnd.android.cursor.item/vnd.co.tinode.im"; - public static final String DATA_PID = Data.DATA1; - static final String DATA_SUMMARY = Data.DATA2; - static final String DATA_DETAIL = Data.DATA3; - private static final String TAG = "Utils"; - - public static Account createAccount(String uid) { - return new Account(uid, ACCOUNT_TYPE); - } - - public static Account getSavedAccount(final AccountManager accountManager, - final @NonNull String uid) { - Account account = null; - - // Let's find out if we already have a suitable account. If one is not found, go to full login. It will create - // an account with suitable name. - final Account[] availableAccounts = accountManager.getAccountsByType(ACCOUNT_TYPE); - if (availableAccounts.length > 0) { - // Found some accounts, let's find the one with the right name - for (Account acc : availableAccounts) { - if (uid.equals(acc.name)) { - account = acc; - break; - } - } - } - - return account; - } - - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - private static boolean loginNow(Context context) { - String uid = BaseDb.getInstance().getUid(); - if (TextUtils.isEmpty(uid)) { - Log.w(TAG, "Data fetch failed: no login credentials"); - // Unknown if data is available, assuming it is. - return false; - } - - final AccountManager am = AccountManager.get(context); - final Account account = getSavedAccount(am, uid); - if (account == null) { - Log.w(TAG, "Data fetch failed: account not found"); - return false; - } - - final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); - String hostName = sharedPref.getString(Utils.PREFS_HOST_NAME, TindroidApp.getDefaultHostName(context)); - boolean tls = sharedPref.getBoolean(Utils.PREFS_USE_TLS, TindroidApp.getDefaultTLS()); - - final Tinode tinode = Cache.getTinode(); - - try { - - String token = AccountManager.get(context).blockingGetAuthToken(account, Utils.TOKEN_TYPE, false); - // Will return immediately if it's already connected. - tinode.connect(hostName, tls, true).getResult(); - tinode.loginToken(token).getResult(); - } catch (Exception ex) { - Log.w(TAG, "Failed to connect to server", ex); - return false; - } - - return true; - } - - /** - * Fetch messages (and maybe topic description and subscriptions) in background. - *

- * This method SHOULD NOT be called on UI thread. - * - * @param context context to use for resources. - * @param topicName name of the topic to sync. - * @param seq sequence ID of the new message to fetch. - * @return true if new data was available or data status was unknown, false if no data was available. - */ - public static boolean backgroundDataFetch(Context context, String topicName, int seq) { - Log.d(TAG, "Fetching messages for " + topicName); - - final Tinode tinode = Cache.getTinode(); - - // noinspection unchecked - ComTopic topic = (ComTopic) tinode.getTopic(topicName); - Topic.MetaGetBuilder builder; - if (topic == null) { - // New topic. Create it. - // noinspection unchecked - topic = (ComTopic) tinode.newTopic(topicName, null); - builder = topic.getMetaGetBuilder().withDesc().withSub(); - } else { - // Existing topic. - builder = topic.getMetaGetBuilder(); - } - - if (topic.isAttached()) { - Log.d(TAG, "Topic is already attached"); - // No need to fetch: topic is already subscribed and got data through normal channel. - // Assuming that data was available. - return true; - } - - boolean dataAvailable = false; - if (topic.getSeq() < seq) { - if (!loginNow(context)) { - return false; - } - dataAvailable = true; - PromisedReply result = null; - // Check if contacts have been synced already. - if (tinode.getTopicsUpdated() == null) { - // Background sync of contacts. - result = Cache.attachMeTopic(null); - } - - // Check again if topic has attached while we tried to connect. It does not guarantee that there - // is no race condition to subscribe. - if (!topic.isAttached()) { - // Fully asynchronous. We don't need to do anything with the result. - // The new data will be automatically saved. - topic.subscribe(null, builder.build()); - topic.getMeta(builder.reset().withLaterData(24).build()); - result = topic.getMeta(builder.reset().withLaterDel(24).build()); - topic.leave(); - } - if (result != null) { - try { - // Wait for result before disconnecting. - result.getResult(); - } catch (Exception ignored) { - } - } - tinode.disconnect(true); - } - return dataAvailable; - } - - /** - * Fetch description of a previously unknown topic or user in background. - * Fetch subscriptions for GRP topics. - *

- * This method SHOULD NOT be called on UI thread. - * - * @param context context to use for resources. - * @param topicName name of the topic to sync. - */ - public static void backgroundMetaFetch(Context context, String topicName) { - Log.d(TAG, "Fetching description for " + topicName); - - final Tinode tinode = Cache.getTinode(); - - if (tinode.getTopic(topicName) != null) { - // Ignoring notification for a known topic. - return; - } - - if (!loginNow(context)) { - // Failed to connect or to login. - return; - } - - // Fetch description without subscribing. - try { - // Check if contacts have been synced already. - if (tinode.getTopicsUpdated() == null) { - // Background sync of all contacts. - Cache.attachMeTopic(null).getResult(); - tinode.getMeTopic().leave(); - } - - // Request description, wait for result. Tinode will save new topic to DB. - tinode.getMeta(topicName, MsgGetMeta.desc()).getResult(); - } catch (Exception ex) { - Log.i(TAG, "Background Meta fetch failed", ex); - } - tinode.disconnect(true); - } -} diff --git a/app/src/main/java/co/tinode/tindroid/services/ContactsSyncAdapter.java b/app/src/main/java/co/tinode/tindroid/services/ContactsSyncAdapter.java index 2f53276fe..b54102274 100644 --- a/app/src/main/java/co/tinode/tindroid/services/ContactsSyncAdapter.java +++ b/app/src/main/java/co/tinode/tindroid/services/ContactsSyncAdapter.java @@ -1,5 +1,7 @@ package co.tinode.tindroid.services; +import static androidx.core.content.ContextCompat.checkSelfPermission; + import android.Manifest; import android.accounts.Account; import android.accounts.AccountManager; @@ -19,6 +21,9 @@ import android.util.Patterns; import android.util.SparseArray; +import androidx.annotation.NonNull; +import androidx.preference.PreferenceManager; + import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -28,25 +33,21 @@ import java.util.LinkedList; import java.util.List; -import androidx.annotation.NonNull; -import androidx.preference.PreferenceManager; import co.tinode.tindroid.Cache; import co.tinode.tindroid.TindroidApp; -import co.tinode.tindroid.account.ContactsManager; -import co.tinode.tindroid.account.Utils; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tinodesdk.PromisedReply; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.Topic; -import co.tinode.tinodesdk.model.MetaGetSub; -import co.tinode.tinodesdk.model.MetaSetDesc; -import co.tinode.tinodesdk.model.MsgGetMeta; -import co.tinode.tinodesdk.model.MsgSetMeta; -import co.tinode.tinodesdk.model.PrivateType; -import co.tinode.tinodesdk.model.ServerMessage; -import co.tinode.tinodesdk.model.Subscription; - -import static androidx.core.content.ContextCompat.checkSelfPermission; +import co.tinode.tinsdk.PromisedReply; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.Topic; +import co.tinode.tinsdk.model.MetaGetSub; +import co.tinode.tinsdk.model.MetaSetDesc; +import co.tinode.tinsdk.model.MsgGetMeta; +import co.tinode.tinsdk.model.MsgSetMeta; +import co.tinode.tinsdk.model.PrivateType; +import co.tinode.tinsdk.model.ServerMessage; +import co.tinode.tinsdk.model.Subscription; +import co.tinode.tinui.account.ContactsManager; +import co.tinode.tinui.account.Utils; +import co.tinode.tinui.media.VxCard; /** * Define a sync adapter for the app. @@ -170,7 +171,7 @@ private static String hash(String s) { try { // Create MD5 Hash - MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); + MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(s.getBytes()); byte[] messageDigest = digest.digest(); @@ -197,7 +198,7 @@ private static String hash(String s) { * . *

*

This is where we actually perform any work required to perform a sync. - * {@link android.content.AbstractThreadedSyncAdapter} guarantees that this will be called on a non-UI thread, + * {@link AbstractThreadedSyncAdapter} guarantees that this will be called on a non-UI thread, * so it is safe to peform blocking I/O here. *

*

The syncResult argument allows you to pass information back to the method that triggered diff --git a/app/src/main/java/co/tinode/tindroid/services/FBaseMessagingService.java b/app/src/main/java/co/tinode/tindroid/services/FBaseMessagingService.java index 1e4235db2..7f333372b 100644 --- a/app/src/main/java/co/tinode/tindroid/services/FBaseMessagingService.java +++ b/app/src/main/java/co/tinode/tindroid/services/FBaseMessagingService.java @@ -13,30 +13,31 @@ import android.text.TextUtils; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; +import androidx.core.content.ContextCompat; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; import java.util.Map; -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; -import androidx.core.content.ContextCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import co.tinode.tindroid.Cache; import co.tinode.tindroid.ChatsActivity; import co.tinode.tindroid.MessageActivity; import co.tinode.tindroid.R; import co.tinode.tindroid.UiUtils; -import co.tinode.tindroid.account.Utils; -import co.tinode.tindroid.format.FontFormatter; -import co.tinode.tindroid.media.VxCard; -import co.tinode.tindroid.widgets.LetterTileDrawable; -import co.tinode.tindroid.widgets.RoundImageDrawable; -import co.tinode.tinodesdk.ComTopic; -import co.tinode.tinodesdk.Tinode; -import co.tinode.tinodesdk.Topic; -import co.tinode.tinodesdk.User; -import co.tinode.tinodesdk.model.Drafty; +import co.tinode.tinsdk.ComTopic; +import co.tinode.tinsdk.Tinode; +import co.tinode.tinsdk.Topic; +import co.tinode.tinsdk.User; +import co.tinode.tinsdk.model.Drafty; +import co.tinode.tinui.account.Utils; +import co.tinode.tinui.format.FontFormatter; +import co.tinode.tinui.media.VxCard; +import co.tinode.tinui.widgets.LetterTileDrawable; +import co.tinode.tinui.widgets.RoundImageDrawable; /** * Receive and handle (e.g. show) a push notification message. @@ -179,7 +180,7 @@ public void onMessageReceived(RemoteMessage remoteMessage) { User sender = tinode.getUser(senderId); if (sender == null) { // If sender is not found, try to fetch description from the server. - Utils.backgroundMetaFetch(this, senderId); + Cache.backgroundMetaFetch(this, senderId); sender = tinode.getUser(senderId); } @@ -210,7 +211,7 @@ public void onMessageReceived(RemoteMessage remoteMessage) { String seqStr = data.get("seq"); if (seqStr != null) { // If there was no data to fetch, the notification does not need to be shown. - if (!Utils.backgroundDataFetch(getApplicationContext(), topicName, Integer.parseInt(seqStr))) { + if (!Cache.backgroundDataFetch(getApplicationContext(), topicName, Integer.parseInt(seqStr))) { Log.d(TAG, "No new data. Skipping notification."); return; } @@ -280,7 +281,7 @@ public void onMessageReceived(RemoteMessage remoteMessage) { } // Legitimate subscription to a new topic. - Utils.backgroundMetaFetch(getApplicationContext(), topicName); + Cache.backgroundMetaFetch(getApplicationContext(), topicName); title = getResources().getString(R.string.new_chat); if (tp == Topic.TopicType.P2P) { // P2P message @@ -372,7 +373,7 @@ private NotificationCompat.Builder composeNotification(String title, CharSequenc .setPriority(NotificationCompat.PRIORITY_HIGH) .setCategory(NotificationCompat.CATEGORY_MESSAGE) .setVisibility(NotificationCompat.VISIBILITY_PRIVATE) - .setSmallIcon(R.drawable.ic_icon_push) + .setSmallIcon(R.drawable.tinui_ic_icon_push) .setLargeIcon(avatar) .setColor(ContextCompat.getColor(this, R.color.colorNotificationBackground)) .setContentTitle(title) @@ -393,7 +394,7 @@ private NotificationCompat.Builder composeNotification(@NonNull RemoteMessage.No return notificationBuilder .setPriority(unwrapInteger(remote.getNotificationPriority(), NotificationCompat.PRIORITY_HIGH)) .setVisibility(unwrapInteger(remote.getVisibility(), NotificationCompat.VISIBILITY_PRIVATE)) - .setSmallIcon(resourceId(res, remote.getIcon(), R.drawable.ic_icon_push, "drawable", packageName)) + .setSmallIcon(resourceId(res, remote.getIcon(), R.drawable.tinui_ic_icon_push, "drawable", packageName)) .setColor(unwrapColor(remote.getColor(), ContextCompat.getColor(this, R.color.colorNotificationBackground))) .setContentTitle(locText(res, remote.getTitleLocalizationKey(), remote.getTitleLocalizationArgs(), remote.getTitle(), packageName)) diff --git a/app/src/main/java/co/tinode/tindroid/services/TinodeAccountService.java b/app/src/main/java/co/tinode/tindroid/services/TinodeAccountService.java index 748a302a2..fdb2ba29f 100644 --- a/app/src/main/java/co/tinode/tindroid/services/TinodeAccountService.java +++ b/app/src/main/java/co/tinode/tindroid/services/TinodeAccountService.java @@ -13,7 +13,7 @@ import android.util.Log; import co.tinode.tindroid.LoginActivity; -import co.tinode.tindroid.account.Utils; +import co.tinode.tinui.account.Utils; /** * Authenticator service: make Tinode login work nicely with the Android authentication system. diff --git a/app/src/main/res/anim/flip_in.xml b/app/src/main/res/anim/tinui_flip_in.xml similarity index 100% rename from app/src/main/res/anim/flip_in.xml rename to app/src/main/res/anim/tinui_flip_in.xml diff --git a/app/src/main/res/anim/flip_out.xml b/app/src/main/res/anim/tinui_flip_out.xml similarity index 100% rename from app/src/main/res/anim/flip_out.xml rename to app/src/main/res/anim/tinui_flip_out.xml diff --git a/app/src/main/res/color/button_background.xml b/app/src/main/res/color/tinui_button_background.xml similarity index 100% rename from app/src/main/res/color/button_background.xml rename to app/src/main/res/color/tinui_button_background.xml diff --git a/app/src/main/res/layout/activity_contacts.xml b/app/src/main/res/layout/tindroid_activity_contacts.xml similarity index 90% rename from app/src/main/res/layout/activity_contacts.xml rename to app/src/main/res/layout/tindroid_activity_contacts.xml index 9968cbb0b..f43a4b1a4 100644 --- a/app/src/main/res/layout/activity_contacts.xml +++ b/app/src/main/res/layout/tindroid_activity_contacts.xml @@ -7,7 +7,7 @@ android:orientation="vertical" tools:context=".ChatsActivity"> - + - + + tools:layout="@layout/tindroid_fragment_create" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/tindroid_activity_login.xml similarity index 81% rename from app/src/main/res/layout/activity_login.xml rename to app/src/main/res/layout/tindroid_activity_login.xml index d1df94b0c..6a052961d 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/tindroid_activity_login.xml @@ -7,12 +7,12 @@ android:orientation="vertical" tools:context=".LoginActivity"> - + + tools:layout="@layout/tindroid_fragment_login" /> diff --git a/app/src/main/res/layout/activity_messages.xml b/app/src/main/res/layout/tindroid_activity_messages.xml similarity index 84% rename from app/src/main/res/layout/activity_messages.xml rename to app/src/main/res/layout/tindroid_activity_messages.xml index d6027205b..4c5e9ff3b 100644 --- a/app/src/main/res/layout/activity_messages.xml +++ b/app/src/main/res/layout/tindroid_activity_messages.xml @@ -8,12 +8,12 @@ + layout="@layout/tindroid_toolbar" /> + tools:layout="@layout/tindroid_fragment_messages" /> diff --git a/app/src/main/res/layout/activity_send_to.xml b/app/src/main/res/layout/tindroid_activity_send_to.xml similarity index 90% rename from app/src/main/res/layout/activity_send_to.xml rename to app/src/main/res/layout/tindroid_activity_send_to.xml index f04414d0e..fdcac121f 100644 --- a/app/src/main/res/layout/activity_send_to.xml +++ b/app/src/main/res/layout/tindroid_activity_send_to.xml @@ -7,7 +7,7 @@ android:orientation="vertical" tools:context=".SendToActivity"> - + @@ -19,7 +19,7 @@ android:layout_width="48dp" android:layout_height="48dp" app:shapeAppearanceOverlay="@style/roundImageView" - app:srcCompat="@drawable/ic_person_circle" /> + app:srcCompat="@drawable/tinui_ic_person_circle" /> + app:srcCompat="@drawable/tinui_ic_circle" /> @@ -63,7 +63,7 @@ android:baseline="-2dp" android:contentDescription="@string/channel" android:visibility="gone" - app:srcCompat="@drawable/ic_channel" + app:srcCompat="@drawable/tinui_ic_channel" app:tint="?android:attr/textColorSecondary" /> + app:srcCompat="@drawable/tinui_ic_verified" /> + app:srcCompat="@drawable/tinui_ic_verified_user" /> + app:srcCompat="@drawable/tinui_ic_danger" /> @@ -161,7 +161,7 @@ android:paddingTop="2dp" android:visibility="gone" tools:ignore="ContentDescription,RtlSymmetry,SmallSp" - tools:src="@drawable/ic_done_all" /> + tools:src="@drawable/tinui_ic_done_all" /> + app:srcCompat="@drawable/tinui_ic_person_circle" /> + app:srcCompat="@drawable/tinui_ic_selected" /> + app:srcCompat="@drawable/tinui_ic_delete_forever" /> \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_about.xml b/app/src/main/res/layout/tindroid_dialog_about.xml similarity index 98% rename from app/src/main/res/layout/dialog_about.xml rename to app/src/main/res/layout/tindroid_dialog_about.xml index 7fde15e91..3f3c89863 100644 --- a/app/src/main/res/layout/dialog_about.xml +++ b/app/src/main/res/layout/tindroid_dialog_about.xml @@ -103,7 +103,7 @@ android:layout_height="128sp" android:layout_gravity="center" android:contentDescription="@string/app_name" - android:src="@drawable/logo_src" /> + android:src="@drawable/tinui_logo_src" /> + app:drawableStartCompat="@drawable/tinui_ic_person" /> + app:drawableStartCompat="@drawable/tinui_ic_chat_grey" /> + app:drawableStartCompat="@drawable/tinui_ic_checklist_grey" /> + app:drawableStartCompat="@drawable/tinui_ic_flag" /> + app:drawableStartCompat="@drawable/tinui_ic_exit_gray" /> + app:drawableStartCompat="@drawable/tinui_ic_block_gray" /> \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_password.xml b/app/src/main/res/layout/tindroid_dialog_password.xml similarity index 100% rename from app/src/main/res/layout/dialog_password.xml rename to app/src/main/res/layout/tindroid_dialog_password.xml diff --git a/app/src/main/res/layout/dialog_validate.xml b/app/src/main/res/layout/tindroid_dialog_validate.xml similarity index 100% rename from app/src/main/res/layout/dialog_validate.xml rename to app/src/main/res/layout/tindroid_dialog_validate.xml diff --git a/app/src/main/res/layout/edit_members.xml b/app/src/main/res/layout/tindroid_edit_members.xml similarity index 100% rename from app/src/main/res/layout/edit_members.xml rename to app/src/main/res/layout/tindroid_edit_members.xml diff --git a/app/src/main/res/layout/edit_one_permission.xml b/app/src/main/res/layout/tindroid_edit_one_permission.xml similarity index 100% rename from app/src/main/res/layout/edit_one_permission.xml rename to app/src/main/res/layout/tindroid_edit_one_permission.xml diff --git a/app/src/main/res/layout/fragment_acc_help.xml b/app/src/main/res/layout/tindroid_fragment_acc_help.xml similarity index 89% rename from app/src/main/res/layout/fragment_acc_help.xml rename to app/src/main/res/layout/tindroid_fragment_acc_help.xml index 8e9ef7288..3a93889ca 100644 --- a/app/src/main/res/layout/fragment_acc_help.xml +++ b/app/src/main/res/layout/tindroid_fragment_acc_help.xml @@ -18,7 +18,7 @@ android:drawablePadding="10dp" android:text="@string/contact_us" tools:text="Contact Us" - app:drawableStartCompat="@drawable/ic_contact_support" + app:drawableStartCompat="@drawable/tinui_ic_contact_support" app:drawableTint="@color/colorAccent" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_acc_notifications.xml b/app/src/main/res/layout/tindroid_fragment_acc_notifications.xml similarity index 97% rename from app/src/main/res/layout/fragment_acc_notifications.xml rename to app/src/main/res/layout/tindroid_fragment_acc_notifications.xml index bf843cf07..cdf647e4b 100644 --- a/app/src/main/res/layout/fragment_acc_notifications.xml +++ b/app/src/main/res/layout/tindroid_fragment_acc_notifications.xml @@ -24,7 +24,7 @@ android:layout_margin="4dp" /> - @@ -47,7 +47,7 @@ android:layout_margin="4dp" /> - diff --git a/app/src/main/res/layout/fragment_acc_personal.xml b/app/src/main/res/layout/tindroid_fragment_acc_personal.xml similarity index 93% rename from app/src/main/res/layout/fragment_acc_personal.xml rename to app/src/main/res/layout/tindroid_fragment_acc_personal.xml index 322990b63..318207895 100644 --- a/app/src/main/res/layout/fragment_acc_personal.xml +++ b/app/src/main/res/layout/tindroid_fragment_acc_personal.xml @@ -20,7 +20,7 @@ android:contentDescription="@string/avatar" android:focusable="true" app:shapeAppearanceOverlay="@style/roundImageView" - app:srcCompat="@drawable/disk" /> + app:srcCompat="@drawable/tinui_disk" />