diff --git a/lib/cubit/repo_cubit.dart b/lib/cubit/repo_cubit.dart index ec32b93..c175979 100644 --- a/lib/cubit/repo_cubit.dart +++ b/lib/cubit/repo_cubit.dart @@ -1,5 +1,4 @@ import 'package:bloc/bloc.dart'; -import 'package:bloc_concurrency/bloc_concurrency.dart'; import 'package:equatable/equatable.dart'; import 'package:gitea_client/cubit/repo_event.dart'; import 'package:gitea_client/model/repository.dart'; @@ -8,10 +7,6 @@ import 'package:stream_transform/stream_transform.dart'; part 'repo_state.dart'; -class RepoCubit extends Cubit { - RepoCubit() : super(RepoState()); -} - class RepoBloc extends Bloc { RepoBloc({required this.giteaService}) : super(const RepoState()) { on(_onRepoFetched, diff --git a/lib/cubit/search_bloc.dart b/lib/cubit/search_bloc.dart index 32d8f98..c7f78fa 100644 --- a/lib/cubit/search_bloc.dart +++ b/lib/cubit/search_bloc.dart @@ -24,61 +24,90 @@ class SearchBloc extends Bloc { transformer: (events, mapper) => events.switchMap(mapper), ); } - Future _SearchFetchedEvent( - SearchFetchedEvent event, Emitter emit) async { + + Future _SearchFetchedEvent(SearchFetchedEvent event, + Emitter emit) async { if (state.hasReachedMax) return; if (state.queryString.isEmpty) return; try { if (state.status == SearchStatus.initial) { - final repos = await giteaService.searchRepo( + final searchResult = await giteaService.searchRepo( query: state.queryString, page: 1, limit: 100); - return emit(state.copyWith( + if(searchResult.ok) { + return emit(state.copyWith( status: SearchStatus.success, - repos: repos, + repos: searchResult.data, loadedPages: 1, hasReachedMax: false, error_message: null, )); + }else { + emit(state.copyWith( + status: SearchStatus.failure, error_message: "No results")); + } } - final repos = await giteaService.searchRepo( + final searchResult = await giteaService.searchRepo( query: state.queryString, page: state.loadedPages + 1, limit: 100); final repoList = List.of(state.repos); - repos.forEach((element) { - if (repoList.where((selement) => selement.id == element.id).isEmpty) { - repoList.add(element); - } - }); - emit(repos.isEmpty - ? state.copyWith(hasReachedMax: true) - : state.copyWith( - status: SearchStatus.success, - repos: repoList, - loadedPages: state.loadedPages + 1, - hasReachedMax: false, - error_message: null, - )); + if(searchResult.ok) { + searchResult.data.forEach((element) { + if (repoList + .where((selement) => selement.id == element.id) + .isEmpty) { + repoList.add(element); + } + }); + emit(searchResult.data.isEmpty + ? state.copyWith(hasReachedMax: true) + : state.copyWith( + status: SearchStatus.success, + repos: repoList, + loadedPages: state.loadedPages + 1, + hasReachedMax: false, + error_message: null, + )); + }else { + emit(state.copyWith( + status: SearchStatus.failure, error_message: "No results")); + } } on Exception catch (e) { emit(state.copyWith( status: SearchStatus.failure, error_message: e.toString())); } } - Future _SearchInputEvent( - SearchInputEvent event, Emitter emit) async { - if (state.queryString.isEmpty) return; - print(event.queryText); + Future _SearchInputEvent(SearchInputEvent event, + Emitter emit) async { + if (event.queryText.isEmpty) { + emit(state.copyWith( + queryString: event.queryText, + status: SearchStatus.success, + repos: [], + loadedPages: 0, + hasReachedMax: false, + error_message: null, + )); + return; + } + + print("New state: ${event.queryText}"); try { - final repos = await giteaService.searchRepo( - query: event.queryText, page: 1, limit: 100); + final searchResult = await giteaService.searchRepo( + query: event.queryText, page: 1, limit: 100); + if(searchResult.ok) { return emit(state.copyWith( queryString: event.queryText, status: SearchStatus.success, - repos: repos, + repos: searchResult.data, loadedPages: 1, hasReachedMax: false, error_message: null, )); + }else { + emit(state.copyWith( + status: SearchStatus.failure, error_message: "No results")); + } } on Exception catch (e) { emit(state.copyWith( status: SearchStatus.failure, error_message: e.toString())); diff --git a/lib/model/SearchResult.dart b/lib/model/SearchResult.dart new file mode 100644 index 0000000..531e5b0 --- /dev/null +++ b/lib/model/SearchResult.dart @@ -0,0 +1,16 @@ +import 'package:gitea_client/model/repository.dart'; + +class SearchResult { + final bool ok; + final List data; + + const SearchResult(this.ok, this.data); + + SearchResult.fromJson(Map jsonM) : ok=jsonM['ok'], data = []{ + jsonM['data'].map((dynamic json) { + Repository repo = Repository.fromJson(json); + data.add(repo); + return repo; + }).toList() as List; + } +} \ No newline at end of file diff --git a/lib/service/gitea_service.dart b/lib/service/gitea_service.dart index 5ab0ec7..add028e 100644 --- a/lib/service/gitea_service.dart +++ b/lib/service/gitea_service.dart @@ -7,6 +7,7 @@ import 'package:gitea_client/model/user.dart'; import 'package:http/http.dart' as http; import '../model/File.dart'; +import '../model/SearchResult.dart'; User _parseAuthenticatedUserResponse(String message){ return User.fromJson(jsonDecode(message)); @@ -73,9 +74,9 @@ class GiteaService { throw Exception('error fetching posts'); } - Future> searchRepo({required String query,int page = 1, int limit = 10}) async{ + Future searchRepo({required String query,int page = 1, int limit = 10}) async{ var response = await http.get( - Uri.https(apiAccess.instance, "api/v1/user/repos/search", { + Uri.https(apiAccess.instance, "api/v1/repos/search", { "token": apiAccess.token, "q": query, "page" : page.toString(), @@ -83,10 +84,9 @@ class GiteaService { }), ); if (response.statusCode == 200) { - final body = json.decode(response.body) as List; - var result = body.map((dynamic json) { - return Repository.fromJson(json); - }).toList(); + + final body = json.decode(response.body); + var result = SearchResult.fromJson(body); return result; } diff --git a/lib/widget/search_list.dart b/lib/widget/search_list.dart index 3a72a12..de0b14b 100644 --- a/lib/widget/search_list.dart +++ b/lib/widget/search_list.dart @@ -22,37 +22,68 @@ class _SearchListState extends State { super.initState(); _scrollController.addListener(_onScroll); } + BuildContext? blocContex; + final search = TextEditingController(); @override Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - switch (state.status) { - case SearchStatus.failure: - String error_message = state.error_message!; - return Center(child: Text('failed to fetch $error_message')); - case SearchStatus.success: - if (state.repos.isEmpty) { - return const Center(child: Text('no repos')); + final media = MediaQuery.of(context).size; + return Column( + children: [ + Text( + "Search", + style: Theme.of(context).textTheme.headline4, + ), + TextField( + decoration: const InputDecoration( + labelText: "Search text", + ), + controller: search, + onChanged: (text) { + + if (blocContex != null) { + print("Input: ${search.text}"); + blocContex! + .read() + .add(SearchInputEvent(search.text)); } - if (state.repos.length < 5) { - context.read().add(SearchFetchedEvent()); + }, + ), + BlocBuilder( + builder: (context, state) { + blocContex = context; + switch (state.status) { + case SearchStatus.failure: + String error_message = state.error_message!; + return Center(child: Text('failed to fetch $error_message')); + case SearchStatus.success: + if (state.repos.isEmpty) { + return const Center(child: Text('no repos')); + } + if (state.repos.length < 5) { + context.read().add(SearchFetchedEvent()); + } + return SizedBox( + height: media.height -kToolbarHeight-130, + child: ListView.builder( + shrinkWrap: true, + itemBuilder: (BuildContext context, int index) { + return index >= state.repos.length + ? BottomLoader() + : RepoListItem(repo: state.repos[index],user: widget.user,); + }, + itemCount: state.hasReachedMax + ? state.repos.length + : state.repos.length + 1, + controller: _scrollController, + ), + ); + default: + return const Center(child: CircularProgressIndicator()); } - return ListView.builder( - itemBuilder: (BuildContext context, int index) { - return index >= state.repos.length - ? BottomLoader() - : RepoListItem(repo: state.repos[index],user: widget.user,); - }, - itemCount: state.hasReachedMax - ? state.repos.length - : state.repos.length + 1, - controller: _scrollController, - ); - default: - return const Center(child: CircularProgressIndicator()); - } - }, + }, + ), + ], ); } @@ -96,7 +127,6 @@ class RepoListItem extends StatelessWidget { final SavedUser user; @override Widget build(BuildContext context) { - final textTheme = Theme.of(context).textTheme; return Material( child: Container( diff --git a/lib/widget/search_page.dart b/lib/widget/search_page.dart index 1713a6f..7e9dc44 100644 --- a/lib/widget/search_page.dart +++ b/lib/widget/search_page.dart @@ -16,18 +16,10 @@ class SearchPage extends StatefulWidget { } class _SearchPage extends State { - final search = TextEditingController(); - @override - void initState() { - search.addListener(_onSearch); - } + void initState() {} - void _onSearch() { - print("Input: ${search.text}"); - context.read().add(SearchInputEvent(search.text)); - } @override Widget build(BuildContext context) { @@ -36,22 +28,14 @@ class _SearchPage extends State { child: SizedBox( width: (media.width > 600) ? media.width * 0.5 : media.width * 0.9, child: BlocProvider( - create: (_) => SearchBloc( - giteaService: GiteaService(apiAccess: widget.user.apiAccess)) - ..add(SearchInputEvent(search.text)), + create: (context) { + return SearchBloc( + giteaService: GiteaService(apiAccess: widget.user.apiAccess)) + ..add(SearchInputEvent("")); + }, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - "Search", - style: Theme.of(context).textTheme.headline4, - ), - TextField( - decoration: const InputDecoration( - labelText: "Search text", - ), - controller: search, - ), SearchList( user: widget.user, ) diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index f16b4c3..1fc8ed3 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -6,9 +6,6 @@ list(APPEND FLUTTER_PLUGIN_LIST url_launcher_linux ) -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) @@ -17,8 +14,3 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST}) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 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) diff --git a/pubspec.lock b/pubspec.lock index 15dc01c..a360e3f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -105,7 +105,7 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.16.0" + version: "1.15.0" convert: dependency: transitive description: @@ -147,7 +147,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.2.0" ffi: dependency: transitive description: @@ -251,7 +251,7 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.4" + version: "0.6.3" json_annotation: dependency: transitive description: @@ -300,7 +300,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.1.3" meta: dependency: transitive description: @@ -328,7 +328,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.0" path_provider_linux: dependency: transitive description: @@ -473,7 +473,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.8.1" stack_trace: dependency: transitive description: @@ -515,7 +515,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.8" typed_data: dependency: transitive description: @@ -585,7 +585,7 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.1" watcher: dependency: transitive description: @@ -615,5 +615,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=2.16.2 <3.0.0" flutter: ">=2.10.0"