Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
## [Unreleased]
## [v0.5.0]

### Added


1. Add message bubbles.

### Changed

1. Use SQLAlchemy offset and limit to fetch only required messages.

### Fixed
### Build

1. Add an entrypoint script created by setuptool.


---
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ fallback_version = "0.0.0"
[tool.setuptools.packages.find]
where = ["src"]


[project.scripts]
memorytext = "memorytext.app:main"

[project.urls]
Repository = "https://github.com/shsiddhant/memory.text"
Issues = "https://github.com/shsiddhant/memory.text/issues"
Expand Down
146 changes: 109 additions & 37 deletions src/memorytext/delegates/message_list.py
Original file line number Diff line number Diff line change
@@ -1,80 +1,152 @@
from PySide6.QtWidgets import QStyledItemDelegate
from PySide6.QtCore import Qt, QRect, QSize
from PySide6.QtGui import QFont, QFontMetrics
from PySide6.QtGui import QFont, QFontMetrics, QColor
from memorytext.models.message_list import MessageList


USER_COLOR = "#ABE7FF"
OTHER_COLOR = "#e0e0e0"
TEXT_COLOR = "#000000"
USER_TEXT_COLOR = "#074D69"
TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M"
TIMESTAMP_COLOR = "#989898"
USER_TIMESTAMP_COLOR = "#2C98C2"


class MessageDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super().__init__(parent)
self.padding = 8
self.padding = 10
self.sender_height = 20
self.spacing = 5

def paint(self, painter, option, index):
painter.save()

# Data
text = str(index.data(Qt.ItemDataRole.DisplayRole))
sender = str(index.data(MessageList.SenderRole))
timestamp = index.data(MessageList.TimestampRole)
ts_text = timestamp.strftime(TIMESTAMP_FORMAT)
is_same_sender = index.data(MessageList.IsSameSenderRole)
alignment = index.data(Qt.ItemDataRole.TextAlignmentRole)

is_user = alignment & Qt.AlignmentFlag.AlignLeft

content_rect = option.rect.adjusted(
self.padding, self.padding, -self.padding, -self.padding
)
current_y = content_rect.top()

# Fonts
base_font = QFont(option.font)
sender_font = QFont(option.font)
sender_font.setBold(True)
sender_font.setPointSize(base_font.pointSize() - 1)
ts_font = QFont(base_font)
ts_font.setPointSize(base_font.pointSize() - 3)

max_width = option.rect.width() * 0.8
inner_width = max_width - 2 * self.padding

metrics = QFontMetrics(base_font)
sender_metrics = QFontMetrics(sender_font)
ts_metrics = QFontMetrics(ts_font)

text_rect = metrics.boundingRect(
0, 0, inner_width, 10000, Qt.TextFlag.TextWordWrap, text
)

# Bubble Dimensions
bubble_height = text_rect.height() + self.padding * 2
bubble_width = text_rect.width()
if not is_same_sender:
bubble_height += self.sender_height
bubble_width = max(bubble_width, sender_metrics.horizontalAdvance(sender))
bubble_height += ts_metrics.height()
bubble_width = max(bubble_width, ts_metrics.horizontalAdvance(ts_text))
bubble_width += 2 * self.padding

# Bubble Position
if alignment & Qt.AlignmentFlag.AlignLeft:
bubble_left = content_rect.left() - self.padding
bubble_color = OTHER_COLOR
else:
bubble_left = content_rect.right() - bubble_width - self.padding
bubble_color = USER_COLOR
bubble_rect = QRect(
bubble_left, option.rect.top() + self.spacing, bubble_width, bubble_height
)

painter.setRenderHint(painter.RenderHint.Antialiasing)

# Paint Bubble
painter.setBrush(QColor(bubble_color))
pen_color = TEXT_COLOR if is_user else USER_TEXT_COLOR
painter.setPen(QColor(pen_color))
painter.drawRoundedRect(bubble_rect, 10, 10)

# Text Positioning
current_top = bubble_rect.top() + self.padding
current_left = bubble_rect.left() + self.padding
current_width = bubble_rect.width() - 2 * self.padding

# Sender
if not is_same_sender:
sender_font = QFont(option.font)
sender_font.setBold(True)
sender_font.setPointSize(base_font.pointSize() - 1)
painter.setFont(sender_font)
sender_rect = QRect(
content_rect.left(),
current_y,
content_rect.width(),
content_rect.height(),
painter.drawText(
current_left,
current_top,
current_width,
self.sender_height,
alignment,
sender,
)
painter.drawText(sender_rect, alignment, sender)
current_y += self.sender_height + self.spacing
current_top += self.sender_height

# Message Text
painter.setFont(option.font)
message_rect = QRect(
content_rect.left(),
current_y,
content_rect.width(),
content_rect.height() - (current_y - content_rect.top()) + self.spacing,
painter.drawText(
current_left,
current_top,
current_width,
text_rect.height(),
alignment | Qt.TextFlag.TextWordWrap,
text,
)
current_top += text_rect.height()

painter.drawText(message_rect, alignment | Qt.TextFlag.TextWordWrap, text)

ts_font = QFont(base_font)
ts_font.setPointSize(base_font.pointSize() - 3)
ts = timestamp.strftime("%Y-%m-%d %H:%M")
ts_rect = QRect(
content_rect.left(),
current_y + message_rect.height(),
content_rect.width(),
content_rect.height(),
)
# Timestamp
painter.setFont(ts_font)
painter.drawText(ts_rect, alignment, ts)
ts_color = TIMESTAMP_COLOR if is_user else USER_TIMESTAMP_COLOR
painter.setPen(QColor(ts_color))
painter.drawText(
current_left,
current_top,
current_width,
ts_metrics.height(),
alignment,
ts_text,
)
painter.restore()

def sizeHint(self, option, index):
text = str(index.data(Qt.ItemDataRole.DisplayRole))
is_same_sender = index.data(MessageList.IsSameSenderRole)

width = option.rect.width()
available_width = width - (self.padding * 2)
max_width = option.rect.width() * 0.8
inner_width = max_width - 2 * self.padding
base_font = QFont(option.font)
ts_font = QFont(base_font)
ts_font.setPointSize(base_font.pointSize() - 3)

metrics = QFontMetrics(base_font)
ts_metrics = QFontMetrics(ts_font)

metrics = QFontMetrics(option.font)
text_rect = metrics.boundingRect(
0, 0, available_width, 10000, Qt.TextFlag.TextWordWrap, text
0, 0, inner_width, 10000, Qt.TextFlag.TextWordWrap, text
)
height = text_rect.height() + (self.padding * 2)
height = text_rect.height() + self.padding * 2 + ts_metrics.height()
if not is_same_sender:
height += self.sender_height
height += self.spacing
return QSize(width, height)

return QSize(option.rect.width(), height + self.spacing)
Loading