diff --git a/app/build.gradle b/app/build.gradle index 015c555..067b912 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -65,6 +65,8 @@ dependencies { } implementation 'net.jpountz.lz4:lz4:1.3.0' implementation 'org.mapdb:elsa:3.0.0-M5' + + implementation 'com.github.instacart.truetime-android:library:3.4' } repositories { mavenCentral() diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/AppHelper.java b/app/src/main/java/io/github/chronosx88/influence/helpers/AppHelper.java index 99def7c..ab6797f 100644 --- a/app/src/main/java/io/github/chronosx88/influence/helpers/AppHelper.java +++ b/app/src/main/java/io/github/chronosx88/influence/helpers/AppHelper.java @@ -8,6 +8,11 @@ import net.tomp2p.dht.PeerDHT; import androidx.multidex.MultiDexApplication; import androidx.room.Room; + +import com.instacart.library.truetime.TrueTime; + +import java.io.IOException; + import io.github.chronosx88.influence.observable.MainObservable; /** @@ -33,6 +38,13 @@ public class AppHelper extends MultiDexApplication { .allowMainThreadQueries() .build(); preferences = getApplicationContext().getSharedPreferences("io.github.chronosx88.influence_preferences", MODE_PRIVATE); + new Thread(() -> { + try { + TrueTime.build().initialize(); + } catch (IOException e) { + e.printStackTrace(); + } + }).start(); } public static void storePeerID(String peerID1) { peerID = peerID1; } diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/ChatAdapter.java b/app/src/main/java/io/github/chronosx88/influence/helpers/ChatAdapter.java index 64e2b28..5ef7223 100644 --- a/app/src/main/java/io/github/chronosx88/influence/helpers/ChatAdapter.java +++ b/app/src/main/java/io/github/chronosx88/influence/helpers/ChatAdapter.java @@ -6,11 +6,18 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import java.text.DateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.SortedSet; +import java.util.TimeZone; import java.util.TreeSet; import androidx.annotation.NonNull; @@ -26,6 +33,7 @@ public class ChatAdapter extends RecyclerView.Adapter { private final Context context = AppHelper.getContext(); private ArrayList messages = new ArrayList<>(); + private static Comparator comparator = ((o1, o2) -> Long.compare(o1.timestamp, o2.timestamp)); @NonNull @Override @@ -45,11 +53,13 @@ public class ChatAdapter extends RecyclerView.Adapter { } } messages.add(message); + Collections.sort(messages, comparator); } } public void addMessages(List messages) { this.messages.addAll(messages); + Collections.sort(messages, comparator); } @Override @@ -58,9 +68,9 @@ public class ChatAdapter extends RecyclerView.Adapter { holder.messageText.setText(messages.get(position).text); // Setting message time (HOUR:MINUTE) - Calendar calendar = Calendar.getInstance(); - calendar.setTime(new Date(messages.get(position).timestamp)); - String time = calendar.get(Calendar.HOUR) + ":" + calendar.get(Calendar.MINUTE); + DateFormat dateFormat = DateFormat.getTimeInstance(DateFormat.SHORT); + dateFormat.setTimeZone(TimeZone.getDefault()); + String time = dateFormat.format(new Date(messages.get(position).timestamp)); holder.messageTime.setText(time); } @@ -90,4 +100,6 @@ public class ChatAdapter extends RecyclerView.Adapter { messageTime = itemView.findViewById(R.id.message_time); } } + + } diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/DataSerializerMapDB.kt b/app/src/main/java/io/github/chronosx88/influence/helpers/DataSerializerMapDB.kt index abe3037..65bfafb 100644 --- a/app/src/main/java/io/github/chronosx88/influence/helpers/DataSerializerMapDB.kt +++ b/app/src/main/java/io/github/chronosx88/influence/helpers/DataSerializerMapDB.kt @@ -39,7 +39,7 @@ class DataSerializerMapDB(private val signatureFactory: SignatureFactory) : Grou val acb = Unpooled.buffer() // store data to disk // header first - if(value.publicKey().equals(PeerBuilder.EMPTY_PUBLIC_KEY)) { + if(value.publicKey()!= null && value.publicKey().equals(PeerBuilder.EMPTY_PUBLIC_KEY)) { value.publicKey(null) } value.encodeHeader(acb, signatureFactory) diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/StorageMapDB.kt b/app/src/main/java/io/github/chronosx88/influence/helpers/StorageMapDB.kt index 85a9b52..0e30d84 100644 --- a/app/src/main/java/io/github/chronosx88/influence/helpers/StorageMapDB.kt +++ b/app/src/main/java/io/github/chronosx88/influence/helpers/StorageMapDB.kt @@ -49,7 +49,7 @@ class StorageMapDB(peerId: Number160, path : File, signatureFactory: SignatureFa private val responsibilityMap: BTreeMap private val responsibilityMapRev: BTreeMap> - private val db: DB = DBMaker.fileDB(path).closeOnJvmShutdown().make() + private val db: DB = DBMaker.fileDB(path).transactionEnable().closeOnJvmShutdown().make() private val storageCheckIntervalMillis: Int = 60 * 1000 init { diff --git a/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.java b/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.java deleted file mode 100644 index 3031dac..0000000 --- a/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.github.chronosx88.influence.presenters; - -import android.widget.Toast; - -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import io.github.chronosx88.influence.contracts.CoreContracts; -import io.github.chronosx88.influence.contracts.observer.IObserver; -import io.github.chronosx88.influence.helpers.AppHelper; -import io.github.chronosx88.influence.helpers.LocalDBWrapper; -import io.github.chronosx88.influence.helpers.actions.NetworkActions; -import io.github.chronosx88.influence.helpers.actions.UIActions; -import io.github.chronosx88.influence.logic.ChatLogic; -import io.github.chronosx88.influence.models.roomEntities.ChatEntity; -import io.github.chronosx88.influence.models.roomEntities.MessageEntity; - -public class ChatPresenter implements CoreContracts.IChatPresenterContract, IObserver { - private CoreContracts.IChatLogicContract logic; - private CoreContracts.IChatViewContract view; - private ChatEntity chatEntity; - private String chatID; - private Gson gson; - - public ChatPresenter(CoreContracts.IChatViewContract view, String chatID) { - this.logic = new ChatLogic(LocalDBWrapper.getChatByChatID(chatID)); - this.view = view; - this.chatID = chatID; - this.chatEntity = LocalDBWrapper.getChatByChatID(chatID); - - AppHelper.getObservable().register(this); - gson = new Gson(); - } - - @Override - public void sendMessage(String text) { - MessageEntity message = LocalDBWrapper.createMessageEntry(NetworkActions.TEXT_MESSAGE, UUID.randomUUID().toString(), chatID, AppHelper.getPeerID(), AppHelper.getPeerID(), System.currentTimeMillis(), text, false, false); - logic.sendMessage(message); - view.updateMessageList(message); - } - - @Override - public void handleEvent(JsonObject object) { - switch (object.get("action").getAsInt()) { - case UIActions.MESSAGE_RECEIVED: { - JsonArray jsonArray = object.getAsJsonArray("additional"); - if(!jsonArray.get(0).getAsString().equals(chatID)) { - return; - } - MessageEntity messageEntity = LocalDBWrapper.getMessageByID(jsonArray.get(1).getAsString()); - view.updateMessageList(messageEntity); - break; - } - - case UIActions.NODE_IS_OFFLINE: { - Toast.makeText(AppHelper.getContext(), "Нода не запущена!", Toast.LENGTH_SHORT).show(); - break; - } - } - } - - @Override - public void updateAdapter() { - List entities = LocalDBWrapper.getMessagesByChatID(chatID); - view.updateMessageList(entities == null ? new ArrayList<>() : entities); - } - - @Override - public void onDestroy() { - logic.stopTrackingForNewMsgs(); - } -} diff --git a/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.kt b/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.kt new file mode 100644 index 0000000..a81e494 --- /dev/null +++ b/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.kt @@ -0,0 +1,70 @@ +package io.github.chronosx88.influence.presenters + +import android.widget.Toast + +import com.google.gson.Gson +import com.google.gson.JsonObject +import com.instacart.library.truetime.TrueTime + +import java.io.IOException +import java.util.ArrayList +import java.util.UUID + +import io.github.chronosx88.influence.contracts.CoreContracts +import io.github.chronosx88.influence.contracts.observer.IObserver +import io.github.chronosx88.influence.helpers.AppHelper +import io.github.chronosx88.influence.helpers.LocalDBWrapper +import io.github.chronosx88.influence.helpers.actions.NetworkActions +import io.github.chronosx88.influence.helpers.actions.UIActions +import io.github.chronosx88.influence.logic.ChatLogic +import io.github.chronosx88.influence.models.roomEntities.ChatEntity +import org.jetbrains.anko.doAsync +import org.jetbrains.anko.doAsyncResult + +class ChatPresenter(private val view: CoreContracts.IChatViewContract, private val chatID: String) : CoreContracts.IChatPresenterContract, IObserver { + private val logic: CoreContracts.IChatLogicContract + private val chatEntity: ChatEntity? + private val gson: Gson + + init { + this.logic = ChatLogic(LocalDBWrapper.getChatByChatID(chatID)!!) + this.chatEntity = LocalDBWrapper.getChatByChatID(chatID) + + AppHelper.getObservable().register(this) + gson = Gson() + } + + override fun sendMessage(text: String) { + doAsync { + val message = LocalDBWrapper.createMessageEntry(NetworkActions.TEXT_MESSAGE, UUID.randomUUID().toString(), chatID, AppHelper.getPeerID(), AppHelper.getPeerID(), TrueTime.now().time, text, false, false) + logic.sendMessage(message!!) + view.updateMessageList(message) + } + } + + override fun handleEvent(obj: JsonObject) { + when (obj.get("action").asInt) { + UIActions.MESSAGE_RECEIVED -> { + val jsonArray = obj.getAsJsonArray("additional") + if (jsonArray.get(0).asString != chatID) { + return + } + val messageEntity = LocalDBWrapper.getMessageByID(jsonArray.get(1).asString) + view.updateMessageList(messageEntity!!) + } + + UIActions.NODE_IS_OFFLINE -> { + Toast.makeText(AppHelper.getContext(), "Нода не запущена!", Toast.LENGTH_SHORT).show() + } + } + } + + override fun updateAdapter() { + val entities = LocalDBWrapper.getMessagesByChatID(chatID) + view.updateMessageList(entities ?: ArrayList()) + } + + override fun onDestroy() { + logic.stopTrackingForNewMsgs() + } +} diff --git a/app/src/main/java/io/github/chronosx88/influence/views/ChatActivity.kt b/app/src/main/java/io/github/chronosx88/influence/views/ChatActivity.kt index 1d0a067..5101141 100644 --- a/app/src/main/java/io/github/chronosx88/influence/views/ChatActivity.kt +++ b/app/src/main/java/io/github/chronosx88/influence/views/ChatActivity.kt @@ -49,7 +49,6 @@ class ChatActivity : AppCompatActivity(), CoreContracts.IChatViewContract { } presenter!!.sendMessage(messageTextEdit!!.text.toString()) messageTextEdit!!.setText("") - messageList!!.scrollToPosition(chatAdapter!!.itemCount - 1) } contactUsernameTextView!!.text = intent.getStringExtra("contactUsername") messageList!!.scrollToPosition(chatAdapter!!.itemCount - 1) @@ -58,6 +57,7 @@ class ChatActivity : AppCompatActivity(), CoreContracts.IChatViewContract { override fun updateMessageList(message: MessageEntity) { runOnUiThread { chatAdapter!!.addMessage(message) + messageList!!.scrollToPosition(chatAdapter!!.itemCount - 1) chatAdapter!!.notifyDataSetChanged() } } @@ -65,6 +65,7 @@ class ChatActivity : AppCompatActivity(), CoreContracts.IChatViewContract { override fun updateMessageList(messages: List) { runOnUiThread { chatAdapter!!.addMessages(messages) + messageList!!.scrollToPosition(chatAdapter!!.itemCount - 1) chatAdapter!!.notifyDataSetChanged() } }