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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,10 @@
package com.muwire.gui
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
@ -13,8 +17,11 @@ import griffon.inject.MVCMember
import griffon.transform.Observable
import griffon.metadata.ArtifactProviderFor
import javax.imageio.ImageIO
import javax.swing.Icon
import javax.swing.SwingWorker
import javax.swing.tree.DefaultMutableTreeNode
import java.awt.image.BufferedImage
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicReference
@ -131,7 +138,7 @@ class SearchTabModel {
SenderBucket senderBucket = sendersBucket.get(event.sender)
if (senderBucket == null) {
senderBucket = new SenderBucket(event.sender, senders.size())
senderBucket = new SenderBucket(event.sender, event.profileHeader, senders.size())
sendersBucket[event.sender] = senderBucket
senders << senderBucket
}
@ -245,15 +252,40 @@ class SearchTabModel {
}
}
static class SenderBucket {
static class SenderBucket implements PersonaOrProfile {
final Persona sender
private final Icon avatar
private final String profileTitle
private final int rowIdx
final List<UIResultEvent> results = []
private int lastUpdatedIdx
SenderBucket(Persona sender, int rowIdx) {
SenderBucket(Persona sender, MWProfileHeader profileHeader,int rowIdx) {
this.sender = sender
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() {

View File

@ -2,6 +2,9 @@ package com.muwire.gui
import com.muwire.core.SharedFile
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 net.i2p.data.Destination
@ -95,7 +98,7 @@ class SearchTabView {
scrollPane (constraints : BorderLayout.CENTER) {
sendersTable = table(id : "senders-table", autoCreateRowSorter : true, rowHeight : rowHeight) {
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("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})
@ -394,12 +397,12 @@ class SearchTabView {
})
// senders table
def personaRenderer = new PersonaCellRenderer()
def personaComparator = new PersonaComparator()
def popRenderer = new PersonaOrProfileCellRenderer()
def popComparator = new PersonaOrProfileComparator()
sendersTable.addMouseListener(sendersMouseListener)
sendersTable.setDefaultRenderer(Integer.class, centerRenderer)
sendersTable.setDefaultRenderer(Persona.class, personaRenderer)
sendersTable.rowSorter.setComparator(0, personaComparator)
sendersTable.setDefaultRenderer(PersonaOrProfile.class, popRenderer)
sendersTable.rowSorter.setComparator(0, popComparator)
sendersTable.rowSorter.addRowSorterListener({evt -> lastSendersSortEvent = evt})
sendersTable.rowSorter.setSortsOnUpdates(true)
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();
}
}