|
|
@@ -0,0 +1,181 @@ |
|
|
import 'package:flutter/material.dart'; |
|
|
import 'package:get/get.dart'; |
|
|
|
|
|
void main() { |
|
|
runApp(GetMaterialApp( |
|
|
initialRoute: '/home', |
|
|
getPages: [ |
|
|
GetPage( |
|
|
name: '/home', |
|
|
page: () => HomePage(), |
|
|
), |
|
|
GetPage( |
|
|
name: '/git-repositories', |
|
|
page: () => GitRepositoryPage(), |
|
|
binding: GitRepositoryBinding(), |
|
|
), |
|
|
], |
|
|
)); |
|
|
} |
|
|
|
|
|
class HomePage extends StatelessWidget { |
|
|
@override |
|
|
Widget build(BuildContext context) { |
|
|
return Scaffold( |
|
|
appBar: AppBar(title: Text('HOME')), |
|
|
body: Center( |
|
|
child: ElevatedButton( |
|
|
onPressed: () => Get.toNamed('/git-repositories'), |
|
|
child: Text('View GitHub Repositories'), |
|
|
), |
|
|
), |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
class GitRepositoryBinding extends Bindings { |
|
|
@override |
|
|
void dependencies() { |
|
|
Get.lazyPut(() => GitRepositoryProvider()); |
|
|
Get.put(GitRepositoryController(provider: Get.find())); |
|
|
} |
|
|
} |
|
|
|
|
|
class GitRepositoryModel { |
|
|
GitRepositoryModel({ |
|
|
required this.fullName, |
|
|
required this.description, |
|
|
required this.url, |
|
|
}); |
|
|
|
|
|
String fullName; |
|
|
String description; |
|
|
String url; |
|
|
|
|
|
factory GitRepositoryModel.fromJson(Map<String, dynamic> json) => |
|
|
GitRepositoryModel( |
|
|
fullName: json['full_name'], |
|
|
description: json['description'] ?? 'No description', |
|
|
url: json['html_url'], |
|
|
); |
|
|
|
|
|
static List<GitRepositoryModel> listFromJson(list) => |
|
|
List<GitRepositoryModel>.from( |
|
|
list.map((x) => GitRepositoryModel.fromJson(x))); |
|
|
} |
|
|
|
|
|
class GitRepositoryController extends GetxController |
|
|
with StateMixin<List<GitRepositoryModel>>, ScrollMixin { |
|
|
final GitRepositoryProvider provider; |
|
|
GitRepositoryController({required this.provider}); |
|
|
|
|
|
List<GitRepositoryModel> repositories = []; |
|
|
final int repositoriesPerPage = 10; |
|
|
int page = 1; |
|
|
bool getFirstData = false; |
|
|
bool lastPage = false; |
|
|
|
|
|
@override |
|
|
void onInit() { |
|
|
findAllGitRepositories(); |
|
|
super.onInit(); |
|
|
} |
|
|
|
|
|
Future<void> findAllGitRepositories() async { |
|
|
await provider.getGitRepositories(repositoriesPerPage, page).then((result) { |
|
|
final bool emptyRepositories = result.body?.isEmpty ?? true; |
|
|
if (!getFirstData && emptyRepositories) { |
|
|
change(null, status: RxStatus.empty()); |
|
|
} else if (getFirstData && emptyRepositories) { |
|
|
lastPage = true; |
|
|
} else { |
|
|
getFirstData = true; |
|
|
repositories.addAll(result.body!); |
|
|
change(repositories, status: RxStatus.success()); |
|
|
} |
|
|
}, onError: (err) { |
|
|
change(null, status: RxStatus.error(err.toString())); |
|
|
}); |
|
|
} |
|
|
|
|
|
@override |
|
|
Future<void> onEndScroll() async { |
|
|
print('onEndScroll'); |
|
|
if (!lastPage) { |
|
|
page += 1; |
|
|
Get.dialog(Center(child: LinearProgressIndicator())); |
|
|
await findAllGitRepositories(); |
|
|
Get.back(); |
|
|
} else { |
|
|
Get.snackbar('Alert', 'End of Repositories'); |
|
|
} |
|
|
} |
|
|
|
|
|
@override |
|
|
Future<void> onTopScroll() async { |
|
|
print('onTopScroll'); |
|
|
} |
|
|
} |
|
|
|
|
|
class GitRepositoryProvider extends GetConnect { |
|
|
final String org = 'flutter'; |
|
|
|
|
|
@override |
|
|
void onInit() { |
|
|
// All request will pass to jsonEncode so CasesModel.fromJson() |
|
|
httpClient.defaultDecoder = GitRepositoryModel.listFromJson; |
|
|
httpClient.baseUrl = 'https://api.github.com/orgs'; |
|
|
} |
|
|
|
|
|
Future<Response<List<GitRepositoryModel>>> getGitRepositories( |
|
|
int itemsPerPage, int page) => |
|
|
get<List<GitRepositoryModel>>( |
|
|
'/$org/repos?per_page=$itemsPerPage&page=$page', |
|
|
// query: {'orderBy': 'nome'}, |
|
|
decoder: GitRepositoryModel.listFromJson, |
|
|
); |
|
|
} |
|
|
|
|
|
class GitRepositoryPage extends GetView<GitRepositoryController> { |
|
|
@override |
|
|
Widget build(BuildContext context) { |
|
|
return Scaffold( |
|
|
appBar: AppBar(title: Text('Repositories')), |
|
|
body: Container( |
|
|
child: controller.obx( |
|
|
(state) => ListView.builder( |
|
|
controller: controller.scroll, |
|
|
itemCount: state?.length, |
|
|
itemBuilder: (context, index) { |
|
|
final GitRepositoryModel repository = state![index]; |
|
|
return ListTile( |
|
|
isThreeLine: true, |
|
|
leading: Text( |
|
|
(++index).toString(), |
|
|
style: TextStyle(fontSize: 20), |
|
|
), |
|
|
title: Text(repository.fullName), |
|
|
subtitle: |
|
|
Text('${repository.description}\n${repository.url}'), |
|
|
); |
|
|
}, |
|
|
), |
|
|
onLoading: Center(child: LinearProgressIndicator()), |
|
|
onEmpty: Center( |
|
|
child: Text( |
|
|
'Repositories no found', |
|
|
style: TextStyle(fontSize: 18), |
|
|
textAlign: TextAlign.center, |
|
|
), |
|
|
), |
|
|
onError: (error) => Center( |
|
|
child: Text( |
|
|
'Error: Cannot get repositories \n$error', |
|
|
style: TextStyle(fontSize: 18), |
|
|
textAlign: TextAlign.center, |
|
|
), |
|
|
), |
|
|
), |
|
|
)); |
|
|
} |
|
|
} |