Basic Repo overview
This commit is contained in:
parent
612e5aad18
commit
0f052d018c
11 changed files with 437 additions and 52 deletions
|
@ -1,8 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:gitea_client/model/repouser.dart';
|
||||
import 'package:gitea_client/model/user.dart';
|
||||
import 'package:gitea_client/widget/login_form.dart';
|
||||
import 'package:gitea_client/widget/login_status.dart';
|
||||
import 'package:gitea_client/widget/repo_list_page.dart';
|
||||
import 'package:gitea_client/widget/repo_overview.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'model/ApiAccess.dart';
|
||||
|
@ -23,11 +25,10 @@ class MyApp extends StatelessWidget {
|
|||
primarySwatch: Colors.lightGreen,
|
||||
),
|
||||
home: MyHomePage(),
|
||||
routes: {
|
||||
|
||||
},
|
||||
routes: {},
|
||||
onGenerateRoute: (route) {
|
||||
switch (route.name) { // <- here
|
||||
switch (route.name) {
|
||||
// <- here
|
||||
case "/loginstatus":
|
||||
return MaterialPageRoute(
|
||||
settings: const RouteSettings(name: "/parameterpage"),
|
||||
|
@ -38,12 +39,18 @@ class MyApp extends StatelessWidget {
|
|||
case "/repolist":
|
||||
return MaterialPageRoute(
|
||||
settings: const RouteSettings(name: "/repolist"),
|
||||
builder: (context) => RepoListPage(savedUser: route.arguments as SavedUser),
|
||||
builder: (context) =>
|
||||
RepoListPage(savedUser: route.arguments as SavedUser),
|
||||
);
|
||||
case "/repopage":
|
||||
final repouser = route.arguments as RepoUser;
|
||||
return MaterialPageRoute(
|
||||
settings: const RouteSettings(name: "/repopage"),
|
||||
builder: (context) =>
|
||||
RepoPage(repo: repouser.repository, user: repouser.user));
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -54,17 +61,15 @@ class MyHomePage extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _MyHomePage extends State<MyHomePage> {
|
||||
|
||||
late SharedPreferences prefs;
|
||||
ApiAccess? _apiAccess;
|
||||
var loggedIn = false;
|
||||
|
||||
|
||||
void _autoLogin() async {
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
final token = prefs.getString("token");
|
||||
final instance = prefs.getString("instance");
|
||||
if(token != null && instance != null) {
|
||||
if (token != null && instance != null) {
|
||||
await prefs.setBool("autoLogin", true);
|
||||
setState(() {
|
||||
loggedIn = true;
|
||||
|
@ -83,12 +88,12 @@ class _MyHomePage extends State<MyHomePage> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return (loggedIn) ? StatefulLoginStatus(apiAccess: _apiAccess!) : const LoginPage(title: "Login to Gitea");
|
||||
return (loggedIn)
|
||||
? StatefulLoginStatus(apiAccess: _apiAccess!)
|
||||
: const LoginPage(title: "Login to Gitea");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class LoginPage extends StatelessWidget {
|
||||
const LoginPage({Key? key, required this.title}) : super(key: key);
|
||||
|
||||
|
@ -118,4 +123,4 @@ class LoginPage extends StatelessWidget {
|
|||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
89
lib/model/File.dart
Normal file
89
lib/model/File.dart
Normal file
|
@ -0,0 +1,89 @@
|
|||
class RepoFile {
|
||||
String name;
|
||||
String path;
|
||||
String sha;
|
||||
String type;
|
||||
int size;
|
||||
String? encoding;
|
||||
String? content;
|
||||
String? target;
|
||||
String url;
|
||||
String htmlUrl;
|
||||
String gitUrl;
|
||||
String? downloadUrl;
|
||||
String? submoduleGitUrl;
|
||||
Links lLinks;
|
||||
|
||||
RepoFile(
|
||||
{required this.name,
|
||||
required this.path,
|
||||
required this.sha,
|
||||
required this.type,
|
||||
required this.size,
|
||||
this.encoding,
|
||||
this.content,
|
||||
this.target,
|
||||
required this.url,
|
||||
required this.htmlUrl,
|
||||
required this.gitUrl,
|
||||
this.downloadUrl,
|
||||
this.submoduleGitUrl,
|
||||
required this.lLinks});
|
||||
|
||||
RepoFile.fromJson(Map<String, dynamic> json)
|
||||
: name = json['name'],
|
||||
path = json['path'],
|
||||
sha = json['sha'],
|
||||
type = json['type'],
|
||||
size = json['size'],
|
||||
url = json['url'],
|
||||
htmlUrl = json['html_url'],
|
||||
gitUrl = json['git_url'],
|
||||
lLinks = Links.fromJson(json['_links']) {
|
||||
encoding = json['encoding'];
|
||||
content = json['content'];
|
||||
target = json['target'];
|
||||
downloadUrl = json['download_url'];
|
||||
submoduleGitUrl = json['submodule_git_url'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['name'] = name;
|
||||
data['path'] = path;
|
||||
data['sha'] = sha;
|
||||
data['type'] = type;
|
||||
data['size'] = size;
|
||||
data['encoding'] = encoding;
|
||||
data['content'] = content;
|
||||
data['target'] = target;
|
||||
data['url'] = url;
|
||||
data['html_url'] = htmlUrl;
|
||||
data['git_url'] = gitUrl;
|
||||
data['download_url'] = downloadUrl;
|
||||
data['submodule_git_url'] = submoduleGitUrl;
|
||||
data['_links'] = lLinks.toJson();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Links {
|
||||
String self;
|
||||
String git;
|
||||
String html;
|
||||
|
||||
Links({required this.self, required this.git, required this.html});
|
||||
|
||||
Links.fromJson(Map<String, dynamic> json)
|
||||
: self = json['self'],
|
||||
git = json['git'],
|
||||
html = json['html'];
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['self'] = self;
|
||||
data['git'] = git;
|
||||
data['html'] = html;
|
||||
return data;
|
||||
}
|
||||
}
|
10
lib/model/repouser.dart
Normal file
10
lib/model/repouser.dart
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
import 'package:gitea_client/model/repository.dart';
|
||||
import 'package:gitea_client/model/user.dart';
|
||||
|
||||
class RepoUser {
|
||||
final Repository repository;
|
||||
final SavedUser user;
|
||||
|
||||
RepoUser(this.repository, this.user);
|
||||
}
|
|
@ -6,6 +6,8 @@ import 'package:gitea_client/model/repository.dart';
|
|||
import 'package:gitea_client/model/user.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../model/File.dart';
|
||||
|
||||
User _parseAuthenticatedUserResponse(String message){
|
||||
return User.fromJson(jsonDecode(message));
|
||||
}
|
||||
|
@ -23,6 +25,16 @@ class GiteaService {
|
|||
);
|
||||
return compute(_parseAuthenticatedUserResponse, response.body);
|
||||
}
|
||||
|
||||
Future<RepoFile> getFile(String owner,String repo,String path) async{
|
||||
var response = await http.get(
|
||||
Uri.https(apiAccess.instance, "api/v1/repos/$owner/$repo/contents/$path", {
|
||||
"token": apiAccess.token,
|
||||
}),
|
||||
);
|
||||
|
||||
return RepoFile.fromJson(jsonDecode(response.body));
|
||||
}
|
||||
//
|
||||
Future<List<Repository>> getUserRepositories([int page = 1, int limit = 10]) async{
|
||||
var response = await http.get(
|
||||
|
|
|
@ -113,17 +113,15 @@ class _StatefulLoginStatus extends State<StatefulLoginStatus> {
|
|||
await prefs.setString('token', apiAccess.token);
|
||||
}
|
||||
|
||||
void _autoLogin() async{
|
||||
void _autoLogin() async {
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
bool? autologin = prefs.getBool("autoLogin");
|
||||
if(autologin != null){
|
||||
if (autologin != null) {
|
||||
userRequest!.then((user) => {
|
||||
Navigator.pushNamed(context, "/repolist",
|
||||
arguments: SavedUser(
|
||||
authedUser: user,
|
||||
apiAccess: widget.apiAccess))
|
||||
});
|
||||
|
||||
Navigator.of(context).pushReplacementNamed("/repolist",
|
||||
arguments:
|
||||
SavedUser(authedUser: user, apiAccess: widget.apiAccess))
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:gitea_client/cubit/repo_event.dart';
|
||||
import 'package:gitea_client/model/ApiAccess.dart';
|
||||
import 'package:gitea_client/model/repository.dart';
|
||||
import 'package:gitea_client/model/repouser.dart';
|
||||
import 'package:gitea_client/model/user.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../cubit/repo_cubit.dart';
|
||||
|
||||
class ReposList extends StatefulWidget {
|
||||
final SavedUser user;
|
||||
|
||||
const ReposList({Key? key, required this.user}) : super(key: key);
|
||||
@override
|
||||
_ReposListState createState() => _ReposListState();
|
||||
}
|
||||
|
@ -31,14 +38,14 @@ class _ReposListState extends State<ReposList> {
|
|||
if (state.repos.isEmpty) {
|
||||
return const Center(child: Text('no repos'));
|
||||
}
|
||||
if(state.repos.length < 5) {
|
||||
if (state.repos.length < 5) {
|
||||
context.read<RepoBloc>().add(RepoFetched());
|
||||
}
|
||||
return ListView.builder(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return index >= state.repos.length
|
||||
? BottomLoader()
|
||||
: RepoListItem(repo: state.repos[index]);
|
||||
: RepoListItem(repo: state.repos[index],user: widget.user,);
|
||||
},
|
||||
itemCount: state.hasReachedMax
|
||||
? state.repos.length
|
||||
|
@ -86,10 +93,10 @@ class BottomLoader extends StatelessWidget {
|
|||
}
|
||||
|
||||
class RepoListItem extends StatelessWidget {
|
||||
const RepoListItem({Key? key, required this.repo}) : super(key: key);
|
||||
const RepoListItem({Key? key, required this.repo, required this.user}) : super(key: key);
|
||||
|
||||
final Repository repo;
|
||||
|
||||
final SavedUser user;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
|
@ -97,24 +104,34 @@ class RepoListItem extends StatelessWidget {
|
|||
return Material(
|
||||
child: Container(
|
||||
color: (repo.private!) ? Colors.yellow[100] : Colors.white,
|
||||
child: ListTile(
|
||||
leading: (repo.mirror!) ? const Icon(Icons.amp_stories_outlined) : (repo.archived!) ? const Icon(Icons.archive) : const Icon(Icons.book) ,
|
||||
title: Text('${repo.owner.username}/${repo.name}'),
|
||||
isThreeLine: true,
|
||||
subtitle: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
(repo.description != null) ? Text(repo.description!) : Container(),
|
||||
(repo.mirror!) ? Text("Mirror of ${repo.originalUrl!}") : Container()
|
||||
],
|
||||
),
|
||||
dense: true,
|
||||
onTap: () => Scaffold
|
||||
.of(context)
|
||||
.showSnackBar(SnackBar(content: Text(repo.fullName!.toString()))),
|
||||
child: ListTile(
|
||||
leading: (repo.private!)
|
||||
? const Icon(Icons.lock)
|
||||
: (repo.mirror!)
|
||||
? const Icon(Icons.amp_stories_outlined)
|
||||
: (repo.archived!)
|
||||
? const Icon(Icons.archive)
|
||||
: const Icon(Icons.book),
|
||||
title: Text('${repo.owner.username}/${repo.name}'),
|
||||
isThreeLine: true,
|
||||
subtitle: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
(repo.description != null)
|
||||
? Text(repo.description!)
|
||||
: Container(),
|
||||
(repo.mirror!)
|
||||
? Text("Mirror of ${repo.originalUrl!}")
|
||||
: Container()
|
||||
],
|
||||
),
|
||||
dense: true,
|
||||
onTap: () => {
|
||||
Navigator.pushNamed(context, "/repopage",arguments: RepoUser(repo,user))
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ class _RepoListPage extends State<RepoListPage> {
|
|||
create: (_) => RepoBloc(
|
||||
giteaService: GiteaService(apiAccess: widget.savedUser.apiAccess))
|
||||
..add(RepoFetched()),
|
||||
child: ReposList(),
|
||||
child: ReposList(user: widget.savedUser, ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
223
lib/widget/repo_overview.dart
Normal file
223
lib/widget/repo_overview.dart
Normal file
|
@ -0,0 +1,223 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:badges/badges.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:gitea_client/model/repository.dart';
|
||||
import 'package:gitea_client/model/user.dart';
|
||||
import 'package:gitea_client/service/gitea_service.dart';
|
||||
|
||||
import '../model/File.dart';
|
||||
|
||||
class RepoPage extends StatefulWidget {
|
||||
final Repository repo;
|
||||
final SavedUser user;
|
||||
|
||||
const RepoPage({Key? key, required this.repo, required this.user})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_RepoPage createState() => _RepoPage();
|
||||
}
|
||||
|
||||
class _RepoPage extends State<RepoPage> {
|
||||
int _currentIndex = 0;
|
||||
|
||||
late final List _screens;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_screens = [
|
||||
RepoHome(
|
||||
repo: widget.repo,
|
||||
user: widget.user,
|
||||
),
|
||||
RepoFiles(
|
||||
repo: widget.repo,
|
||||
user: widget.user,
|
||||
),
|
||||
RepoIssues(
|
||||
repo: widget.repo,
|
||||
user: widget.user,
|
||||
),
|
||||
RepoPullRequests(
|
||||
repo: widget.repo,
|
||||
user: widget.user,
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
void _updateIndex(int value) {
|
||||
setState(() {
|
||||
_currentIndex = value;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.repo.name),
|
||||
),
|
||||
body: _screens[_currentIndex],
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
type: BottomNavigationBarType.fixed,
|
||||
currentIndex: _currentIndex,
|
||||
onTap: _updateIndex,
|
||||
selectedItemColor: Colors.green[700],
|
||||
selectedFontSize: 13,
|
||||
unselectedFontSize: 13,
|
||||
iconSize: 30,
|
||||
items: [
|
||||
const BottomNavigationBarItem(
|
||||
label: "Home",
|
||||
icon: Icon(Icons.home),
|
||||
),
|
||||
const BottomNavigationBarItem(
|
||||
label: "Files",
|
||||
icon: Icon(Icons.folder),
|
||||
),
|
||||
if (widget.repo.hasIssues!)
|
||||
BottomNavigationBarItem(
|
||||
label: "Issues",
|
||||
icon: (widget.repo.openIssuesCount! > 0)
|
||||
? Badge(
|
||||
badgeContent:
|
||||
Text(widget.repo.openIssuesCount!.toString()),
|
||||
child: const Icon(Icons.error_outline),
|
||||
)
|
||||
: const Icon(Icons.error_outline),
|
||||
),
|
||||
if (widget.repo.hasPullRequests!)
|
||||
BottomNavigationBarItem(
|
||||
label: "Pull requests",
|
||||
icon: (widget.repo.openPrCounter! > 0)
|
||||
? Badge(
|
||||
badgeContent: Text(widget.repo.openPrCounter!.toString()),
|
||||
child: const Icon(Icons.mediation_rounded),
|
||||
)
|
||||
: const Icon(Icons.mediation_rounded),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RepoHome extends StatefulWidget {
|
||||
final Repository repo;
|
||||
final SavedUser user;
|
||||
|
||||
const RepoHome({Key? key, required this.repo, required this.user})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_RepoHome createState() => _RepoHome();
|
||||
}
|
||||
|
||||
class _RepoHome extends State<RepoHome> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final media = MediaQuery.of(context).size;
|
||||
|
||||
return Column(children: [
|
||||
Text(widget.repo.fullName!,
|
||||
style: Theme.of(context).textTheme.headline3,),
|
||||
FutureBuilder<RepoFile>(
|
||||
future: readmeRequest,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Text("No Readme file found!",
|
||||
style: Theme.of(context).textTheme.headline6),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else if (snapshot.hasData) {
|
||||
var file = snapshot.data!;
|
||||
final content = utf8.decode(base64.decode(file.content!));
|
||||
|
||||
return SingleChildScrollView(child: Center(
|
||||
child: SizedBox(
|
||||
width: (media.width > 600) ? media.width * 0.6 : media.width*0.9,
|
||||
height: media.height*0.7,
|
||||
child: Markdown(selectable: true, data: content)),
|
||||
));
|
||||
} else {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
})
|
||||
]);
|
||||
}
|
||||
|
||||
Future<RepoFile>? readmeRequest;
|
||||
late final GiteaService giteaService;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
giteaService = GiteaService(apiAccess: widget.user.apiAccess);
|
||||
readmeRequest = giteaService.getFile(
|
||||
widget.repo.owner.username!, widget.repo.name, "README.md");
|
||||
}
|
||||
}
|
||||
|
||||
class RepoFiles extends StatefulWidget {
|
||||
final Repository repo;
|
||||
final SavedUser user;
|
||||
|
||||
const RepoFiles({Key? key, required this.repo, required this.user})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_RepoFiles createState() => _RepoFiles();
|
||||
}
|
||||
|
||||
class _RepoFiles extends State<RepoFiles> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
class RepoIssues extends StatefulWidget {
|
||||
final Repository repo;
|
||||
final SavedUser user;
|
||||
|
||||
const RepoIssues({Key? key, required this.repo, required this.user})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_RepoIssues createState() => _RepoIssues();
|
||||
}
|
||||
|
||||
class _RepoIssues extends State<RepoIssues> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
class RepoPullRequests extends StatefulWidget {
|
||||
final Repository repo;
|
||||
final SavedUser user;
|
||||
|
||||
const RepoPullRequests({Key? key, required this.repo, required this.user})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_RepoPullRequests createState() => _RepoPullRequests();
|
||||
}
|
||||
|
||||
class _RepoPullRequests extends State<RepoPullRequests> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
|
@ -6,6 +6,9 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||
url_launcher_linux
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
||||
foreach(plugin ${FLUTTER_PLUGIN_LIST})
|
||||
|
@ -14,3 +17,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
|
|||
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
|
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
|
||||
endforeach(plugin)
|
||||
|
||||
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
|
||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
|
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
|
||||
endforeach(ffi_plugin)
|
||||
|
|
39
pubspec.lock
39
pubspec.lock
|
@ -29,6 +29,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.2"
|
||||
badges:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: badges
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
bloc:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -98,7 +105,7 @@ packages:
|
|||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
version: "1.16.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -140,7 +147,7 @@ packages:
|
|||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.0"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -179,6 +186,13 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_markdown:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_markdown
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.10"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
@ -223,7 +237,7 @@ packages:
|
|||
name: js
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.3"
|
||||
version: "0.6.4"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -252,6 +266,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
markdown:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: markdown
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -265,7 +286,7 @@ packages:
|
|||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.3"
|
||||
version: "0.1.4"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -293,7 +314,7 @@ packages:
|
|||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
version: "1.8.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -438,7 +459,7 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.1"
|
||||
version: "1.8.2"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -480,7 +501,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.8"
|
||||
version: "0.4.9"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -550,7 +571,7 @@ packages:
|
|||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -580,5 +601,5 @@ packages:
|
|||
source: hosted
|
||||
version: "3.1.0"
|
||||
sdks:
|
||||
dart: ">=2.16.2 <3.0.0"
|
||||
dart: ">=2.17.0-0 <3.0.0"
|
||||
flutter: ">=2.10.0"
|
||||
|
|
|
@ -44,6 +44,8 @@ dependencies:
|
|||
stream_transform: ^2.0.0
|
||||
bloc_concurrency: ^0.2.0
|
||||
shared_preferences: ^2.0.13
|
||||
badges: ^2.0.2
|
||||
flutter_markdown: ^0.6.10
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
Loading…
Reference in a new issue