summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--justfile3
-rw-r--r--kodereviewer/app.py3
-rw-r--r--kodereviewer/data.py96
-rw-r--r--kodereviewer/models/__init__.py2
-rw-r--r--kodereviewer/models/comments.py12
-rw-r--r--kodereviewer/models/file.py2
-rw-r--r--kodereviewer/models/reviews.py295
-rw-r--r--kodereviewer/network_manager.py14
-rw-r--r--kodereviewer/qml/Editor.qml2
-rw-r--r--kodereviewer/qml/Main.qml2
-rw-r--r--kodereviewer/qml/MarkdownTextArea.qml3
-rw-r--r--kodereviewer/qml/PullRequestPage.qml56
-rw-r--r--kodereviewer/qml/ReviewList.qml84
-rw-r--r--org.deprecated.kodereviewer.yml26
-rw-r--r--requirements.txt5
15 files changed, 569 insertions, 36 deletions
diff --git a/justfile b/justfile
index c0b6f32..5674506 100644
--- a/justfile
+++ b/justfile
@@ -10,3 +10,6 @@ build-flatpak:
qmltypes:
# If this fails, comment __main__.py code
pyside6-qml-stubgen kodereviewer/ --out-dir ./qmltypes/
+
+gammaray:
+ gammaray --probe qt6_8-x86_64 python -mkodereviewer
diff --git a/kodereviewer/app.py b/kodereviewer/app.py
index bc5a626..1eeb241 100644
--- a/kodereviewer/app.py
+++ b/kodereviewer/app.py
@@ -14,7 +14,7 @@ from kodereviewer.models.file import FileModel
from kodereviewer.network_manager import NetworkManager
from kodereviewer.models import (
CommentModel, TreeFileModel, LabelModel, LineModel, PullRequestModel,
- ProjectModel, ReviewerModel
+ ProjectModel, ReviewerModel, ReviewModel
)
import logging
from rich.logging import RichHandler
@@ -54,6 +54,7 @@ def main():
qmlRegisterType(LineModel, "org.deprecated.kodereviewer", 1, 0, "LineModel")
qmlRegisterType(PullRequestModel, "org.deprecated.kodereviewer", 1, 0, "PullRequestModel")
qmlRegisterType(ReviewerModel, "org.deprecated.kodereviewer", 1, 0, "ReviewerModel")
+ qmlRegisterType(ReviewModel, "org.deprecated.kodereviewer", 1, 0, "ReviewModel")
qmlRegisterType(NetworkManager, "org.deprecated.kodereviewer", 1, 0, "NetworkManager")
localized_context = KLocalizedContext()
diff --git a/kodereviewer/data.py b/kodereviewer/data.py
index 61f1a01..1598e9d 100644
--- a/kodereviewer/data.py
+++ b/kodereviewer/data.py
@@ -10,13 +10,22 @@ from PySide6.QtQml import QmlElement
class User(QObject):
- username: str
- avatar_url: str
+
+ _username: str
+ _avatar_url: str
def __init__(self, data: dict[str, Any]):
super().__init__()
- self.username = data['login']
- self.avatar_url = data['avatar_url']
+ self._username = data['login']
+ self._avatar_url = data['avatar_url']
+
+ @Property(str, constant=True)
+ def username(self) -> str:
+ return self._username
+
+ @Property(str, constant=True)
+ def avatarUrl(self) -> str:
+ return self._avatar_url
class Label(QObject):
@@ -32,21 +41,68 @@ class Label(QObject):
class Comment(QObject):
- body: str
- reactions: dict[str, int]
+ _body: str
+ _reactions: dict[str, int]
- created_at: datetime
- updated_at: datetime
+ _created_at: datetime
+ _updated_at: datetime
- user: User
+ _user: User
def __init__(self, data: dict[str, Any]):
super().__init__()
- self.body = data['body']
- self.reactions = data['reactions']
- self.created_at = datetime.fromisoformat(data['created_at'])
- self.updated_at = datetime.fromisoformat(data['updated_at'])
- self.user = User(data['user'])
+ self._body = data['body']
+ self._reactions = data['reactions']
+ self._created_at = datetime.fromisoformat(data['created_at'])
+ self._updated_at = datetime.fromisoformat(data['updated_at'])
+ self._user = User(data['user'])
+
+ @Property(str, constant=True)
+ def body(self) -> str:
+ return self._body
+
+ @Property(datetime, constant=True)
+ def created_at(self) -> datetime:
+ return self._created_at
+
+ @Property(datetime, constant=True)
+ def updated_at(self) -> datetime:
+ return self._updated_at
+
+ @Property(User, constant=True)
+ def user(self) -> User:
+ return self._user
+
+
+class ReviewComment(Comment):
+ _id: int
+ _in_reply_to: int | None
+ _diff: str
+ _line: int
+ def __init__(self, data: dict[str, Any]):
+ super().__init__(data)
+ self._id = data['id']
+ self._in_reply_to = data.get('in_reply_to_id')
+ self._diff = data['diff_hunk']
+ self._line = data['line']
+
+ @Property(int, constant=True)
+ def id(self) -> int:
+ return self._id
+
+ @Property(int, constant=True)
+ def in_reply_to(self) -> int:
+ if self._in_reply_to is None:
+ return 0
+ return self._in_reply_to
+
+ @Property(str, constant=True)
+ def diff(self) -> str:
+ return self._diff
+
+ @Property(int, constant=True)
+ def line(self) -> int:
+ return self._line
class ChangedFileStatus(Enum):
@@ -112,12 +168,14 @@ class PullRequest(QObject):
_last_commit: str
_comments: list[Comment]
+ _reviews: list[ReviewComment]
_files: list[ChangedFile]
_initial_data: dict[str, Any]
commentsLoaded = Signal()
filesLoaded = Signal()
+ reviewsLoaded = Signal()
def __init__(self, data: dict[str, Any], *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -146,6 +204,7 @@ class PullRequest(QObject):
# At first this is empty until it's updated with a request
self._comments = []
self._files = []
+ self._reviews = []
self._initial_data = data
@@ -207,6 +266,10 @@ class PullRequest(QObject):
def files(self) -> list[ChangedFile]:
return self._files
+ @Property(list, constant=True)
+ def reviews(self) -> list[ReviewComment]:
+ return self._reviews
+
def load_comments(self, response: QByteArray) -> None:
data = json.loads(response.toStdString())
self._comments = [Comment(comment) for comment in data]
@@ -217,6 +280,11 @@ class PullRequest(QObject):
self._files = [ChangedFile(file) for file in data]
self.filesLoaded.emit()
+ def load_reviews(self, response: QByteArray) -> None:
+ data = json.loads(response.toStdString())
+ self._reviews = [ReviewComment(review) for review in data]
+ self.reviewsLoaded.emit()
+
def copy(self):
"""Create a copy of a PullRequest with it's initial parameters."""
return PullRequest(deepcopy(self._initial_data))
diff --git a/kodereviewer/models/__init__.py b/kodereviewer/models/__init__.py
index 810d403..aa7bb7d 100644
--- a/kodereviewer/models/__init__.py
+++ b/kodereviewer/models/__init__.py
@@ -5,6 +5,7 @@ from kodereviewer.models.project import ProjectModel
from kodereviewer.models.pull_request import PullRequestModel
from kodereviewer.models.label import LabelModel
from kodereviewer.models.reviewer import ReviewerModel
+from kodereviewer.models.reviews import ReviewModel
__all__ = [
'CommentModel',
@@ -15,4 +16,5 @@ __all__ = [
'ProjectModel',
'PullRequestModel',
'ReviewerModel',
+ 'ReviewModel'
]
diff --git a/kodereviewer/models/comments.py b/kodereviewer/models/comments.py
index 0d92e23..bc7eee0 100644
--- a/kodereviewer/models/comments.py
+++ b/kodereviewer/models/comments.py
@@ -60,17 +60,17 @@ class CommentModel(QAbstractListModel):
comment: Comment = self._pull_request._comments[index.row()]
if role == self.Roles.Body:
- return comment.body
+ return comment._body
if role == self.Roles.CreatedAt:
- return comment.created_at.strftime("%Y-%M-%d %H:%m")
+ return comment._created_at.strftime("%Y-%M-%d %H:%m")
if role == self.Roles.UpdatedAt:
- return comment.updated_at.strftime("%Y-%M-%d %H:%m")
+ return comment._updated_at.strftime("%Y-%M-%d %H:%m")
if role == self.Roles.Username:
- return comment.user.username
+ return comment._user._username
if role == self.Roles.AvatarUrl:
- return comment.user.avatar_url
+ return comment._user._avatar_url
if role == Qt.ItemDataRole.DisplayRole:
- return comment.body
+ return comment._body
return None
def rowCount(self, parent: QModelIndex | QPersistentModelIndex = QModelIndex()) -> int:
diff --git a/kodereviewer/models/file.py b/kodereviewer/models/file.py
index 43fcbe4..c8e4da6 100644
--- a/kodereviewer/models/file.py
+++ b/kodereviewer/models/file.py
@@ -174,7 +174,7 @@ class TreeFileModel(QAbstractItemModel):
def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
return 1
- def data(self, index: QModelIndex, role: int) -> Any:
+ def data(self, index: QModelIndex | QPersistentModelIndex, role: int = Qt.ItemDataRole.DisplayRole) -> Any:
if not index.isValid():
return ''
item: FileItem = index.internalPointer()
diff --git a/kodereviewer/models/reviews.py b/kodereviewer/models/reviews.py
new file mode 100644
index 0000000..81860fc
--- /dev/null
+++ b/kodereviewer/models/reviews.py
@@ -0,0 +1,295 @@
+from dataclasses import dataclass, field
+from enum import auto, IntEnum
+from logging import getLogger
+from typing import Optional, Self, Union
+
+from PySide6.QtCore import QAbstractItemModel, QAbstractListModel, QByteArray, QModelIndex, QObject, QPersistentModelIndex, QStandardPaths, QUrl, Qt, Signal, Slot, Property
+from PySide6.QtQml import QmlElement
+
+from kodereviewer.data import PullRequest, ReviewComment
+
+QML_IMPORT_NAME = "org.deprecated.kodereviewer"
+QML_IMPORT_MAJOR_VERSION = 1
+
+logger = getLogger(__name__)
+
+
+class Roles(IntEnum):
+ Body = Qt.ItemDataRole.UserRole + 1
+ CreatedAt = auto()
+ UpdatedAt = auto()
+ Username = auto()
+ AvatarUrl = auto()
+ Diff = auto()
+ Line = auto()
+
+
+# List model
+
+@dataclass
+class Thread(QObject):
+ id: int
+ diff: str = ''
+ reviews: list[ReviewComment] = field(default_factory=list)
+
+ def review_ids(self) -> list[int]:
+ return [review._id for review in self.reviews]
+
+
+class ReviewModel(QAbstractListModel):
+ _pull_request: Optional[PullRequest]
+ threads: list[Thread]
+
+ class Roles(IntEnum):
+ Id = Qt.ItemDataRole.UserRole + 1
+ Diff = auto()
+ Reviews = auto()
+
+ def __init__(self):
+ super().__init__()
+ self._pull_request = None
+ self.threads = []
+
+ pullRequestChanged = Signal()
+
+ def get_pull_request(self) -> Optional[PullRequest]:
+ return self._pull_request
+
+ def set_pull_request(self, pull_request: Optional[PullRequest]) -> None:
+ if pull_request is None:
+ return
+
+ if self._pull_request is not None and self._pull_request == pull_request:
+ return
+
+ self.beginResetModel()
+ self._pull_request = pull_request
+ self._pull_request.reviewsLoaded.connect(self._reset_model)
+ self.endResetModel()
+ self.pullRequestChanged.emit()
+
+ pullRequest = Property(PullRequest, fget=get_pull_request, fset=set_pull_request,
+ notify=pullRequestChanged)
+
+ def _reset_model(self):
+ assert self._pull_request is not None
+ self.beginResetModel()
+ self.load_reviews(self._pull_request._reviews)
+ self.endResetModel()
+
+ def load_reviews(self, reviews: list[ReviewComment]):
+ self.mapping: dict[int, Thread] = {}
+ for review in reviews:
+ logger.info('Processing %d', review.id)
+ if review._in_reply_to is not None:
+ thread = self.mapping[review._in_reply_to]
+ else:
+ if review.id not in self.mapping:
+ self.mapping[review._id] = Thread(id=review._id, diff=review._diff)
+ thread = self.mapping[review._id]
+ else:
+ thread = self.mapping[review._id]
+
+ thread.reviews.append(review)
+
+ self.threads = list(self.mapping.values())
+
+ def data(self,
+ index: QModelIndex | QPersistentModelIndex,
+ role: int = Qt.ItemDataRole.DisplayRole) -> object:
+
+ if self._pull_request is None:
+ return None
+
+ thread = self.threads[index.row()]
+
+ if role == self.Roles.Id:
+ return thread.id
+ if role == self.Roles.Diff:
+ return thread.diff
+ if role == self.Roles.Reviews:
+ return thread.reviews
+ if role == Qt.ItemDataRole.DisplayRole:
+ return f'Thread #{thread.id}'
+
+ return None
+
+
+ def rowCount(self, parent: QModelIndex | QPersistentModelIndex = QModelIndex()) -> int:
+ if self._pull_request is None:
+ return 0
+
+ return len(self.threads)
+
+ def roleNames(self) -> dict[int, QByteArray]:
+ return {
+ self.Roles.Id: QByteArray(b'id'),
+ self.Roles.Diff: QByteArray(b'diff'),
+ self.Roles.Reviews: QByteArray(b'reviews'),
+ }
+
+
+# Tree Model
+
+@dataclass
+class ThreadItem:
+ parent: "Root"
+ id: int
+ reviews: list["ReviewItem"] = field(default_factory=list)
+
+ def data(self, role: int):
+ return None
+
+
+@dataclass
+class ReviewItem:
+ parent: ThreadItem
+ id: int
+ review: ReviewComment
+
+ def data(self, role: int):
+
+ if role == Roles.Body:
+ return self.review._body
+ if role == Roles.CreatedAt:
+ return self.review._created_at.strftime("%Y-%M-%d %H:%m")
+ if role == Roles.UpdatedAt:
+ return self.review._updated_at.strftime("%Y-%M-%d %H:%m")
+ if role == Roles.Username:
+ return self.review._.username
+ if role == Roles.AvatarUrl:
+ return self.review._.avatar_url
+ if role == Roles.Diff:
+ return self.review.diff
+ if role == Roles.Line:
+ return self.review.line
+ if role == Qt.ItemDataRole.DisplayRole:
+ return self.review._body
+ return None
+
+
+@dataclass
+class Root:
+ threads: list[ThreadItem] = field(default_factory=list)
+
+ def data(self, role: int):
+ return None
+
+
+Item = Union[Root, ThreadItem, ReviewItem]
+
+@QmlElement
+class TreeReviewModel(QAbstractItemModel):
+
+ _pull_request: Optional[PullRequest]
+ root: Root
+
+ def __init__(self):
+ super().__init__()
+ self._pull_request = None
+ self.root = Root()
+
+ def get_pull_request(self) -> Optional[PullRequest]:
+ return self._pull_request
+
+ def set_pull_request(self, pull_request: Optional[PullRequest]) -> None:
+ if pull_request is None:
+ return
+
+ if self._pull_request is not None and self._pull_request == pull_request:
+ return
+
+ self.beginResetModel()
+ self._pull_request = pull_request
+ self._pull_request.reviewsLoaded.connect(self._reset_model)
+ self.endResetModel()
+ self.pullRequestChanged.emit()
+
+ pullRequestChanged = Signal()
+ pullRequest = Property(PullRequest, fget=get_pull_request, fset=set_pull_request,
+ notify=pullRequestChanged)
+
+ def load_reviews(self, reviews: list[ReviewComment]):
+ mapping: dict[int, ThreadItem] = {}
+ for review in reviews:
+ if review.id not in mapping:
+ thread = ThreadItem(self.root, review.id)
+ else:
+ thread = mapping[review.id]
+ thread.reviews.append(ReviewItem(thread, review.id, review))
+
+ def _reset_model(self) -> None:
+ if self._pull_request is None:
+ return
+
+ self.beginResetModel()
+ self.load_reviews(self._pull_request._reviews)
+ self.endResetModel()
+
+ def index(self, row: int, column: int,
+ parent: QModelIndex | QPersistentModelIndex = QModelIndex()) -> QModelIndex:
+ if not self.hasIndex(row, column, parent):
+ return QModelIndex()
+ if not parent.isValid():
+ if 0 <= row < len(self.root.threads):
+ return self.createIndex(row, column, self.root.threads[row])
+ else:
+ item: Root | ThreadItem = parent.internalPointer()
+ if isinstance(item, Root):
+ if 0 <= row < len(self.root.threads):
+ return self.createIndex(row, column, self.root.threads[row])
+ else:
+ if 0 <= row < len(item.reviews):
+ return self.createIndex(row, column, item.reviews[row])
+ return QModelIndex()
+
+ def parent(self, index: QModelIndex) -> QModelIndex:
+ if not index.isValid():
+ return QModelIndex()
+ item: Item = index.internalPointer()
+
+ if isinstance(item, Root):
+ return QModelIndex()
+ if isinstance(item, ThreadItem):
+ return self.createIndex(self.root.threads.index(item), 0, self.root)
+ if isinstance(item, ReviewItem):
+ return self.createIndex(item.parent.reviews.index(item), 0, item.parent)
+ raise ValueError(f'Unknown {item}')
+
+ def rowCount(self, index: QModelIndex | QPersistentModelIndex = QModelIndex()) -> int:
+ parent: Item
+ if not index.isValid():
+ return len(self.root.threads)
+
+ parent = index.internalPointer()
+
+ if isinstance(parent, Root):
+ return len(self.root.threads)
+ if isinstance(parent, ThreadItem):
+ return len(parent.reviews)
+ return 0
+
+ def columnCount(self, parent: QModelIndex | QPersistentModelIndex = QModelIndex()) -> int:
+ return 1
+
+ def data(self,
+ index: QModelIndex | QPersistentModelIndex,
+ role: int = Qt.ItemDataRole.DisplayRole) -> object:
+ if self._pull_request is None:
+ return None
+ reviews: list[ReviewComment] = self._pull_request._reviews
+ review: ReviewComment = reviews[index.row()]
+
+ item: Item = index.internalPointer()
+ return item.data(role)
+
+ def roleNames(self) -> dict[int, QByteArray]:
+ return {
+ Roles.Body: QByteArray(b'body'),
+ Roles.CreatedAt: QByteArray(b'createdAt'),
+ Roles.UpdatedAt: QByteArray(b'updatedAt'),
+ Roles.Username: QByteArray(b'username'),
+ Roles.AvatarUrl: QByteArray(b'avatarUrl'),
+ Roles.Diff: QByteArray(b'diff'),
+ Roles.Line: QByteArray(b'line'),
+ }
diff --git a/kodereviewer/network_manager.py b/kodereviewer/network_manager.py
index 3296153..089e69e 100644
--- a/kodereviewer/network_manager.py
+++ b/kodereviewer/network_manager.py
@@ -18,6 +18,7 @@ PULL_REQUEST_LIST_URL = re.compile(r'/pulls$')
COMMENT_LIST_URL = re.compile(r'/issues/(\d+)/comments')
FILE_LIST_URL = re.compile(r'/pulls/(\d+)/files')
CREATE_REVIEW_URL = re.compile(r'/pulls/(\d+)/reviews')
+REVIEW_COMMENTS_URL = re.compile(r'/pulls/(\d+)/comments')
logger = logging.getLogger(__name__)
@@ -90,6 +91,11 @@ class NetworkManager(QObject):
pull_request.load_files(response_body)
elif (match := CREATE_REVIEW_URL.search(reply.url().toString())):
logger.info(f'Got review reply: {response_body}')
+ elif (match := REVIEW_COMMENTS_URL.search(reply.url().toString())):
+ pull_request_number = int(match.groups()[0])
+ pull_request: Optional[PullRequest] = self._project.find_pull_request(pull_request_number)
+ if pull_request is not None:
+ pull_request.load_reviews(response_body)
else:
logger.info(f"Can't handle {reply.url()}")
@@ -111,6 +117,14 @@ class NetworkManager(QObject):
)
)
+ @Slot(int)
+ def getPullRequestReviews(self, pull_request_number: int) -> None:
+ self._manager.get(
+ self._request_factory.createRequest(
+ f'/pulls/{pull_request_number}/comments'
+ )
+ )
+
@Slot(int, str, str, str)
def createReview(
self, pull_request_number: str, commit_id: str,
diff --git a/kodereviewer/qml/Editor.qml b/kodereviewer/qml/Editor.qml
index 052933d..fdd1cbd 100644
--- a/kodereviewer/qml/Editor.qml
+++ b/kodereviewer/qml/Editor.qml
@@ -32,10 +32,10 @@ TextEdit {
font.family: "monospace"
Kirigami.SpellCheck.enabled: false
+
LineModel {
id: lineModel
document: root.textDocument
- onDocumentChanged: print('Document changed!')
}
onWidthChanged: lineModel.resetModel()
diff --git a/kodereviewer/qml/Main.qml b/kodereviewer/qml/Main.qml
index 1c5e951..c1be6b9 100644
--- a/kodereviewer/qml/Main.qml
+++ b/kodereviewer/qml/Main.qml
@@ -46,8 +46,6 @@ Kirigami.ApplicationWindow {
}
}
-
-
Loader {
id: treeFileModelLoader
active: !!pullRequest
diff --git a/kodereviewer/qml/MarkdownTextArea.qml b/kodereviewer/qml/MarkdownTextArea.qml
index 966b209..9debc1a 100644
--- a/kodereviewer/qml/MarkdownTextArea.qml
+++ b/kodereviewer/qml/MarkdownTextArea.qml
@@ -10,7 +10,8 @@ QQC2.TextArea {
placeholderText: "Leave a comment"
wrapMode: TextEdit.Wrap
- Kirigami.SpellCheck.enabled: true
+ Kirigami.SpellCheck.enabled: false
+
SyntaxHighlighter {
id: hightlighter
textEdit: root
diff --git a/kodereviewer/qml/PullRequestPage.qml b/kodereviewer/qml/PullRequestPage.qml
index cdcc1ec..5b52c3e 100644
--- a/kodereviewer/qml/PullRequestPage.qml
+++ b/kodereviewer/qml/PullRequestPage.qml
@@ -6,6 +6,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
+import org.kde.kirigamiaddons.components as KirigamiComponents
import org.deprecated.kodereviewer 1.0
@@ -20,6 +21,8 @@ Kirigami.ScrollablePage {
property string currentView: "info"
+ title: pullRequest ? pullRequest.title : ""
+
actions: [
Kirigami.Action {
id: reviewChangesAction
@@ -66,6 +69,16 @@ Kirigami.ScrollablePage {
}
Loader {
+ id: reviewLoader
+ active: !!root.pullRequest
+ sourceComponent: ReviewModel {
+ id: reviewModel
+ pullRequest: root.pullRequest
+ onPullRequestChanged: root.connection.getPullRequestReviews(root.pullRequest.number)
+ }
+ }
+
+ Loader {
id: fileModelLoader
active: !!root.pullRequest
sourceComponent: FileModel {
@@ -94,34 +107,39 @@ Kirigami.ScrollablePage {
Layout.fillHeight: true
//anchors.fill: parent
}
-
Kirigami.CardsListView {
- visible: !!root.pullRequest && root.currentView == "comments"
- //anchors.fill: parent
+ id: commentsListView
Layout.fillWidth: true
Layout.fillHeight: true
+ visible: !!root.pullRequest && root.currentView == "comments"
model: commentModelLoader.item
delegate: CommentDelegate {}
footerPositioning: ListView.OverlayFooter
}
+ ReviewList {
+ id: reviewListView
+ visible: !!root.pullRequest && root.currentView == "reviews"
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ model: reviewLoader.item
+ }
+
Editor {
+ id: editor
visible: !!root.pullRequest && root.currentView == "files"
-
Layout.fillWidth: true
Layout.fillHeight: true
- id: editor
text: ""
file: ""
- //fileModel: fileModelLoader.item
}
}
Connections {
target: contextDrawer
function onFileSelected(filename, text) {
- print("ASDF")
+ console.log("file changed!")
editor.filename = filename + '.diff'
editor.text = text
}
@@ -132,18 +150,36 @@ Kirigami.ScrollablePage {
Kirigami.Action {
icon.name: "info"
text: i18n("Info")
- onTriggered: root.currentView = "info"
+ onTriggered: {
+ root.currentView = "info"
+ //root.flickable = mainLayout
+ }
},
Kirigami.Action {
icon.name: "comment-symbolic"
text: i18n("Comments")
- onTriggered: root.currentView = "comments"
+ onTriggered: {
+ root.currentView = "comments"
+ //root.flickable = commentsListView
+ }
},
Kirigami.Action {
icon.name: "file-catalog-symbolic"
text: i18n("Files")
- onTriggered: root.currentView = "files"
+ onTriggered: {
+ root.currentView = "files"
+ //root.flickable = reviewListView
+ }
+ },
+ Kirigami.Action {
+ icon.name: "document-preview-symbolic"
+ text: i18n("Reviews")
+ onTriggered: {
+ root.currentView = "reviews"
+
+ //root.flickable = mainLayout
+ }
}
]
}
diff --git a/kodereviewer/qml/ReviewList.qml b/kodereviewer/qml/ReviewList.qml
new file mode 100644
index 0000000..e8821af
--- /dev/null
+++ b/kodereviewer/qml/ReviewList.qml
@@ -0,0 +1,84 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtCore
+import QtQuick.Controls as QQC2
+import QtQuick.Layouts
+
+import org.kde.kirigami as Kirigami
+import org.kde.kirigamiaddons.formcard as FormCard
+import org.kde.kirigamiaddons.components as KirigamiComponents
+
+
+Kirigami.CardsListView {
+ id: root
+
+ Kirigami.PlaceholderMessage {
+ visible: root.count == 0
+ anchors.centerIn: parent
+ text: "No reviews!"
+ }
+
+ delegate: Kirigami.AbstractCard {
+ id: delegate
+
+ required property int id
+ required property string diff
+ required property var reviews
+
+ clip: true
+
+ header: Editor {
+ text: delegate.diff
+ file: "bla.txt"
+ }
+
+ contentItem: Item {
+ implicitHeight: commentsLayout.implicitHeight
+ implicitWidth: commentsLayout.implicitWidth
+ ColumnLayout {
+ id: commentsLayout
+ anchors.fill: parent
+
+ Repeater {
+ model: delegate.reviews
+ ColumnLayout {
+ required property var modelData
+
+ Kirigami.Separator {
+ Layout.fillWidth: true
+ }
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ KirigamiComponents.Avatar {
+ name: modelData.user.username
+ source: modelData.user.avatarUrl
+ Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
+ Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
+ Layout.fillWidth: false
+ Layout.alignment: Qt.AlignTop
+ }
+ QQC2.Label {
+ text: `@${modelData.user.username}`
+ Layout.fillWidth: false
+ Layout.alignment: Qt.AlignTop
+ }
+ }
+ MarkdownLabel {
+ Layout.fillWidth: true
+ text: modelData.body
+ }
+
+ }
+ }
+
+ MarkdownTextArea {
+ id: addComment
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+}
+
diff --git a/org.deprecated.kodereviewer.yml b/org.deprecated.kodereviewer.yml
new file mode 100644
index 0000000..d179f88
--- /dev/null
+++ b/org.deprecated.kodereviewer.yml
@@ -0,0 +1,26 @@
+app-id: org.deprecated.kodereviewer
+runtime: org.kde.Platform
+runtime-version: "6.7"
+sdk: org.kde.Sdk
+base: io.qt.PySide.BaseApp
+base-version: "6.7"
+command: kodereviewer
+finish-args:
+ - --share-ipc
+ - --share=network
+ - --socket=fallback-x11
+ - --socker=wayland
+ - --device=dri
+modules:
+ - "python3-setuptools.json"
+ - "python3-wheel.json"
+ - name: kodereviewer
+ buildsystem: simple
+ build-commands:
+ - python -mbuild
+ - python -mpip install --prefix=/app --root=/ --no-deps .
+ sources:
+ - type: archive
+ path: "dist/kodereviewer-0.1.tar.gz"
+cleanup-commands:
+ - "/app/cleanup-BaseApp.sh"
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..3e9b360
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,5 @@
+pyside6
+#custom
+# KI18n
+#build
+hatch