new contact selector

dbus-notify
Zlatin Balevsky 2022-06-07 11:31:14 +01:00
parent 56f83c8078
commit 53206b3b84
No known key found for this signature in database
GPG Key ID: A72832072D525E41
10 changed files with 318 additions and 7 deletions

View File

@ -669,7 +669,7 @@ FOLDER_CONFIRM_DELETE=This folder is not empty. Are you sure you want to delete
## New message window ## New message window
UNREAD=Unread UNREAD=Unread
RECIPIENTS=Recipients RECIPIENTS=Recipients
RECIPIENTS_TITLE=Drag and drop contacts from your contact list RECIPIENTS_TITLE=You can drag and drop contacts from your contact list here
SEND=Send SEND=Send
MESSAGE_VERB=Message MESSAGE_VERB=Message
MESSAGE_NOUN=Message MESSAGE_NOUN=Message
@ -681,6 +681,9 @@ SUBJECT_TOO_LONG_BODY=Your subject is {0} characters. The maximum length is {1}
NO_RECIPIENTS=No Recipients NO_RECIPIENTS=No Recipients
NO_RECIPIENTS_BODY=Please add at least one recipient. NO_RECIPIENTS_BODY=Please add at least one recipient.
## Contact chooser
CONTACT_CHOOSER_SELECT_CONTACT=Select Contact
## Add Contact dialog ## Add Contact dialog
ADD_CONTACT_SPECIFIC=Add Contact ADD_CONTACT_SPECIFIC=Add Contact
ADD_CONTACT_TITLE=Add a new contact ADD_CONTACT_TITLE=Add a new contact

View File

@ -1,5 +1,6 @@
package com.muwire.gui.contacts package com.muwire.gui.contacts
import com.muwire.core.Core
import com.muwire.core.Persona import com.muwire.core.Persona
import griffon.core.artifact.GriffonModel import griffon.core.artifact.GriffonModel
import griffon.inject.MVCMember import griffon.inject.MVCMember
@ -9,5 +10,6 @@ import javax.annotation.Nonnull
@ArtifactProviderFor(GriffonModel) @ArtifactProviderFor(GriffonModel)
class ContactSelectorModel { class ContactSelectorModel {
Core core
Set<Persona> contacts Set<Persona> contacts
} }

View File

@ -62,6 +62,7 @@ class NewMessageView {
def params = [:] def params = [:]
params.contacts = model.recipients params.contacts = model.recipients
params.core = model.core
contactSelector = mvcGroup.createMVCGroup("contact-selector", UUID.randomUUID().toString(), params) contactSelector = mvcGroup.createMVCGroup("contact-selector", UUID.randomUUID().toString(), params)
window = builder.frame(visible : false, locationRelativeTo : mainFrame, window = builder.frame(visible : false, locationRelativeTo : mainFrame,

View File

@ -43,6 +43,7 @@ class WatchedDirectoryView {
mainFrame = application.windowManager.findWindow("main-frame") mainFrame = application.windowManager.findWindow("main-frame")
def params = [:] def params = [:]
params.core = model.core
params.contacts = model.allowedContacts params.contacts = model.allowedContacts
contactSelector = mvcGroup.createMVCGroup("contact-selector", UUID.randomUUID().toString(), params) contactSelector = mvcGroup.createMVCGroup("contact-selector", UUID.randomUUID().toString(), params)

View File

@ -23,6 +23,10 @@ import javax.swing.border.TitledBorder
import java.awt.BorderLayout import java.awt.BorderLayout
import java.awt.datatransfer.DataFlavor import java.awt.datatransfer.DataFlavor
import java.awt.datatransfer.Transferable import java.awt.datatransfer.Transferable
import java.awt.event.ItemEvent
import java.awt.event.ItemListener
import java.awt.event.KeyAdapter
import java.awt.event.KeyEvent
import java.awt.event.MouseAdapter import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent import java.awt.event.MouseEvent
@ -39,23 +43,37 @@ class ContactSelectorView {
DefaultListModel contactsModel DefaultListModel contactsModel
JList contactsList JList contactsList
ContactChooser contactChooser
ContactChooserModel contactChooserModel
JPanel component JPanel component
private UISettings settings
private Contact lastSelectedContact
void initUI() { void initUI() {
settings = application.context.get("ui-settings")
contactsModel = new DefaultListModel() contactsModel = new DefaultListModel()
model.contacts.each { model.contacts.each {
contactsModel.addElement(new Contact(it)) contactsModel.addElement(new Contact(it, settings))
} }
contactsList = new JList(contactsModel) contactsList = new JList(contactsModel)
contactsList.setVisibleRowCount(2) contactsList.setVisibleRowCount(2)
component = builder.panel(border : builder.titledBorder(title : trans("RECIPIENTS_TITLE"), contactChooserModel= new ContactChooserModel(model.core.trustService.getGood().values())
border : builder.etchedBorder(), titlePosition : TitledBorder.TOP)) { contactChooser = new ContactChooser(settings, contactChooserModel)
component = builder.panel {
borderLayout() borderLayout()
scrollPane(constraints : BorderLayout.CENTER) { scrollPane(constraints : BorderLayout.CENTER, border : builder.titledBorder(title : trans("RECIPIENTS_TITLE"),
border : builder.etchedBorder(), titlePosition : TitledBorder.TOP)) {
widget(contactsList) widget(contactsList)
} }
widget(contactChooser, constraints: BorderLayout.SOUTH,
border : builder.titledBorder(title : trans("CONTACT_CHOOSER_SELECT_CONTACT"),
border : builder.etchedBorder(), titlePosition : TitledBorder.TOP))
} }
} }
@ -79,6 +97,34 @@ class ContactSelectorView {
contactsMenu.show(e.getComponent(), e.getX(), e.getY()) contactsMenu.show(e.getComponent(), e.getX(), e.getY())
} }
}) })
contactChooser.addItemListener(new ItemListener() {
@Override
void itemStateChanged(ItemEvent e) {
if (e.getStateChange() != ItemEvent.SELECTED)
return
Object item = e.getItem()
if (item == null || item instanceof String)
return
ContactChooserPOP ccp = (ContactChooserPOP) item
if (ccp.getPersona() == null)
return
lastSelectedContact = new Contact(ccp.getPersona(), settings)
}
})
contactChooser.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
@Override
void keyReleased(KeyEvent e) {
if (e.getKeyCode() != KeyEvent.VK_ENTER)
return
if (lastSelectedContact != null) {
if (model.contacts.add(lastSelectedContact.persona))
contactsModel << lastSelectedContact
}
}
})
} }
void removeSelectedContacts() { void removeSelectedContacts() {
@ -110,7 +156,7 @@ class ContactSelectorView {
items.each { items.each {
if (model.contacts.add(it)) if (model.contacts.add(it))
contactsModel.insertElementAt(new Contact(it),0) contactsModel.insertElementAt(new Contact(it, settings),0)
} }
return true return true
} }
@ -119,8 +165,9 @@ class ContactSelectorView {
private static class Contact { private static class Contact {
private final UISettings settings private final UISettings settings
private final Persona persona private final Persona persona
Contact(Persona persona) { Contact(Persona persona, UISettings settings) {
this.persona = persona this.persona = persona
this.settings = settings
} }
public String toString() { public String toString() {

View File

@ -0,0 +1,18 @@
package com.muwire.gui.contacts
import com.muwire.gui.UISettings
import com.muwire.gui.profile.PersonaOrProfileCellRenderer
import javax.swing.JComboBox
import javax.swing.JTextField
class ContactChooser extends JComboBox{
ContactChooser(UISettings settings, ContactChooserModel model) {
super()
setEditable(true)
setModel(model)
setEditor(new ContactChooserEditor(model, this))
setRenderer(new PersonaOrProfileListCellRenderer(settings))
}
}

View File

@ -0,0 +1,47 @@
package com.muwire.gui.contacts
import javax.swing.SwingUtilities
import javax.swing.event.DocumentEvent
import javax.swing.event.DocumentListener
import javax.swing.plaf.basic.BasicComboBoxEditor
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.awt.event.KeyAdapter
import java.awt.event.KeyEvent
class ContactChooserEditor extends BasicComboBoxEditor{
private final ContactChooserModel model
private final ContactChooser field
ContactChooserEditor(ContactChooserModel model, ContactChooser field) {
super()
this.model = model
this.field = field
editor.addKeyListener(new KeyAdapter() {
@Override
void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode()
if (keyCode == KeyEvent.VK_ENTER)
editor.setText("")
else if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN) {
return
} else {
SwingUtilities.invokeLater {
field.hidePopup()
if (model.onKeyStroke(editor.text))
field.showPopup()
}
}
}
})
}
public void setItem(Object o) {
if (o == null || o instanceof ContactChooserPOP)
super.setItem(o)
else
editor.setText("")
}
}

View File

@ -0,0 +1,73 @@
package com.muwire.gui.contacts
import com.muwire.core.trust.TrustService
import com.muwire.core.trust.TrustService.TrustEntry
import com.muwire.gui.profile.PersonaOrProfile
import com.muwire.gui.profile.PersonaOrProfileComparator
import com.muwire.gui.profile.TrustPOP
import javax.swing.ComboBoxModel
import javax.swing.DefaultComboBoxModel
import javax.swing.DefaultListModel
import javax.swing.MutableComboBoxModel
class ContactChooserModel extends DefaultComboBoxModel implements MutableComboBoxModel {
private final List<PersonaOrProfile> allObjects
private final Comparator<PersonaOrProfile> popComparator = new PersonaOrProfileComparator()
PersonaOrProfile selectedPOP
ContactChooserModel(Collection<TrustEntry> entries) {
allObjects = entries.collect {new ContactChooserPOP(it)}
addAll(allObjects)
}
boolean onKeyStroke(String selected) {
if (selected == null || selected.length() == 0) {
removeAllElements()
addAll(allObjects)
return true
}
removeAllElements()
setSelectedItem(new ContactChooserPOP(selected))
List<PersonaOrProfile> matches = []
for(PersonaOrProfile pop : allObjects) {
if (justName(pop).containsIgnoreCase(selected))
matches << pop
}
if (matches.isEmpty())
return false
Collections.sort(matches, popComparator)
addAll(matches)
true
}
private static String justName(PersonaOrProfile pop) {
String name = pop.getPersona().getHumanReadableName()
name.substring(0, name.indexOf("@")).toLowerCase()
}
@Override
public void setSelectedItem(Object anObject) {
if (anObject instanceof String) {
if (anObject == selectedPOP?.getPersona()?.getHumanReadableName())
super.setSelectedItem(selectedPOP)
return
}
if (anObject == null)
selectedPOP = null
else {
if (!(anObject instanceof ContactChooserPOP))
throw new Exception("invalid type $anObject")
ContactChooserPOP ccp = (ContactChooserPOP) anObject
if (ccp.getPersona() != null)
selectedPOP = ccp
}
super.setSelectedItem(anObject)
}
}

View File

@ -0,0 +1,65 @@
package com.muwire.gui.contacts
import com.muwire.core.Persona
import com.muwire.core.profile.MWProfile
import com.muwire.core.profile.MWProfileHeader
import com.muwire.core.trust.TrustService.TrustEntry
import com.muwire.gui.profile.PersonaOrProfile
import com.muwire.gui.profile.ThumbnailIcon
import javax.swing.Icon
class ContactChooserPOP implements PersonaOrProfile {
private final TrustEntry trustEntry
private final String text
private Icon icon
ContactChooserPOP(TrustEntry trustEntry) {
this.trustEntry = trustEntry
this.text = null
}
ContactChooserPOP(String text) {
this.text = text
this.trustEntry = null
}
Persona getPersona() {
trustEntry?.getPersona()
}
@Override
Icon getThumbnail() {
MWProfileHeader header = getHeader()
if (header == null)
return null
if (icon == null)
icon = new ThumbnailIcon(header.getThumbNail())
return icon
}
@Override
MWProfileHeader getHeader() {
trustEntry.getProfileHeader()
}
@Override
MWProfile getProfile() {
trustEntry.getProfile()
}
public boolean equals(Object o) {
if (!(o instanceof ContactChooserPOP))
return false
ContactChooserPOP other = (ContactChooserPOP)o
Objects.equals(text, other.text) &&
Objects.equals(trustEntry, other.trustEntry)
}
String toString() {
if (text != null)
return text
else
return getPersona().getHumanReadableName()
}
}

View File

@ -0,0 +1,54 @@
package com.muwire.gui.contacts
import com.muwire.gui.PersonaCellRenderer
import com.muwire.gui.UISettings
import com.muwire.gui.profile.PersonaOrProfile
import javax.swing.JLabel
import javax.swing.JList
import javax.swing.ListCellRenderer
import java.awt.Component
import static com.muwire.gui.Translator.trans
class PersonaOrProfileListCellRenderer implements ListCellRenderer<PersonaOrProfile>{
private final UISettings settings
PersonaOrProfileListCellRenderer(UISettings settings) {
this.settings = settings
}
@Override
Component getListCellRendererComponent(JList<? extends PersonaOrProfile> list, PersonaOrProfile value,
int index, boolean isSelected, boolean cellHasFocus) {
JLabel rv = new JLabel()
String text
if (settings.personaRendererIds)
text = "<html>" + PersonaCellRenderer.htmlize(value.getPersona()) + "</html>"
else
text = PersonaCellRenderer.justName(value.getPersona())
rv.setText(text)
if (value.getThumbnail() != null)
rv.setIcon(value.getThumbnail())
else
rv.setIcon(null)
if (value.getTitle() != null)
rv.setToolTipText(value.getTitle())
else
rv.setToolTipText(trans("NO_PROFILE"))
if (!isSelected) {
rv.setForeground(list.getForeground())
rv.setBackground(list.getBackground())
} else {
rv.setForeground(list.getSelectionForeground())
rv.setBackground(list.getSelectionBackground())
}
rv
}
}