Skip to content
代码片段 群组 项目
提交 b3c54da8 编辑于 作者: Neil Wang's avatar Neil Wang 提交者: 万友 朱
浏览文件

fix: #157 Not same with issue info between web and app

上级 d1396bb4
No related branches found
No related tags found
无相关合并请求
image: $CI_REGISTRY_IMAGE/flutter
stages:
- check
- build
- deploy
......@@ -13,7 +14,7 @@ default:
- export PATH="$PATH:$HOME/.pub-cache/bin"
code_quality:
stage: build
stage: check
script:
- flutter analyze --no-fatal-infos
- flutter_analyze_reporter --output=report.json --reporter=gitlab
......@@ -21,8 +22,8 @@ code_quality:
reports:
codequality: report.json
unit_test:
stage: build
test_all:
stage: check
script:
- flutter test --coverage --dart-define=REQUEST_ENV=test
- lcov -r coverage/lcov.info '*/__test*__/*' -o coverage/lcov_cleaned.info
......@@ -36,6 +37,7 @@ unit_test:
build_android:
stage: build
needs: [ "code_quality","test_all" ]
script:
- VERSION_NAME=$(cat pubspec.yaml | grep version | head -1 | awk '{print $2}' | awk -F+ '{print $1}')
- VERSION_CODE=$(cat pubspec.yaml | grep version | head -1 | awk '{print $2}' | awk -F+ '{print $1}')
......@@ -55,10 +57,12 @@ build_android:
expire_in: 2 days
reports:
dotenv: build.env
only:
- main
upload_apk:
stage: deploy
needs: ["build_android"]
needs: [ "build_android" ]
script:
- echo $VERSION_NAME
- chmod -R 777 build/app/outputs/apk/release
......
......@@ -16,14 +16,13 @@ class HttpRequest {
HttpRequest(this._environment, this._dio);
static HttpRequest instance() {
_impl._dio.options.headers[HttpHeaders.authorizationHeader] =
'Bearer ${TokenModel.accessToken()}';
_impl._dio.options.headers[HttpHeaders.authorizationHeader] = 'Bearer ${TokenModel.accessToken()}';
_impl._dio.interceptors.add(ErrorInterceptor());
return _impl;
}
Future<Response<T>> get<T>(String path) async {
return Response(await _dio.get(_environment.url() + path));
return Response(await _dio.get(_environment.url() + path.replaceAll(_environment.url(), '')));
}
Future<Response<T>> post<T>(String path, Map<String, dynamic> data) async {
......
class Author {
class Assignee {
int id;
String name;
String username;
String avatarUrl;
Author(this.id, this.name, this.username, this.avatarUrl);
Assignee(this.id, this.name, this.username, this.avatarUrl);
factory Author.fromJson(Map<String, dynamic> json) {
return Author(
factory Assignee.empty() {
return Assignee(0, '', '', '');
}
factory Assignee.fromJson(Map<String, dynamic> json) {
return Assignee(
json['id'], json['name'], json['username'], json['avatar_url']);
}
}
......@@ -11,7 +11,7 @@ class Issue {
String targetType;
Target target;
Project project;
Author author;
Assignee author;
Issue(this.id, this.targetUrl, this.createdAt, this.actionName, this.target,
this.project, this.author, this.targetType);
......@@ -24,7 +24,7 @@ class Issue {
json['action_name'] ?? "",
Target.fromJson(json['target']),
Project.fromJson(json['project']),
Author.fromJson(json['author']),
Assignee.fromJson(json['author']),
json['target_type'],
);
}
......
import '../common/data/time.dart';
import 'author.dart';
class IssueDetail {
......@@ -6,26 +7,49 @@ class IssueDetail {
int projectId;
String title;
String description;
String state;
String createdAt;
String projectName;
Author author;
Assignee author;
Assignee editor;
String updatedAt;
IssueDetail(this.id, this.iid, this.projectId, this.title, this.description, this.createdAt, this.projectName, this.state, this.author, this.editor, this.updatedAt);
IssueDetail(this.id, this.iid, this.projectId, this.title, this.description, this.createdAt, this.projectName, this.author);
String recentActivities() {
if (state == 'created') {
return "由 ${author.name} 创建于 ${Utils.formatTime(createdAt)}";
}
return "由 ${editor.name} 编辑于 ${Utils.formatTime(updatedAt)}";
}
factory IssueDetail.fromJson(Map<String, dynamic> issueJson, Map<String, dynamic> projectJson, Map<String, dynamic> recentEditResponse) {
var description = issueJson['description'].toString().replaceAll("/uploads/", "https://jihulab.com/${projectJson['path_with_namespace']}/uploads/").replaceAll('<br>', '\n');
var state = buildState(recentEditResponse);
var editor = buildAssignee(recentEditResponse);
var updatedAt = buildUpdatedAt(recentEditResponse);
return IssueDetail(issueJson['id'], issueJson['iid'], issueJson['project_id'], issueJson['title'], description, issueJson['created_at'], projectJson['name'], state,
Assignee.fromJson(issueJson['author']), editor, updatedAt);
}
static String buildState(Map<String, dynamic> recentEditResponse) {
if (recentEditResponse['updated_at'] == null && recentEditResponse['updated_by_name'] == null) {
return 'created';
}
return 'updated';
}
static Assignee buildAssignee(Map<String, dynamic> recentEditResponse) {
if (recentEditResponse['updated_at'] == null && recentEditResponse['updated_by_name'] == null) {
return Assignee.empty();
}
return Assignee(0, recentEditResponse['updated_by_name'], '', '');
}
factory IssueDetail.fromJson(Map<String, dynamic> issueJson, Map<String, dynamic> projectJson) {
var replaceAll = issueJson['description']
.toString()
.replaceAll("/uploads/", "https://jihulab.com/${projectJson['path_with_namespace']}/uploads/");
return IssueDetail(
issueJson['id'],
issueJson['iid'],
issueJson['project_id'],
issueJson['title'],
replaceAll.replaceAll('<br>', '\n'),
issueJson['created_at'],
projectJson['name'],
Author.fromJson(issueJson['author'])
);
static String buildUpdatedAt(Map<String, dynamic> recentEditResponse) {
if (recentEditResponse['updated_at'] == null && recentEditResponse['updated_by_name'] == null) {
return '';
}
return recentEditResponse['updated_at'];
}
}
\ No newline at end of file
}
......@@ -5,7 +5,7 @@ class Note {
String createdAt;
bool system;
String body;
Author author;
Assignee author;
String type;
Note(this.id, this.createdAt, this.body, this.system, this.author, this.type);
......@@ -15,6 +15,6 @@ class Note {
.toString()
.replaceAll("/uploads/", "https://jihulab.com/$pathWithNamespace/uploads/");
return Note(json['id'], json['created_at'], replaceAll, json['system'],
Author.fromJson(json['author']), json['type'] ?? "");
Assignee.fromJson(json['author']), json['type'] ?? "");
}
}
\ No newline at end of file
}
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:jihu_gitlab_app/common/data/enum/load_state.dart';
import 'package:jihu_gitlab_app/common/data/time.dart';
import 'package:jihu_gitlab_app/common/widgets/common_app_bar.dart';
import 'package:jihu_gitlab_app/common/widgets/toast_component.dart';
import 'package:jihu_gitlab_app/models/discussions.dart';
import 'package:jihu_gitlab_app/models/issue.dart';
import 'package:jihu_gitlab_app/models/note.dart';
import 'package:jihu_gitlab_app/pages/todo_list/widgets/comments_model.dart';
import 'package:jihu_gitlab_app/common/data/time.dart';
class Comments extends StatefulWidget {
final Issue issue;
......@@ -26,10 +26,7 @@ class _CommentsState extends State<Comments> {
@override
void initState() {
super.initState();
model
.getDiscussions(widget.issue.project.id, widget.issue.target.iid,
widget.issue.project.pathWithNamespace)
.then((value) => setState(() => {}));
model.getDiscussions(widget.issue).then((value) => setState(() => {}));
}
@override
......@@ -159,8 +156,7 @@ class _CommentsState extends State<Comments> {
context: context, message: '添加失败', img: addFail)
});
await model
.getDiscussions(widget.issue.project.id, widget.issue.target.iid,
widget.issue.project.pathWithNamespace)
.getDiscussions(widget.issue)
.then((value) => setState(() => {}));
_commentController.clear();
commentFocusNode.unfocus();
......@@ -262,7 +258,7 @@ class _CommentsState extends State<Comments> {
Row(
children: [
Text(
"由 ${model.issueDetail.author.name} 编辑于 ${Utils.formatTime(model.issueDetail.createdAt)}",
model.issueDetail.recentActivities(),
style: const TextStyle(
color: Color(0xFF87878C), fontWeight: FontWeight.w400),
),
......
......@@ -2,34 +2,31 @@ import 'package:jihu_gitlab_app/common/data/enum/load_state.dart';
import 'package:jihu_gitlab_app/common/net/http_request.dart';
import 'package:jihu_gitlab_app/models/author.dart';
import 'package:jihu_gitlab_app/models/discussions.dart';
import 'package:jihu_gitlab_app/models/issue.dart';
import 'package:jihu_gitlab_app/models/issue_detail.dart';
class CommentsModel {
IssueDetail issueDetail = IssueDetail(0, 0, 0, '标题', '',
'2022-10-14T15:46:18.762+08:00', '项目名', Author(0, '名字', '名字', ''));
IssueDetail issueDetail = IssueDetail(0, 0, 0, '标题', '', '2022-10-14T15:46:18.762+08:00', '项目名', 'created', Assignee.empty(), Assignee.empty(), '2022-10-14T15:46:18.762+08:00');
List<Discussion> comments = [];
LoadState _loadState = LoadState.loadingState;
Future getDiscussions(projectId, iid, pathWithNamespace) async {
Future getDiscussions(Issue issue) async {
int projectId = issue.project.id;
int iid = issue.target.iid;
comments = [];
try {
var response = await HttpRequest.instance().get<List<dynamic>>(
"/api/v4/projects/$projectId/issues/$iid/discussions");
var data = response
.body()
.map((e) => Discussion.fromJson(e, pathWithNamespace))
.toList();
comments =
data.where((element) => element.notes[0].system == false).toList();
var issueResponse = await HttpRequest.instance()
.get<Map<String, dynamic>>("/api/v4/projects/$projectId/issues/$iid");
var projectResponse = await HttpRequest.instance()
.get<Map<String, dynamic>>("/api/v4/projects/$projectId");
issueDetail =
IssueDetail.fromJson(issueResponse.body(), projectResponse.body());
var response = await HttpRequest.instance().get<List<dynamic>>("/api/v4/projects/$projectId/issues/$iid/discussions");
var data = response.body().map((e) => Discussion.fromJson(e, issue.project.pathWithNamespace)).toList();
comments = data.where((element) => element.notes[0].system == false).toList();
var issueResponse = await HttpRequest.instance().get<Map<String, dynamic>>("/api/v4/projects/$projectId/issues/$iid");
var projectResponse = await HttpRequest.instance().get<Map<String, dynamic>>("/api/v4/projects/$projectId");
var webUrl = projectResponse.body()['web_url'];
var recentEditResponse = await HttpRequest.instance().get<Map<String, dynamic>>("$webUrl/issues/$iid/realtime_changes");
issueDetail = IssueDetail.fromJson(issueResponse.body(), projectResponse.body(), recentEditResponse.body());
_loadState = LoadState.successState;
} catch (e) {
_loadState = LoadState.errorState;
......@@ -44,8 +41,7 @@ class CommentsModel {
Map<String, dynamic> data = {};
data['body'] = comments;
try {
await HttpRequest.instance().post<dynamic>(
"/api/v4/projects/$projectId/issues/$iid/discussions", data);
await HttpRequest.instance().post<dynamic>("/api/v4/projects/$projectId/issues/$iid/discussions", data);
} catch (e) {
_loadState = LoadState.errorState;
}
......
......@@ -21,6 +21,7 @@ dependencies:
json_annotation: ^4.7.0
shared_preferences: ^2.0.15
fluttertoast: ^8.1.1
path_provider: ^2.0.11
connectivity_plus: ^3.0.2
pretty_dio_logger: ^1.1.1
app_installer: ^1.1.0
......
......@@ -28,7 +28,7 @@ void main() {
"/projects", {"name": "test-project"}).reply(200, "test-project-id");
var instance = HttpRequest.instance();
Response<String> res =
await instance.post<String>("/projects", {"name": "test-project"});
await instance.post<String>("/projects", {"name": "test-project"});
expect(res.body(), 'test-project-id');
});
});
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册