Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

522 chat click links #537

Merged
merged 19 commits into from
Oct 27, 2016
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,73 @@

import de.qabel.desktop.daemon.drop.TextMessage;
import javafx.scene.Node;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.text.TextFlow;
import org.controlsfx.control.HyperlinkLabel;
import org.jetbrains.annotations.NotNull;

import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ResourceBundle;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PlaintextMessageRenderer implements FXMessageRenderer {
private static final String STYLE_CLASS = "message-text";
public Consumer<String> browserOpener;

public PlaintextMessageRenderer() {
browserOpener = (uri) -> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also initialize it inline where you declare the member. Functionally it is identical.

A better way do to this is imho to create a dedicated browser opener interactor and replace the real one, which has Desktop.getDesktop() stuff, with a testable browser opener.

try {
Desktop.getDesktop().browse(new URI(uri));
} catch (IOException | URISyntaxException ignored) {
}
};

}

@Override
public Node render(String dropPayload, ResourceBundle resourceBundle) {
Label label = new Label(renderString(dropPayload, resourceBundle));
label.getStyleClass().add("message-text");
String text = renderString(dropPayload, resourceBundle);
return renderHyperlinks(text);
}

@NotNull
TextFlow renderHyperlinks(String message) {
String regex = "(https?:\\/\\/(?:www\\.|(?!www))[^\\s\\.]+\\.[^\\s]{2,}|www\\.[^\\s]+\\.[^\\s]{2,})";
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.COMMENTS | Pattern.MULTILINE);
Matcher matcher = pattern.matcher(message);
String result = matcher.replaceAll("[$1]");
Copy link
Member

@audax audax Oct 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract this replace stuff to a different place, it shouldn't be in a renderer.


HyperlinkLabel hyperLinkLabel = new HyperlinkLabel(result);
hyperLinkLabel.getStyleClass().add("text");

hyperLinkLabel.setOnAction(event -> {
Hyperlink link = (Hyperlink) event.getSource();
final String uri = link == null ? "" : link.getText();
new Thread(() -> browserOpener.accept(uri)).start();
});

TextFlow node = new TextFlow(hyperLinkLabel);
node.getStyleClass().add(STYLE_CLASS);
return node;
}

@NotNull
private Label renderLabel(String text) {
Label label = new Label(text);
label.getStyleClass().add(STYLE_CLASS);
return label;
}

@Override
public String renderString(String dropPayload, ResourceBundle resourceBundle) {
return TextMessage.fromJson(dropPayload).getText();
}


}
92 changes: 56 additions & 36 deletions src/main/resources/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,14 @@
-fx-background-radius: 5;
}

#shadow {
-fx-effect: dropshadow(one-pass-box, grey, 5, -1, 0, 2);
}

#myMessagebox {
-fx-background-color: #4d4d4d;
-fx-background-radius: 5;
}
#shadow {
-fx-effect: dropshadow(one-pass-box, grey, 5, -1, 0, 2);
}


.selected {
-fx-background-color: #b3b3b3;
Expand Down Expand Up @@ -254,35 +254,77 @@
-fx-text-fill: -fx-text-inner-color;
}

.message-text {
-fx-padding: 1em 1em 1em 1em;
-fx-text-alignment: justify;
-fx-wrap-text: true;
-fx-text-fill: white;

.hyperlink {
-fx-border-color: transparent;
-fx-padding: 0;
-fx-underline: false;
}

.hyperlink .text {
-fx-fill: #222222;
}

.hyperlink:visited .text {
-fx-fill: #222222;
}

.hyperlink:hover .text {
-fx-fill: #787878;
}

.hyperlink:pressed .text {
-fx-fill: #fd670d;
}


.message-date {
-fx-padding: 0 1em 0.5em 1em;
-fx-text-alignment: justify;
-fx-wrap-text: true;
}


.own .message-date {
-fx-alignment: bottom-right;
-fx-text-alignment: right;
}

.own .message-text .label {
.message-text {
-fx-padding: 1em 1em 1em 1em;
-fx-text-alignment: justify;
-fx-wrap-text: true;
-fx-text-fill: white;
-fx-fill: white;
}

.message-text,
.message-text .label,
.message-text .text,
.message-text Text {
-fx-wrap-text: true;
-fx-text-fill: white;
-fx-fill: white;
}

.own .message-text .label,
.own .message-text Text {
-fx-text-alignment: right;
-fx-text-fill: #4d4d4d;
}

.other .message-text .label {
.other .message-text .label ,
.other .message-text Text {
-fx-text-alignment: left;

}

.message-text .label {
-fx-wrap-text: true;
-fx-text-fill: white;
.own .message-text .hyperlink .text {
-fx-fill: #ff690f;
}

.other .message-text .hyperlink .text {
-fx-fill: #4d4d4d;
}

.payload-type-icon {
Expand Down Expand Up @@ -458,28 +500,6 @@ VBox.spaced, HBox.spaced {
-fx-border-width: 0 0 1px 0;
}

.hyperlink {
-fx-border-color: transparent;
-fx-padding: 0;
-fx-underline: false;
}

.hyperlink .text {
-fx-fill: #222222;
}

.hyperlink:visited .text {
-fx-fill: #222222;
}

.hyperlink:hover .text {
-fx-fill: #787878;
}

.hyperlink:pressed .text {
-fx-fill: #fd670d;
}

.labeled-link {
-fx-spacing: 0.5em;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,57 @@

import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import static junit.framework.TestCase.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;


public class ActionlogGuiTest extends AbstractGuiTest<ActionlogController> {
private AtomicReference<String> browserOpener = new AtomicReference<>();

@Override
protected FXMLView getView() {
return new ActionlogView();
}

@Test
public void typeMessageWithHyperlinkAndClickIt() throws Exception {
controller.contact = new Contact(identity.getAlias(), identity.getDropUrls(), identity.getEcPublicKey());
writeTwoLinesWithOneHyperlink();
submitChat();

plaintextMessageRenderer.browserOpener = browserOpener::set;
fxMessageRendererFactory.setFallbackRenderer(plaintextMessageRenderer);
clickOn(".hyperlink");
assertThat(browserOpener.get(), is("http://qabel.de"));
}

private void submitChat() {
assertTrue(receiveMessages().isEmpty());
robot.push(KeyCode.ENTER);
assertFalse(receiveMessages().isEmpty());
}

private void writeTwoLinesWithOneHyperlink() {
FxRobot textArea = clickOn("#textarea");
textArea.write("line1");
robot.press(KeyCode.SHIFT);
try {
robot.push(KeyCode.ENTER);
} finally {
robot.release(KeyCode.SHIFT);
}
robot.write("http://qabel.de");
}

@Test
public void testSendMessage() {
String text = "Message";
waitUntil(() -> controller.textarea != null);
Identity i = controller.identity;
controller.contact = new Contact(i.getAlias(),i.getDropUrls(), i.getEcPublicKey());
controller.contact = new Contact(i.getAlias(), i.getDropUrls(), i.getEcPublicKey());
clickOn("#textarea").write(text);
robot.push(KeyCode.ENTER);
List<DropMessage> list = receiveMessages();
Expand All @@ -58,9 +90,7 @@ public void multilineInput() {
}
robot.write("line2");

assertTrue(receiveMessages().isEmpty());
robot.push(KeyCode.ENTER);
assertFalse(receiveMessages().isEmpty());
submitChat();

DropMessage message = receiveMessages().get(0);
assertEquals(DropMessageRepository.PAYLOAD_TYPE_MESSAGE, message.getDropPayloadType());
Expand Down
10 changes: 7 additions & 3 deletions src/test/java/de/qabel/desktop/ui/AbstractControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ public class AbstractControllerTest extends AbstractFxTest {
protected int remoteDebounceTimeout;
protected EventDispatcher eventDispatcher = new SubjectEventDispatcher();

protected FXMessageRendererFactory fxMessageRendererFactory = new FXMessageRendererFactory();
protected PlaintextMessageRenderer plaintextMessageRenderer = new PlaintextMessageRenderer();

static {
logger = createLogger();
}
Expand Down Expand Up @@ -150,9 +153,10 @@ public void setUp() throws Exception {
diContainer.put("boxSyncConfigRepository", boxSyncRepository);
diContainer.put("boxSyncRepository", boxSyncRepository);
diContainer.put("transactionManager", transactionManager);
FXMessageRendererFactory FXMessageRendererFactory = new FXMessageRendererFactory();
FXMessageRendererFactory.setFallbackRenderer(new PlaintextMessageRenderer());
diContainer.put("messageRendererFactory", FXMessageRendererFactory);

fxMessageRendererFactory.setFallbackRenderer(plaintextMessageRenderer);
diContainer.put("messageRendererFactory", fxMessageRendererFactory);

SyncIndexFactory syncIndexFactory = new SqliteSyncIndexFactory();
diContainer.put("boxSyncConfigFactory", new DefaultBoxSyncConfigFactory(syncIndexFactory));
diContainer.put("boxSyncIndexFactory", syncIndexFactory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,53 @@
import de.qabel.desktop.ui.AbstractFxTest;
import javafx.scene.Node;
import javafx.scene.control.Labeled;
import javafx.scene.text.TextFlow;
import org.controlsfx.control.HyperlinkLabel;
import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicReference;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class PlaintextMessageRendererTest extends AbstractFxTest {
private PlaintextMessageRenderer renderer;
private String payload;

@Before
public void setUp() throws Exception {
renderer = new PlaintextMessageRenderer();
payload = "{'msg': 'content'}";
}

@Test
public void rendersPlaintextFromJson() {
String payload = "{'msg': 'content'}";
String message = renderer.renderString(payload, null);

assertEquals("content", message);
}

@Test
public void rendersMessageNode() {
String payload = "{'msg': 'content'}";
Node node = renderer.render(payload, null);
assertTrue(node instanceof Labeled);
assertEquals("content", ((Labeled)node).getText());
assertEquals("content", ((Labeled) node).getText());
}

@Test
public void renderHyperlinks() throws Exception {
final String string = "This is a Text,\n"
+ " wich has a neat hyperlinks www.qabel.de";

String expectedUriFormat = "[www.qabel.de]";

AtomicReference<String> browserOpener = new AtomicReference<>();
renderer.browserOpener = browserOpener::set;

Node node = renderer.renderHyperlinks(string);
HyperlinkLabel hyperLinkLabel = ((HyperlinkLabel) ((TextFlow) node).getChildren().get(0));
assertTrue(hyperLinkLabel.getText().contains(expectedUriFormat));
}


}