hook up profiles with search results, sending and rendering side

dbus-notify
Zlatin Balevsky 2022-05-31 08:00:27 +01:00
parent 3e3e0d5b68
commit 216d0db303
No known key found for this signature in database
GPG Key ID: A72832072D525E41
11 changed files with 161 additions and 14 deletions

View File

@ -430,7 +430,8 @@ public class Core {
eventBus.register(UIFeedUpdateEvent.class, feedClient) eventBus.register(UIFeedUpdateEvent.class, feedClient)
log.info "initializing results sender" log.info "initializing results sender"
ResultsSender resultsSender = new ResultsSender(eventBus, i2pConnector, me, props, certificateManager, chatServer, collectionManager) ResultsSender resultsSender = new ResultsSender(eventBus, i2pConnector, me, { getMyProfile()?.getHeader() } as Supplier,
props, certificateManager, chatServer, collectionManager)
log.info "initializing search manager" log.info "initializing search manager"
SearchManager searchManager = new SearchManager(eventBus, me, resultsSender, props) SearchManager searchManager = new SearchManager(eventBus, me, resultsSender, props)

View File

@ -7,6 +7,7 @@ import com.muwire.core.connection.Endpoint
import com.muwire.core.connection.I2PConnector import com.muwire.core.connection.I2PConnector
import com.muwire.core.filecert.CertificateManager import com.muwire.core.filecert.CertificateManager
import com.muwire.core.files.FileHasher import com.muwire.core.files.FileHasher
import com.muwire.core.profile.MWProfileHeader
import com.muwire.core.util.DataUtil import com.muwire.core.util.DataUtil
import com.muwire.core.Persona import com.muwire.core.Persona
@ -16,6 +17,7 @@ import java.util.concurrent.Executor
import java.util.concurrent.Executors import java.util.concurrent.Executors
import java.util.concurrent.ThreadFactory import java.util.concurrent.ThreadFactory
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import java.util.function.Supplier
import java.util.logging.Level import java.util.logging.Level
import java.util.stream.Collectors import java.util.stream.Collectors
import java.util.zip.GZIPOutputStream import java.util.zip.GZIPOutputStream
@ -48,17 +50,20 @@ class ResultsSender {
private final I2PConnector connector private final I2PConnector connector
private final Persona me private final Persona me
private final Supplier<MWProfileHeader> myProfileHeader
private final EventBus eventBus private final EventBus eventBus
private final MuWireSettings settings private final MuWireSettings settings
private final CertificateManager certificateManager private final CertificateManager certificateManager
private final ChatServer chatServer private final ChatServer chatServer
private final CollectionManager collectionManager private final CollectionManager collectionManager
ResultsSender(EventBus eventBus, I2PConnector connector, Persona me, MuWireSettings settings, ResultsSender(EventBus eventBus, I2PConnector connector, Persona me, Supplier<MWProfileHeader> myProfileHeader,
CertificateManager certificateManager, ChatServer chatServer, CollectionManager collectionManager) { MuWireSettings settings, CertificateManager certificateManager, ChatServer chatServer,
CollectionManager collectionManager) {
this.connector = connector; this.connector = connector;
this.eventBus = eventBus this.eventBus = eventBus
this.me = me this.me = me
this.myProfileHeader = myProfileHeader
this.settings = settings this.settings = settings
this.certificateManager = certificateManager this.certificateManager = certificateManager
this.chatServer = chatServer this.chatServer = chatServer
@ -109,7 +114,8 @@ class ResultsSender {
messages : settings.allowMessages, messages : settings.allowMessages,
feed : settings.fileFeed && settings.advertiseFeed, feed : settings.fileFeed && settings.advertiseFeed,
collections : collections, collections : collections,
path: path path: path,
profileHeader: myProfileHeader.get()
) )
uiResultEvents << uiResultEvent uiResultEvents << uiResultEvent
} }
@ -168,6 +174,9 @@ class ResultsSender {
os.write("Feed: $feed\r\n".getBytes(StandardCharsets.US_ASCII)) os.write("Feed: $feed\r\n".getBytes(StandardCharsets.US_ASCII))
boolean messages = settings.allowMessages boolean messages = settings.allowMessages
os.write("Messages: $messages\r\n".getBytes(StandardCharsets.US_ASCII)) os.write("Messages: $messages\r\n".getBytes(StandardCharsets.US_ASCII))
MWProfileHeader header = myProfileHeader.get()
if (header != null)
os.write("ProfileHeader: ${myProfileHeader.toBase64()}\r\n".getBytes(StandardCharsets.US_ASCII))
os.write("\r\n".getBytes(StandardCharsets.US_ASCII)) os.write("\r\n".getBytes(StandardCharsets.US_ASCII))
dos = new DataOutputStream(new GZIPOutputStream(os)) dos = new DataOutputStream(new GZIPOutputStream(os))
results.each { results.each {

View File

@ -3,7 +3,7 @@ package com.muwire.core.search
import com.muwire.core.Event import com.muwire.core.Event
import com.muwire.core.InfoHash import com.muwire.core.InfoHash
import com.muwire.core.Persona import com.muwire.core.Persona
import com.muwire.core.profile.MWProfileHeader
import net.i2p.data.Destination import net.i2p.data.Destination
class UIResultEvent extends Event { class UIResultEvent extends Event {
@ -23,6 +23,7 @@ class UIResultEvent extends Event {
boolean messages boolean messages
Set<InfoHash> collections Set<InfoHash> collections
String[] path String[] path
MWProfileHeader profileHeader
private String fullPath private String fullPath

View File

@ -270,6 +270,8 @@ FEED=Feed
NEUTRAL=Neutral NEUTRAL=Neutral
DISTRUST=Distrust DISTRUST=Distrust
COPY_FULL_ID=Copy Full ID COPY_FULL_ID=Copy Full ID
NO_PROFILE=This user does not have a profile
# results table (group by sender) # results table (group by sender)
DIRECT_SOURCES=Direct Sources DIRECT_SOURCES=Direct Sources

View File

@ -105,7 +105,7 @@ class Initialize extends AbstractLifecycleHandler {
} else { } else {
fontSize = uiSettings.fontSize fontSize = uiSettings.fontSize
} }
rowHeight = fontSize + 3 rowHeight = Math.max(24, fontSize + 3)
FontUIResource font = new FontUIResource(fontName, uiSettings.fontStyle, fontSize) FontUIResource font = new FontUIResource(fontName, uiSettings.fontStyle, fontSize)
def keys = lnf.getDefaults().keys() def keys = lnf.getDefaults().keys()

View File

@ -1,6 +1,10 @@
package com.muwire.gui package com.muwire.gui
import com.muwire.core.InfoHash import com.muwire.core.InfoHash
import com.muwire.core.profile.MWProfileHeader
import com.muwire.gui.profile.ImageScaler
import com.muwire.gui.profile.PersonaOrProfile
import com.muwire.gui.profile.ThumbnailIcon
import javax.annotation.Nonnull import javax.annotation.Nonnull
@ -13,8 +17,11 @@ import griffon.inject.MVCMember
import griffon.transform.Observable import griffon.transform.Observable
import griffon.metadata.ArtifactProviderFor import griffon.metadata.ArtifactProviderFor
import javax.imageio.ImageIO
import javax.swing.Icon
import javax.swing.SwingWorker import javax.swing.SwingWorker
import javax.swing.tree.DefaultMutableTreeNode import javax.swing.tree.DefaultMutableTreeNode
import java.awt.image.BufferedImage
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
@ -131,7 +138,7 @@ class SearchTabModel {
SenderBucket senderBucket = sendersBucket.get(event.sender) SenderBucket senderBucket = sendersBucket.get(event.sender)
if (senderBucket == null) { if (senderBucket == null) {
senderBucket = new SenderBucket(event.sender, senders.size()) senderBucket = new SenderBucket(event.sender, event.profileHeader, senders.size())
sendersBucket[event.sender] = senderBucket sendersBucket[event.sender] = senderBucket
senders << senderBucket senders << senderBucket
} }
@ -245,15 +252,40 @@ class SearchTabModel {
} }
} }
static class SenderBucket { static class SenderBucket implements PersonaOrProfile {
final Persona sender final Persona sender
private final Icon avatar
private final String profileTitle
private final int rowIdx private final int rowIdx
final List<UIResultEvent> results = [] final List<UIResultEvent> results = []
private int lastUpdatedIdx private int lastUpdatedIdx
SenderBucket(Persona sender, int rowIdx) { SenderBucket(Persona sender, MWProfileHeader profileHeader,int rowIdx) {
this.sender = sender this.sender = sender
this.rowIdx = rowIdx this.rowIdx = rowIdx
if (profileHeader != null) {
Icon icon = null
try {
icon = new ThumbnailIcon(profileHeader.getThumbNail())
} catch (IOException iox) {}
avatar = icon
profileTitle = profileHeader.getTitle()
} else {
avatar = null
profileTitle = null
}
}
Persona getPersona() {
sender
}
Icon getThumbnail() {
avatar
}
String getTitle() {
profileTitle
} }
List<UIResultEvent> getPendingResults() { List<UIResultEvent> getPendingResults() {

View File

@ -2,6 +2,9 @@ package com.muwire.gui
import com.muwire.core.SharedFile import com.muwire.core.SharedFile
import com.muwire.gui.SearchTabModel.SenderBucket import com.muwire.gui.SearchTabModel.SenderBucket
import com.muwire.gui.profile.PersonaOrProfile
import com.muwire.gui.profile.PersonaOrProfileCellRenderer
import com.muwire.gui.profile.PersonaOrProfileComparator
import griffon.core.artifact.GriffonView import griffon.core.artifact.GriffonView
import net.i2p.data.Destination import net.i2p.data.Destination
@ -95,7 +98,7 @@ class SearchTabView {
scrollPane (constraints : BorderLayout.CENTER) { scrollPane (constraints : BorderLayout.CENTER) {
sendersTable = table(id : "senders-table", autoCreateRowSorter : true, rowHeight : rowHeight) { sendersTable = table(id : "senders-table", autoCreateRowSorter : true, rowHeight : rowHeight) {
tableModel(list : model.senders) { tableModel(list : model.senders) {
closureColumn(header : trans("SENDER"), preferredWidth : 500, type: Persona, read : { SenderBucket row -> row.sender}) closureColumn(header : trans("SENDER"), preferredWidth : 500, type: PersonaOrProfile, read : { SenderBucket row -> row})
closureColumn(header : trans("RESULTS"), preferredWidth : 20, type: Integer, read : {SenderBucket row -> row.results.size()}) closureColumn(header : trans("RESULTS"), preferredWidth : 20, type: Integer, read : {SenderBucket row -> row.results.size()})
closureColumn(header : trans("BROWSE"), preferredWidth : 20, type: Boolean, read : {SenderBucket row -> row.results[0].browse}) closureColumn(header : trans("BROWSE"), preferredWidth : 20, type: Boolean, read : {SenderBucket row -> row.results[0].browse})
closureColumn(header : trans("COLLECTIONS"), preferredWidth : 20, type: Boolean, read : {SenderBucket row -> row.results[0].browseCollections}) closureColumn(header : trans("COLLECTIONS"), preferredWidth : 20, type: Boolean, read : {SenderBucket row -> row.results[0].browseCollections})
@ -394,12 +397,12 @@ class SearchTabView {
}) })
// senders table // senders table
def personaRenderer = new PersonaCellRenderer() def popRenderer = new PersonaOrProfileCellRenderer()
def personaComparator = new PersonaComparator() def popComparator = new PersonaOrProfileComparator()
sendersTable.addMouseListener(sendersMouseListener) sendersTable.addMouseListener(sendersMouseListener)
sendersTable.setDefaultRenderer(Integer.class, centerRenderer) sendersTable.setDefaultRenderer(Integer.class, centerRenderer)
sendersTable.setDefaultRenderer(Persona.class, personaRenderer) sendersTable.setDefaultRenderer(PersonaOrProfile.class, popRenderer)
sendersTable.rowSorter.setComparator(0, personaComparator) sendersTable.rowSorter.setComparator(0, popComparator)
sendersTable.rowSorter.addRowSorterListener({evt -> lastSendersSortEvent = evt}) sendersTable.rowSorter.addRowSorterListener({evt -> lastSendersSortEvent = evt})
sendersTable.rowSorter.setSortsOnUpdates(true) sendersTable.rowSorter.setSortsOnUpdates(true)
selectionModel = sendersTable.getSelectionModel() selectionModel = sendersTable.getSelectionModel()

View File

@ -0,0 +1,46 @@
package com.muwire.gui.profile
import com.muwire.core.Persona
import javax.swing.JTable
import javax.swing.table.DefaultTableCellRenderer
import java.awt.Component
import static com.muwire.gui.Translator.trans
class PersonaOrProfileCellRenderer extends DefaultTableCellRenderer {
@Override
Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column)
PersonaOrProfile pop = (PersonaOrProfile) value
if (pop.getThumbnail() != null)
setIcon(pop.getThumbnail())
else
setIcon(null)
if (pop.getTitle() != null)
setToolTipText(pop.getTitle())
else
setToolTipText(trans("NO_PROFILE"))
Persona persona = pop.getPersona()
setText("<html>${htmlize(persona)}</html>")
if (isSelected) {
setForeground(table.getSelectionForeground())
setBackground(table.getSelectionBackground())
} else {
setForeground(table.getForeground())
setBackground(table.getBackground())
}
this
}
static String htmlize(Persona persona) {
int atIdx = persona.getHumanReadableName().indexOf("@")
String nickname = persona.getHumanReadableName().substring(0, atIdx)
String hashPart = persona.getHumanReadableName().substring(atIdx)
"$nickname<font color='gray'>$hashPart</font>"
}
}

View File

@ -0,0 +1,9 @@
package com.muwire.gui.profile
import java.text.Collator
class PersonaOrProfileComparator implements Comparator<PersonaOrProfile>{
int compare(PersonaOrProfile a, PersonaOrProfile b) {
Collator.getInstance().compare(a.getPersona().getHumanReadableName(), b.getPersona().getHumanReadableName())
}
}

View File

@ -0,0 +1,11 @@
package com.muwire.gui.profile;
import com.muwire.core.Persona;
import javax.swing.*;
public interface PersonaOrProfile {
Persona getPersona();
Icon getThumbnail();
String getTitle();
}

View File

@ -0,0 +1,33 @@
package com.muwire.gui.profile;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class ThumbnailIcon implements Icon {
BufferedImage image;
public ThumbnailIcon(byte [] rawData) throws IOException {
BufferedImage img = ImageIO.read(new ByteArrayInputStream(rawData));
image = ImageScaler.scaleToThumbnail(img);
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
((Graphics2D)g).drawImage(image, x, y, null);
}
@Override
public int getIconWidth() {
return image.getWidth();
}
@Override
public int getIconHeight() {
return image.getHeight();
}
}