diff --git a/lib/app.dart b/lib/app.dart index d740682..00c5a98 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -25,10 +25,10 @@ class MyApp extends StatelessWidget { return MultiProvider( providers: [ ChangeNotifierProvider( - create: (_) => ArticleStore(loginStore, client), + create: (_) => ArticleRepository(loginStore, client), ), ChangeNotifierProvider( - create: (_) => CategoryStore(client), + create: (_) => CategoryRepository(client), ), ChangeNotifierProvider( create: (_) => PostPageStore(), diff --git a/lib/models/api_repository.dart b/lib/models/api_client.dart similarity index 95% rename from lib/models/api_repository.dart rename to lib/models/api_client.dart index 0646769..2bbb788 100644 --- a/lib/models/api_repository.dart +++ b/lib/models/api_client.dart @@ -34,6 +34,12 @@ class ApiClient implements BaseClient { return lists; } + @override + Future> getFilteredArticles(String categoryId) { + // TODO: implement getFilteredArticles + throw UnimplementedError(); + } + @override Future postArticle(String title, File before, File after, String body, String categoryId, String userId) async { // base64 encode diff --git a/lib/models/base_repository.dart b/lib/models/base_client.dart similarity index 88% rename from lib/models/base_repository.dart rename to lib/models/base_client.dart index 922ded2..0e3196b 100644 --- a/lib/models/base_repository.dart +++ b/lib/models/base_client.dart @@ -4,11 +4,17 @@ import 'package:gottiesclient/models/entities/entities.dart'; abstract class BaseClient { Future> getArticles(); + + Future> getFilteredArticles(String categoryId); + Future postArticle(String title, File before, File after, String body, String categoryId, String userId); + Future deleteArticle(String id, String userID); + Future> getCategories(); /// いいね関係 Future likeArticle(String userID, String articleID); + Future unlikeArticle(String userID, String articleID); } diff --git a/lib/models/firestore_repository.dart b/lib/models/firestore_client.dart similarity index 88% rename from lib/models/firestore_repository.dart rename to lib/models/firestore_client.dart index 002b451..8001378 100644 --- a/lib/models/firestore_repository.dart +++ b/lib/models/firestore_client.dart @@ -13,6 +13,18 @@ class FirestoreClient implements BaseClient { @override Future> getArticles() async { final documents = (await _firestore.collection('articles').getDocuments()).documents; + return mapJsonToArticle(documents); + } + + @override + Future> getFilteredArticles(String categoryId) async { + final categoryRef = _firestore.collection('category').where('id', isEqualTo: categoryId); + final articleRef = _firestore.collection('articles'); + final documents = (await articleRef.where('category', isEqualTo: categoryRef).getDocuments()).documents; + return mapJsonToArticle(documents); + } + + Future> mapJsonToArticle(List documents) { return Future.wait( documents.map((document) async { final data = document.data; diff --git a/lib/models/models.dart b/lib/models/models.dart index 8c6268d..495e4fa 100644 --- a/lib/models/models.dart +++ b/lib/models/models.dart @@ -1,5 +1,5 @@ -export 'api_repository.dart'; -export 'base_repository.dart'; +export 'api_client.dart'; +export 'base_client.dart'; export 'custom_exception.dart'; export 'entities/entities.dart'; -export 'firestore_repository.dart'; +export 'firestore_client.dart'; diff --git a/lib/models/stores/article_repository.dart b/lib/models/stores/article_repository.dart new file mode 100644 index 0000000..ce4db90 --- /dev/null +++ b/lib/models/stores/article_repository.dart @@ -0,0 +1,88 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:gottiesclient/models/entities/article.dart'; +import 'package:gottiesclient/models/models.dart'; +import 'package:gottiesclient/models/stores/stores.dart'; + +class ArticleRepository extends ChangeNotifier { + ArticleRepository(LoginStore loginStore, BaseClient client) + : assert(client != null), + assert(loginStore != null), + _loginStore = loginStore, + _client = client { + getArticles(); + } + + final BaseClient _client; + final LoginStore _loginStore; + List
articles; + + String get userID => _loginStore.user?.uid; + + // TODO: try catchはStoreで + Future getArticles() async { + articles = await _client.getArticles(); + notifyListeners(); + } + + Future postArticle(String title, File before, File after, String body, String categoryId) async { + if (!_loginStore.isLoggedIn) { + await _loginStore.loginAnonymously(); + } + await _client.postArticle(title, before, after, body, categoryId, userID ?? ''); + } + + Future deleteArticle(Article article) async { + if (userID == article.userID) { + throw UnauthorisedException(); + } + await _client.deleteArticle(article.id, userID); + articles = articles.where((element) => element.id != article.id).toList(); + notifyListeners(); + } + + Future likeArticle(String articleID) async { + if (userID == null) { + throw UnauthorisedException(); + } + await _client.likeArticle(userID, articleID); + articles.forEach((article) { + if (article.id == articleID) { + article.likeUserIds.add(_loginStore.user.uid); + } + }); + notifyListeners(); + } + + bool isLike(String articleId) { + if (userID == null) { + return false; + } + final article = articles.firstWhere((article) => article.id == articleId); + final isLike = article.likeUserIds.contains(userID); + return isLike; + } + + Future unlikeArticle(String articleID) async { + if (userID == null) { + throw UnauthorisedException(); + } + await _client.unlikeArticle(userID, articleID); + articles.forEach((article) { + if (article.id == articleID) { + article.likeUserIds.remove(userID); + } + }); + notifyListeners(); + } + + Future filterArticles(Category category) async { + articles = await _client.getFilteredArticles(category.id); + notifyListeners(); + } + + bool isMyArticle(Article article) { + return article.userID == userID; + } +} diff --git a/lib/models/stores/article_store.dart b/lib/models/stores/article_store.dart deleted file mode 100644 index 5669a54..0000000 --- a/lib/models/stores/article_store.dart +++ /dev/null @@ -1,118 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; -import 'package:gottiesclient/models/entities/article.dart'; -import 'package:gottiesclient/models/models.dart'; -import 'package:gottiesclient/models/stores/stores.dart'; - -class ArticleStore extends ChangeNotifier { - ArticleStore(LoginStore loginStore, BaseClient client) - : assert(client != null), - assert(loginStore != null), - _loginStore = loginStore, - _client = client { - getArticles(); - } - - final BaseClient _client; - final LoginStore _loginStore; - List
_allArticles; - List
articles; - - String get userID => _loginStore.user?.uid; - - Future getArticles() async { - try { - _allArticles = await _client.getArticles(); - articles = _allArticles; - notifyListeners(); - } on Exception catch (e) { - debugPrint(e.toString()); - } - } - - Future postArticle(String title, File before, File after, String body, String categoryId) async { - try { - if (!_loginStore.isLoggedIn) { - await _loginStore.loginAnonymously(); - } - await _client.postArticle(title, before, after, body, categoryId, userID ?? ''); - notifyListeners(); - } on Exception catch (e) { - debugPrint(e.toString()); - } - } - - Future deleteArticle(Article article) async { - try { - if (userID == article.userID) { - throw UnauthorisedException(); - } - await _client.deleteArticle(article.id, userID); - _allArticles = _allArticles.where((element) => element.id != article.id).toList(); - articles = articles.where((element) => element.id != article.id).toList(); - notifyListeners(); - } on Exception catch (e) { - debugPrint(e.toString()); - } - } - - Future likeArticle(String articleID) async { - try { - if (userID == null) { - throw UnauthorisedException(); - } - await _client.likeArticle(userID, articleID); - _allArticles.forEach( - (article) { - if (article.id == articleID) { - article.likeUserIds.add(_loginStore.user.uid); - } - }, - ); - notifyListeners(); - } on Exception catch (e) { - debugPrint(e.toString()); - } - } - - bool isLike(String articleId) { - if (userID == null) { - return false; - } - final article = _allArticles.firstWhere((article) => article.id == articleId); - final isLike = article.likeUserIds.contains(userID); - return isLike; - } - - Future unlikeArticle(String articleID) async { - try { - if (userID == null) { - throw UnauthorisedException(); - } - await _client.unlikeArticle(userID, articleID); - _allArticles.forEach((article) { - if (article.id == articleID) { - article.likeUserIds.remove(userID); - } - }); - notifyListeners(); - } on Exception catch (e) { - debugPrint(e.toString()); - } - } - - void filterArticles(Category category) { - // TODO: APIが完成したらAPIを叩く - articles = _allArticles - .where( - (article) => article.category.id == category.id, - ) - .toList(); - notifyListeners(); - } - - bool isMyArticle(Article article) { - return article.userID == userID; - } -} diff --git a/lib/models/stores/category_store.dart b/lib/models/stores/category_repository.dart similarity index 75% rename from lib/models/stores/category_store.dart rename to lib/models/stores/category_repository.dart index d010540..6882148 100644 --- a/lib/models/stores/category_store.dart +++ b/lib/models/stores/category_repository.dart @@ -2,28 +2,26 @@ import 'package:flutter/material.dart'; import 'package:gottiesclient/models/entities/entities.dart'; import 'package:gottiesclient/models/models.dart'; -class CategoryStore extends ChangeNotifier { - CategoryStore(BaseClient client) +class CategoryRepository extends ChangeNotifier { + CategoryRepository(BaseClient client) : assert(client != null), _client = client { getCategories(); } final BaseClient _client; + List _categories; List searchedCategories; // カテゴリを選択していない状態(null) = 全てのカテゴリ Category selectedCategory; + // TODO: try catchはStoreで Future getCategories() async { - try { - _categories = await _client.getCategories(); - searchedCategories = _categories; - notifyListeners(); - } on Exception catch (e) { - debugPrint(e.toString()); - } + _categories = await _client.getCategories(); + searchedCategories = _categories; + notifyListeners(); } void searchCategory(String word) { diff --git a/lib/models/stores/stores.dart b/lib/models/stores/stores.dart index 11785d2..d6f77ae 100644 --- a/lib/models/stores/stores.dart +++ b/lib/models/stores/stores.dart @@ -1,5 +1,5 @@ -export 'article_store.dart'; -export 'category_store.dart'; +export 'article_repository.dart'; +export 'category_repository.dart'; export 'detail_store.dart'; export 'focus_node_store.dart'; export 'login_store.dart'; diff --git a/lib/pages/detail/widgets/content_container.dart b/lib/pages/detail/widgets/content_container.dart index 9d9e075..0880d11 100644 --- a/lib/pages/detail/widgets/content_container.dart +++ b/lib/pages/detail/widgets/content_container.dart @@ -1,8 +1,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:gottiesclient/models/entities/article.dart'; -import 'package:gottiesclient/models/stores/article_store.dart'; import 'package:gottiesclient/models/stores/share_store.dart'; +import 'package:gottiesclient/models/stores/stores.dart'; import 'package:gottiesclient/util/converter.dart'; import 'package:gottiesclient/widgets/icon_button_with_splash.dart'; import 'package:provider/provider.dart'; @@ -105,18 +105,18 @@ class ContentContainer extends StatelessWidget { width: 45, height: 45, icon: Icon( - Provider.of(context).isLike(article.id) + Provider.of(context).isLike(article.id) ? Icons.favorite : Icons.favorite_border, color: Colors.red, ), onTapButton: () { - final store = Provider.of(context, listen: false); - final isLike = store.isLike(article.id); + final repository = Provider.of(context, listen: false); + final isLike = repository.isLike(article.id); if (isLike) { - store.unlikeArticle(article.id); + repository.unlikeArticle(article.id); } else { - store.likeArticle(article.id); + repository.likeArticle(article.id); } }, ), @@ -130,13 +130,13 @@ class ContentContainer extends StatelessWidget { article.beforeImageURL, ), ), - if (Provider.of(context).isMyArticle(article)) + if (Provider.of(context).isMyArticle(article)) IconButtonWithSplash( width: 45, height: 45, icon: Icon(Icons.delete), onTapButton: () { - Provider.of(context, listen: false).deleteArticle(article); + Provider.of(context, listen: false).deleteArticle(article); Navigator.pop(context); }, ), diff --git a/lib/pages/home/article_list.dart b/lib/pages/home/article_list.dart index 85d1066..95cb840 100644 --- a/lib/pages/home/article_list.dart +++ b/lib/pages/home/article_list.dart @@ -44,7 +44,7 @@ class ArticleList extends StatelessWidget { alignment: Alignment.centerLeft, margin: const EdgeInsets.only(top: 16, left: 8, bottom: 8), child: Text( - '${Provider.of(context).selectedCategory?.title ?? 'ALL'}', + '${Provider.of(context).selectedCategory?.title ?? 'ALL'}', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), diff --git a/lib/pages/home/article_tile.dart b/lib/pages/home/article_tile.dart index 1e4db9b..14316bb 100644 --- a/lib/pages/home/article_tile.dart +++ b/lib/pages/home/article_tile.dart @@ -61,18 +61,18 @@ class ArticleTile extends StatelessWidget { const Expanded(child: SizedBox()), IconButton( icon: Icon( - Provider.of(context).isLike(article.id) + Provider.of(context).isLike(article.id) ? Icons.favorite : Icons.favorite_border, color: Colors.redAccent, ), onPressed: () async { - final store = Provider.of(context, listen: false); - final isLike = store.isLike(article.id); + final repository = Provider.of(context, listen: false); + final isLike = repository.isLike(article.id); if(isLike){ - await store.unlikeArticle(article.id); + await repository.unlikeArticle(article.id); }else{ - await store.likeArticle(article.id); + await repository.likeArticle(article.id); } }, ), diff --git a/lib/pages/home/category/category_list.dart b/lib/pages/home/category/category_list.dart index 17b7cbd..52cdc0e 100644 --- a/lib/pages/home/category/category_list.dart +++ b/lib/pages/home/category/category_list.dart @@ -14,7 +14,7 @@ class CategoryList extends StatelessWidget { @override Widget build(BuildContext context) { - final categories = Provider.of(context).searchedCategories; + final categories = Provider.of(context).searchedCategories; return categories == null ? const CircularProgressIndicator() : ListView.builder( diff --git a/lib/pages/home/category/category_modal.dart b/lib/pages/home/category/category_modal.dart index 2179068..829ca85 100644 --- a/lib/pages/home/category/category_modal.dart +++ b/lib/pages/home/category/category_modal.dart @@ -58,10 +58,10 @@ class _CategoryModalState extends State { Flexible( child: _buildCategoryList( context, - Provider.of(context).searchedCategories, + Provider.of(context).searchedCategories, (category) { - Provider.of(context, listen: false).filterArticles(category); - Provider.of(context, listen: false).onSelectCategory(category); + Provider.of(context, listen: false).filterArticles(category); + Provider.of(context, listen: false).onSelectCategory(category); Navigator.pop(context); }, ), diff --git a/lib/pages/home/home_page.dart b/lib/pages/home/home_page.dart index d62244e..d4d9367 100644 --- a/lib/pages/home/home_page.dart +++ b/lib/pages/home/home_page.dart @@ -35,10 +35,10 @@ class HomePage extends StatelessWidget { body: Column( children: [ ArticleList( - articles: Provider.of(context).articles, + articles: Provider.of(context).articles, onTapTile: (article) => Navigator.pushNamed(context, '/detail', arguments: article), onRefresh: () async { - await Provider.of(context, listen: false).getArticles(); + await Provider.of(context, listen: false).getArticles(); controller.refreshCompleted(); }, controller: controller, diff --git a/lib/pages/post/input_category.dart b/lib/pages/post/input_category.dart index 5237d8d..4726d06 100644 --- a/lib/pages/post/input_category.dart +++ b/lib/pages/post/input_category.dart @@ -21,7 +21,7 @@ class InputCategory extends StatelessWidget { borderRadius: BorderRadius.all(Radius.circular(10)), ), ), - onChanged: (word) => Provider.of(context, listen: false).searchCategory(word), + onChanged: (word) => Provider.of(context, listen: false).searchCategory(word), ), const SizedBox( height: 16, @@ -34,7 +34,7 @@ class InputCategory extends StatelessWidget { child: CategoryList( scrollDirection: Axis.horizontal, onTapCategory: (category) { - final store = Provider.of( + final store = Provider.of( context, listen: false, )..onSelectCategory(category); diff --git a/lib/pages/post/post_page.dart b/lib/pages/post/post_page.dart index 886e052..e248804 100644 --- a/lib/pages/post/post_page.dart +++ b/lib/pages/post/post_page.dart @@ -60,7 +60,7 @@ class _PostPageState extends State { _isLoading = true; }); //ダイアログ出す→トップに戻る確認は以下の3行をコメントアウトした状態で行いました! - await Provider.of(context, listen: false) + await Provider.of(context, listen: false) .postArticle(title, _beforeImage, _afterImage, body, selectedCategory.id); setState(() { _isLoading = false; @@ -114,14 +114,14 @@ class _PostPageState extends State { @override void initState() { - Provider.of(context, listen: false).getCategories(); + Provider.of(context, listen: false).getCategories(); super.initState(); } @override void didChangeDependencies() { super.didChangeDependencies(); - selectedCategory = Provider.of(context).selectedCategory; + selectedCategory = Provider.of(context).selectedCategory; } @override diff --git a/lib/widgets/search_text_field.dart b/lib/widgets/search_text_field.dart index 19a109b..2d94323 100644 --- a/lib/widgets/search_text_field.dart +++ b/lib/widgets/search_text_field.dart @@ -30,7 +30,7 @@ class SearchTextField extends StatelessWidget { ), onTap: onTapSearchBar, onChanged: (word) { - Provider.of(context, listen: false).searchCategory(word); + Provider.of(context, listen: false).searchCategory(word); }, ); }