From d761a2ee2081fde9b6779fc9a5b54969160aee68 Mon Sep 17 00:00:00 2001 From: Zlatin Balevsky Date: Mon, 28 Feb 2022 18:04:46 +0000 Subject: [PATCH] chat favorites --- gui/griffon-app/conf/Config.groovy | 5 + .../com/muwire/gui/MainFrameController.groovy | 10 ++ .../gui/chat/ChatFavoritesController.groovy | 69 ++++++++++++ gui/griffon-app/i18n/messages.properties | 14 +++ .../muwire/gui/chat/ChatFavoritesModel.groovy | 10 ++ .../views/com/muwire/gui/MainFrameView.groovy | 22 ++-- .../muwire/gui/chat/ChatFavoritesView.groovy | 100 ++++++++++++++++++ .../com/muwire/gui/chat/ChatFavorite.groovy | 13 +++ .../com/muwire/gui/chat/ChatFavorites.groovy | 53 ++++++++++ 9 files changed, 290 insertions(+), 6 deletions(-) create mode 100644 gui/griffon-app/controllers/com/muwire/gui/chat/ChatFavoritesController.groovy create mode 100644 gui/griffon-app/models/com/muwire/gui/chat/ChatFavoritesModel.groovy create mode 100644 gui/griffon-app/views/com/muwire/gui/chat/ChatFavoritesView.groovy create mode 100644 gui/src/main/groovy/com/muwire/gui/chat/ChatFavorite.groovy create mode 100644 gui/src/main/groovy/com/muwire/gui/chat/ChatFavorites.groovy diff --git a/gui/griffon-app/conf/Config.groovy b/gui/griffon-app/conf/Config.groovy index fa9d26d4..05a4556d 100644 --- a/gui/griffon-app/conf/Config.groovy +++ b/gui/griffon-app/conf/Config.groovy @@ -228,4 +228,9 @@ mvcGroups { view = 'com.muwire.gui.tools.RuleWizardView' controller = 'com.muwire.gui.tools.RuleWizardController' } + 'chat-favorites' { + model = 'com.muwire.gui.chat.ChatFavoritesModel' + view = 'com.muwire.gui.chat.ChatFavoritesView' + controller = 'com.muwire.gui.chat.ChatFavoritesController' + } } diff --git a/gui/griffon-app/controllers/com/muwire/gui/MainFrameController.groovy b/gui/griffon-app/controllers/com/muwire/gui/MainFrameController.groovy index 70bece5c..926c6a4a 100644 --- a/gui/griffon-app/controllers/com/muwire/gui/MainFrameController.groovy +++ b/gui/griffon-app/controllers/com/muwire/gui/MainFrameController.groovy @@ -1043,6 +1043,16 @@ class MainFrameController { } else mvcGroup.getChildrenGroups().get(p.getHumanReadableName()).model.connect() } + + @ControllerAction + void chatFavorites() { + if (application.getMvcGroupManager().findGroup("chat-favorites") != null) + return + + def params = [:] + params.chatFavorites = view.chatFavorites + mvcGroup.createMVCGroup("chat-favorites", params) + } void saveMuWireSettings() { core.saveMuSettings() diff --git a/gui/griffon-app/controllers/com/muwire/gui/chat/ChatFavoritesController.groovy b/gui/griffon-app/controllers/com/muwire/gui/chat/ChatFavoritesController.groovy new file mode 100644 index 00000000..827c53a7 --- /dev/null +++ b/gui/griffon-app/controllers/com/muwire/gui/chat/ChatFavoritesController.groovy @@ -0,0 +1,69 @@ +package com.muwire.gui.chat + +import com.muwire.core.Persona +import griffon.core.artifact.GriffonController +import griffon.core.controller.ControllerAction +import griffon.inject.MVCMember +import griffon.metadata.ArtifactProviderFor +import net.i2p.data.Base64 + +import javax.annotation.Nonnull +import javax.swing.JOptionPane + +import static com.muwire.gui.Translator.trans + +@ArtifactProviderFor(GriffonController) +class ChatFavoritesController { + @MVCMember @Nonnull + ChatFavoritesModel model + @MVCMember @Nonnull + ChatFavoritesView view + + @ControllerAction + void addAction() { + String address = JOptionPane.showInputDialog(trans("COPY_PASTE_SERVER_ADDRESS")) + if (address == null) + return + Persona p + try { + p = new Persona(new ByteArrayInputStream(Base64.decode(address))) + } catch (Exception bad) { + JOptionPane.showMessageDialog(null, trans("INVALID_SERVER_ADDRESS"), trans("INVALID_SERVER_ADDRESS"), JOptionPane.ERROR_MESSAGE) + return + } + + def newFavorite = new ChatFavorite(p, false) + model.chatFavorites. favorites << newFavorite + model.chatFavorites.save() + view.refreshTable() + + } + + @ControllerAction + void deleteAction() { + List selected = view.selectedFavorites() + if (selected.isEmpty()) + return + + model.chatFavorites.favorites.removeAll(selected) + model.chatFavorites.save() + view.refreshTable() + } + + @ControllerAction + void connectAction() { + List selected = view.selectedFavorites() + if (selected.isEmpty()) + return + + for (ChatFavorite cf : selected) { + model.chatFavorites.connect(cf.address) + } + } + + @ControllerAction + void closeAction() { + view.window.setVisible(false) + mvcGroup.destroy() + } +} diff --git a/gui/griffon-app/i18n/messages.properties b/gui/griffon-app/i18n/messages.properties index 8728d9f1..cb82a0bf 100644 --- a/gui/griffon-app/i18n/messages.properties +++ b/gui/griffon-app/i18n/messages.properties @@ -220,6 +220,7 @@ REVIEW=Review START_CHAT_SERVER=Start Chat Server STOP_CHAT_SERVER=Stop Chat Server CONNECT_TO_REMOTE_SERVER=Connect To Remote Server +FAVORITE_SERVERS=Favorite Servers # Bottom strip COPY_SHORT=Copy Short @@ -677,6 +678,13 @@ PUBLISH_PREVIEW_TITLE=Preview files to be published PUBLISH_PREVIEW_TO_PUBLISH=List of files to be published now PUBLISH_PREVIEW_ALREADY_PUBLISHED=List of files already published +## Favorite servers window +CHAT_SERVERS_TITLE=Chat servers address book +CHAT_SERVERS_STARTUP_CONNECT=Auto Connect +CHAT_SERVERS_ADD=Add +CHAT_SERVERS_DELETE=Delete +CHAT_SERVERS_CONNECT=Connect + ## Tooltips TOOLTIP_FILE_FEED_DISABLED=Your file feed is disabled @@ -764,6 +772,7 @@ TOOLTIP_MESSAGES_COMPOSE=Compose a new message TOOLTIP_CHAT_START_CHAT_SERVER=Start your local chat server TOOLTIP_CHAT_STOP_CHAT_SERVER=Stop your local chat server TOOLTIP_CHAT_CONNECT=Connect to a remote chat server +TOOLTIP_CHAT_FAVORITE_SERVERS=Your address book of chat servers ### Tooltips for the Contacts tab TOOLTIP_CONTACTS_ADD_CONTACT=Add a new contact @@ -835,5 +844,10 @@ TOOLTIP_RESTART=Update and restart MuWire TOOLTIP_CLOSE_TAB=Close tab TOOLTIP_REPEAT_SEARCH=Repeat search +### Tooltips for chat favorites +TOOLTIP_CHAT_SERVERS_ADD=Add chat server to address book +TOOLTIP_CHAT_SERVERS_DELETE=Delete chat server from address book +TOOLTIP_CHAT_SERVERS_CONNECT=Connect to server now + ## Test string TEST_PLURALIZABLE_STRING={count, plural, one {You have {count} item.} other {You have {count} items.}} diff --git a/gui/griffon-app/models/com/muwire/gui/chat/ChatFavoritesModel.groovy b/gui/griffon-app/models/com/muwire/gui/chat/ChatFavoritesModel.groovy new file mode 100644 index 00000000..d62eeb36 --- /dev/null +++ b/gui/griffon-app/models/com/muwire/gui/chat/ChatFavoritesModel.groovy @@ -0,0 +1,10 @@ +package com.muwire.gui.chat + +import griffon.core.artifact.GriffonModel +import griffon.metadata.ArtifactProviderFor + +@ArtifactProviderFor(GriffonModel) +class ChatFavoritesModel { + + ChatFavorites chatFavorites +} diff --git a/gui/griffon-app/views/com/muwire/gui/MainFrameView.groovy b/gui/griffon-app/views/com/muwire/gui/MainFrameView.groovy index cf75a9ec..a82b30fc 100644 --- a/gui/griffon-app/views/com/muwire/gui/MainFrameView.groovy +++ b/gui/griffon-app/views/com/muwire/gui/MainFrameView.groovy @@ -4,6 +4,7 @@ import com.muwire.core.messenger.MWMessage import com.muwire.core.messenger.Messenger import com.muwire.core.messenger.UIMessageMovedEvent import com.muwire.core.trust.TrustLevel +import com.muwire.gui.chat.ChatFavorites import griffon.core.GriffonApplication import griffon.core.mvc.MVCGroup @@ -97,6 +98,7 @@ class MainFrameView { UISettings settings ChatNotificator chatNotificator + ChatFavorites chatFavorites JTable collectionsTable def lastCollectionSortEvent @@ -740,12 +742,19 @@ class MainFrameView { borderLayout() tabbedPane(id : "chat-tabs", constraints : BorderLayout.CENTER) panel(constraints : BorderLayout.SOUTH) { - button(text : trans("START_CHAT_SERVER"), toolTipText: trans("TOOLTIP_CHAT_START_CHAT_SERVER"), - enabled : bind {!model.chatServerRunning}, startChatServerAction) - button(text : trans("STOP_CHAT_SERVER"), toolTipText: trans("TOOLTIP_CHAT_STOP_CHAT_SERVER"), - enabled : bind {model.chatServerRunning}, stopChatServerAction) - button(text : trans("CONNECT_TO_REMOTE_SERVER"), toolTipText: trans("TOOLTIP_CHAT_CONNECT"), - connectChatServerAction) + gridLayout(rows : 1, cols : 2) + panel (border: etchedBorder()) { + button(text: trans("START_CHAT_SERVER"), toolTipText: trans("TOOLTIP_CHAT_START_CHAT_SERVER"), + enabled: bind { !model.chatServerRunning }, startChatServerAction) + button(text: trans("STOP_CHAT_SERVER"), toolTipText: trans("TOOLTIP_CHAT_STOP_CHAT_SERVER"), + enabled: bind { model.chatServerRunning }, stopChatServerAction) + } + panel (border: etchedBorder()) { + button(text: trans("CONNECT_TO_REMOTE_SERVER"), toolTipText: trans("TOOLTIP_CHAT_CONNECT"), + connectChatServerAction) + button(text : trans("FAVORITE_SERVERS"), toolTipText: trans("TOOLTIP_CHAT_FAVORITE_SERVERS"), + chatFavoritesAction) + } } } } @@ -786,6 +795,7 @@ class MainFrameView { chatNotificator = new ChatNotificator(application.getMvcGroupManager(), (Window)application.getWindowManager().findWindow("main-frame"), (Image) builder.imageIcon("/comment.png").image) + chatFavorites = new ChatFavorites(application) collectionsTable = builder.getVariable("collections-table") collectionFilesTable = builder.getVariable("items-table") diff --git a/gui/griffon-app/views/com/muwire/gui/chat/ChatFavoritesView.groovy b/gui/griffon-app/views/com/muwire/gui/chat/ChatFavoritesView.groovy new file mode 100644 index 00000000..67bb279b --- /dev/null +++ b/gui/griffon-app/views/com/muwire/gui/chat/ChatFavoritesView.groovy @@ -0,0 +1,100 @@ +package com.muwire.gui.chat + +import griffon.core.artifact.GriffonView +import griffon.inject.MVCMember +import griffon.metadata.ArtifactProviderFor +import org.intellij.lang.annotations.JdkConstants + +import javax.annotation.Nonnull +import javax.swing.DefaultCellEditor +import javax.swing.JCheckBox +import javax.swing.JFrame +import javax.swing.JTable +import javax.swing.ListSelectionModel +import javax.swing.event.CellEditorListener +import javax.swing.event.ChangeEvent +import java.awt.BorderLayout +import java.awt.event.WindowAdapter +import java.awt.event.WindowEvent + +import static com.muwire.gui.Translator.trans + +@ArtifactProviderFor(GriffonView) +class ChatFavoritesView { + @MVCMember @Nonnull + FactoryBuilderSupport builder + @MVCMember @Nonnull + ChatFavoritesModel model + + JFrame window + private JTable favoritesTable + + void initUI() { + def mainFrame = application.windowManager.findWindow("main-frame") + int rowHeight = application.context.get("row-height") + + window = builder.frame(visible : false, locationRelativeTo: mainFrame, + defaultCloseOperation: JFrame.DISPOSE_ON_CLOSE, + iconImage: builder.imageIcon("/MuWire-48x48.png").image, + title: trans("CHAT_SERVERS_TITLE")) { + borderLayout() + scrollPane(constraints : BorderLayout.CENTER) { + favoritesTable = table(autoCreateRowSorter : true, rowHeight : rowHeight) { + tableModel(list: model.chatFavorites.favorites) { + closureColumn(header: trans("SERVER"), type: String, + read : {ChatFavorite cf -> cf.address.getHumanReadableName()}) + closureColumn(header: trans("CHAT_SERVERS_STARTUP_CONNECT"), preferredWidth: 50, + type: Boolean, + read : {ChatFavorite cf -> cf.autoConnect}, + write: checkBoxEditor) + } + } + } + panel (constraints: BorderLayout.SOUTH) { + button(text : trans("CHAT_SERVERS_ADD"), toolTipText : trans("TOOLTIP_CHAT_SERVERS_ADD"), + addAction) + button(text : trans("CHAT_SERVERS_DELETE"), toolTipText: trans("TOOLTIP_CHAT_SERVERS_DELETE"), + deleteAction) + button(text : trans("CHAT_SERVERS_CONNECT"), toolTipText: trans("TOOLTIP_CHAT_SERVERS_CONNECT"), + connectAction) + button(text : trans("CLOSE"), closeAction) + } + } + } + + void refreshTable() { + favoritesTable.model.fireTableDataChanged() + } + + List selectedFavorites() { + int [] rows = favoritesTable.getSelectedRows() + if (rows.length == 0) + return Collections.emptyList() + + for (int i = 0; i < rows.length; i++) + rows[i] = favoritesTable.rowSorter.convertRowIndexToModel(rows[i]) + + List rv = [] + for (int i : rows) + rv << model.chatFavorites.favorites[i] + rv + } + + void mvcGroupInit(Map args) { + + favoritesTable.selectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) + + window.addWindowListener( new WindowAdapter() { + void windowClosed(WindowEvent event) { + mvcGroup.destroy() + } + }) + window.pack() + window.setVisible(true) + } + + def checkBoxEditor = {ChatFavorite cf, Boolean newValue -> + cf.autoConnect = newValue + model.chatFavorites.save() + } +} diff --git a/gui/src/main/groovy/com/muwire/gui/chat/ChatFavorite.groovy b/gui/src/main/groovy/com/muwire/gui/chat/ChatFavorite.groovy new file mode 100644 index 00000000..cb7d82cd --- /dev/null +++ b/gui/src/main/groovy/com/muwire/gui/chat/ChatFavorite.groovy @@ -0,0 +1,13 @@ +package com.muwire.gui.chat + +import com.muwire.core.Persona + +class ChatFavorite { + final Persona address + boolean autoConnect + + ChatFavorite(Persona address, boolean autoConnect) { + this.address = address + this.autoConnect = autoConnect + } +} diff --git a/gui/src/main/groovy/com/muwire/gui/chat/ChatFavorites.groovy b/gui/src/main/groovy/com/muwire/gui/chat/ChatFavorites.groovy new file mode 100644 index 00000000..ba1c2e7d --- /dev/null +++ b/gui/src/main/groovy/com/muwire/gui/chat/ChatFavorites.groovy @@ -0,0 +1,53 @@ +package com.muwire.gui.chat + +import com.muwire.core.Persona +import griffon.core.GriffonApplication +import groovy.json.JsonOutput +import groovy.json.JsonSlurper +import net.i2p.data.Base64 + +class ChatFavorites { + + private File favoritesFile + final List favorites = [] + private def controller + + ChatFavorites(GriffonApplication application) { + application.addPropertyChangeListener("core", { + favoritesFile = new File(it.getNewValue().home, "chat.json") + load() + controller = application.mvcGroupManager.findGroup("MainFrame").getController() + favorites.stream().filter({it.autoConnect}).forEach { + controller.startChat(it.address) + } + }) + } + + private void load() { + if (!favoritesFile.exists()) + return + JsonSlurper slurper = new JsonSlurper() + favoritesFile.eachLine { + def json = slurper.parseText(it) + byte [] personaBytes = Base64.decode(json.address) + def address = new Persona(new ByteArrayInputStream(personaBytes)) + boolean autoConnect = json.autoConnect + favorites << new ChatFavorite(address, autoConnect) + } + } + + void save() { + favoritesFile.withPrintWriter { + for (ChatFavorite favorite : favorites) { + def json = [:] + json.autoConnect = favorite.autoConnect + json.address = favorite.address.toBase64() + it.println(JsonOutput.toJson(json)) + } + } + } + + void connect(Persona persona) { + controller.startChat(persona) + } +}