diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore index 2d0ebc4..25ea8ba 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ /build/ # Web related +lib/generated_plugin_registrant.dart # Symbolication related app.*.symbols @@ -52,4 +53,4 @@ coverage .fvm sqflite_sw.js -sqlite3.wasm +sqlite3.wasm \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index a3868c6..8353687 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,8 +7,7 @@ { "name": "moa_app", "request": "launch", - "type": "dart", - "flutterMode": "debug" + "type": "dart" }, { "name": "moa_app (profile mode)", diff --git a/analysis_options.yaml b/analysis_options.yaml index 2531de0..eecf41d 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -27,10 +27,6 @@ linter: - comment_references - prefer_void_to_null - use_key_in_widget_constructors - - prefer_const_literals_to_create_immutables - - prefer_typing_uninitialized_variables - - unnecessary_getters_setters - - no_leading_underscores_for_local_identifiers analyzer: strong-mode: diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 332a547..f44a1a6 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -5,7 +5,7 @@ PODS: - AppAuth/Core (1.6.2) - AppAuth/ExternalUserAgent (1.6.2): - AppAuth/Core - - BranchSDK (2.2.1) + - BranchSDK (2.2.0) - Firebase/CoreOnly (10.12.0): - FirebaseCore (= 10.12.0) - firebase_core (2.15.1): @@ -15,7 +15,7 @@ PODS: - FirebaseCoreInternal (~> 10.0) - GoogleUtilities/Environment (~> 7.8) - GoogleUtilities/Logger (~> 7.8) - - FirebaseCoreInternal (10.15.0): + - FirebaseCoreInternal (10.12.0): - "GoogleUtilities/NSData+zlib (~> 7.8)" - Flutter (1.0.0) - flutter_branch_sdk (6.4.0): @@ -40,11 +40,11 @@ PODS: - AppAuth (~> 1.5) - GTMAppAuth (~> 1.3) - GTMSessionFetcher/Core (< 3.0, >= 1.1) - - GoogleUtilities/Environment (7.11.5): + - GoogleUtilities/Environment (7.11.4): - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.11.5): + - GoogleUtilities/Logger (7.11.4): - GoogleUtilities/Environment - - "GoogleUtilities/NSData+zlib (7.11.5)" + - "GoogleUtilities/NSData+zlib (7.11.4)" - GTMAppAuth (1.3.1): - AppAuth/Core (~> 1.6) - GTMSessionFetcher/Core (< 3.0, >= 1.5) @@ -160,11 +160,11 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570 - BranchSDK: cb046c2714b03e573484ce9e349e2ddbad7016e8 + BranchSDK: 8749d10e30725d08b6c188ab90e6fd6223d204db Firebase: 07150e75d142fb9399f6777fa56a187b17f833a0 firebase_core: 4a3246a02f828a01c74a2c26427037786d90f17f FirebaseCore: f86a1394906b97ac445ae49c92552a9425831bed - FirebaseCoreInternal: 2f4bee5ed00301b5e56da0849268797a2dd31fb4 + FirebaseCoreInternal: 950500ad8a08963657f6d8c67b579740c06d6aa1 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_branch_sdk: da3bece1a03160a8a021ef4ec3d426e89c6da169 flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef @@ -174,7 +174,7 @@ SPEC CHECKSUMS: FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a google_sign_in_ios: 1256ff9d941db546373826966720b0c24804bcdd GoogleSignIn: 5651ce3a61e56ca864160e79b484cd9ed3f49b7a - GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084 + GoogleUtilities: c63691989bf362ba0505507da00eeb326192e83e GTMAppAuth: 0ff230db599948a9ad7470ca667337803b3fc4dd GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2 image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 @@ -194,4 +194,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 8eb7cecb637c8d903f411e7008dc4a94863ea0c3 -COCOAPODS: 1.13.0 +COCOAPODS: 1.12.1 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 7a4d864..8431221 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -210,10 +210,10 @@ 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, - 6DCA4EFC2A15E5C200B62F90 /* Embed Foundation Extensions */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 03396E302AF4D338AAAA8637 /* [CP] Embed Pods Frameworks */, + 6DCA4EFC2A15E5C200B62F90 /* Embed Foundation Extensions */, ); buildRules = ( ); diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 2ccf710..f388651 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -60,16 +60,6 @@ com.googleusercontent.apps.152179311533-2lsvtrj7junkos93nd2oekpropcv8929 - - CFBundleTypeRole - Editor - CFBundleURLName - com.beside.moa - CFBundleURLSchemes - - https - - CFBundleVersion $(FLUTTER_BUILD_NUMBER) @@ -119,8 +109,6 @@ Need location when in use NSPhotoLibraryUsageDescription To upload photos, please allow permission to access your photo library, Pictures are displayed for the purpose of displaying and identifying stored content. - NSUserTrackingUsageDescription - App would like to access IDFA for tracking purpose UIApplicationSupportsIndirectInputEvents UILaunchStoryboardName @@ -144,18 +132,6 @@ UIViewControllerBasedStatusBarAppearance - branch_key - - live - key_live_cAdCkiozDTmbHUBKiCWYplbhrqfE9TOt - test - key_test_eunAdbdqxMhgMHBOaCXYobdouujyZVVL - - branch_universal_link_domains - - moayo.app.link - moayo-alternate.app.link - naverConsumerKey K10uUCEMBAnAY0ZtJMeo naverConsumerSecret diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements index 5cbb833..abed031 100644 --- a/ios/Runner/Runner.entitlements +++ b/ios/Runner/Runner.entitlements @@ -10,8 +10,7 @@ com.apple.developer.associated-domains - moa:moayo.app.link - moa:moayo-alternate.app.link + moa:example.com com.apple.security.application-groups diff --git a/ios/Runner/RunnerDebug.entitlements b/ios/Runner/RunnerDebug.entitlements index 5cbb833..abed031 100644 --- a/ios/Runner/RunnerDebug.entitlements +++ b/ios/Runner/RunnerDebug.entitlements @@ -10,8 +10,7 @@ com.apple.developer.associated-domains - moa:moayo.app.link - moa:moayo-alternate.app.link + moa:example.com com.apple.security.application-groups diff --git a/ios/fastlane/report.xml b/ios/fastlane/report.xml index e0ce2cc..9c2d2c4 100644 --- a/ios/fastlane/report.xml +++ b/ios/fastlane/report.xml @@ -5,17 +5,17 @@ - + - + - + diff --git a/lib/providers/content_detail_provider.dart b/lib/providers/content_detail_provider.dart index 5aba1d4..19d8698 100644 --- a/lib/providers/content_detail_provider.dart +++ b/lib/providers/content_detail_provider.dart @@ -37,8 +37,8 @@ class ContentDetail extends _$ContentDetail { } @override - Future build({required String id}) async { - return fetchItem(contentId: id); + Future build() async { + return null; } Future editContent({ @@ -56,8 +56,8 @@ class ContentDetail extends _$ContentDetail { contentMemo: contentMemo, hashTagStringList: hashTagStringList, ); - - return fetchItem(contentId: contentId); + var data = await fetchItem(contentId: contentId); + return data; }); } } diff --git a/lib/providers/folder_detail_provider.dart b/lib/providers/folder_detail_provider.dart index 4c46d9d..a06d889 100644 --- a/lib/providers/folder_detail_provider.dart +++ b/lib/providers/folder_detail_provider.dart @@ -11,13 +11,34 @@ part 'folder_detail_provider.g.dart'; @riverpod class FolderDetail extends _$FolderDetail { Future> fetchItem({ - required String folderId, + required String folderName, int? page, int? size, }) async { - // todo 처음에 불러오는 page==1 일때 데이터만 캐싱하는 방법을 찾아보자 + // get the [KeepAliveLink] + var link = ref.keepAlive(); + // a timer to be used by the callbacks below + Timer? timer; + // An object from package:dio that allows cancelling http requests + // When the provider is destroyed, cancel the http request and the timer + ref.onDispose(() { + timer?.cancel(); + }); + // When the last listener is removed, start a timer to dispose the cached data + ref.onCancel(() { + // start a 30 second timer + timer = Timer(const Duration(seconds: 30), () { + // dispose on timeout + link.close(); + }); + }); + // If the provider is listened again after it was paused, cancel the timer + ref.onResume(() { + timer?.cancel(); + }); + var data = await FolderRepository.instance.getFolderDetailList( - folderId: folderId, + folderName: folderName, page: page, size: size, ); @@ -25,26 +46,8 @@ class FolderDetail extends _$FolderDetail { } @override - Future?> build({required String folderId}) async { - return fetchItem(folderId: folderId); - } - - Future loadMore({ - required String folderId, - required int page, - }) async { - List res = []; - - state = await AsyncValue.guard(() async { - res = await fetchItem( - folderId: folderId, - page: page, - ); - - return [...state.value!, ...res]; - }); - - return res.length; + Future?> build() async { + return null; } Future refresh({required String folderName}) async { diff --git a/lib/repositories/folder_repository.dart b/lib/repositories/folder_repository.dart index a467de0..f8d5f8c 100644 --- a/lib/repositories/folder_repository.dart +++ b/lib/repositories/folder_repository.dart @@ -11,7 +11,7 @@ abstract class IFolderRepository { Future editFolderName( {required String currentFolderName, required String editFolderName}); Future> getFolderDetailList({ - required String folderId, + required String folderName, int? page, int? size, }); @@ -92,14 +92,14 @@ class FolderRepository implements IFolderRepository { @override Future> getFolderDetailList({ - required String folderId, + required String folderName, int? page = 0, int? size = 10, }) async { var token = await TokenRepository.instance.getToken(); var res = await dio.get( - '/api/v1/folder/detail/view?folderId=$folderId&page=$page&size=$size', + '/api/v1/folder/detail/view?folderName=$folderName&page=$page&size=$size', options: Options( headers: { 'Authorization': 'Bearer $token', diff --git a/lib/screens/home/content_view.dart b/lib/screens/home/content_view.dart index d6d9bbf..5ee82ee 100644 --- a/lib/screens/home/content_view.dart +++ b/lib/screens/home/content_view.dart @@ -6,6 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:moa_app/constants/color_constants.dart'; import 'package:moa_app/constants/file_constants.dart'; import 'package:moa_app/constants/font_constants.dart'; +import 'package:moa_app/models/content_model.dart'; import 'package:moa_app/providers/content_detail_provider.dart'; import 'package:moa_app/providers/folder_detail_provider.dart'; import 'package:moa_app/providers/folder_view_provider.dart'; @@ -36,7 +37,7 @@ class ContentView extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - var contentAsync = ref.watch(contentDetailProvider(id: id)); + var contentNotifier = ref.watch(contentDetailProvider.notifier); var hashtagAsync = ref.watch(hashtagViewProvider.notifier); var isEditMode = useState(false); @@ -49,12 +50,7 @@ class ContentView extends HookConsumerWidget { } } - void refreshCache() { - ref.refresh(folderDetailProvider(folderId: id)).value; - } - void pressConfirm() { - refreshCache(); context.pop(); } @@ -65,7 +61,9 @@ class ContentView extends HookConsumerWidget { void deleteContent() async { await hashtagAsync.deleteContent(contentId: id); await ref.read(folderViewProvider.notifier).refresh(); - ref.refresh(folderDetailProvider(folderId: id)).value; + await ref + .read(folderDetailProvider.notifier) + .refresh(folderName: folderName); if (context.mounted) { context.pop(); @@ -156,10 +154,6 @@ class ContentView extends HookConsumerWidget { return Scaffold( appBar: AppBarBack( - onPressedBack: () => { - refreshCache(), - context.pop(), - }, title: folderName, isBottomBorderDisplayed: false, actions: [ @@ -175,15 +169,47 @@ class ContentView extends HookConsumerWidget { ], ), body: SafeArea( - child: contentAsync.when( - data: (content) { + child: FutureBuilder( + future: contentNotifier.fetchItem(contentId: id), + builder: (context, snapshot) { + var content = snapshot.data; return AnimatedSwitcher( transitionBuilder: (child, animation) { return FadeTransition(opacity: animation, child: child); }, duration: const Duration(milliseconds: 300), child: () { - if (content != null) { + if ((snapshot.connectionState == ConnectionState.waiting) || + ref.watch(contentDetailProvider).isLoading) { + return const LoadingIndicator(); + } + if (snapshot.hasError) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + kDebugMode + ? snapshot.error.toString() + : '취향을 불러오는데 실패했습니다.', + style: const TextStyle( + color: AppColors.blackColor, + fontSize: 16, + fontWeight: FontWeight.w600, + fontFamily: FontConstants.pretendard, + ), + ), + Button( + onPressed: () { + ref.refresh(contentDetailProvider).value; + }, + margin: const EdgeInsets.only( + left: 100, right: 100, top: 20), + text: '다시 시도', + ), + ], + ); + } + if (snapshot.hasData && content != null) { return isEditMode.value ? SingleChildScrollView( padding: const EdgeInsets.only( @@ -332,30 +358,6 @@ class ContentView extends HookConsumerWidget { }(), ); }, - error: (error, stackTrace) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - kDebugMode ? error.toString() : '취향을 불러오는데 실패했습니다.', - style: const TextStyle( - color: AppColors.blackColor, - fontSize: 16, - fontWeight: FontWeight.w600, - fontFamily: FontConstants.pretendard, - ), - ), - Button( - onPressed: () { - ref.refresh(contentDetailProvider(id: id)).value; - }, - margin: const EdgeInsets.only(left: 100, right: 100, top: 20), - text: '다시 시도', - ), - ], - ); - }, - loading: () => const LoadingIndicator(), ), ), ); diff --git a/lib/screens/home/edit_content_view.dart b/lib/screens/home/edit_content_view.dart index 8024121..63a7797 100644 --- a/lib/screens/home/edit_content_view.dart +++ b/lib/screens/home/edit_content_view.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; @@ -7,7 +8,9 @@ import 'package:moa_app/constants/file_constants.dart'; import 'package:moa_app/constants/font_constants.dart'; import 'package:moa_app/models/content_model.dart'; import 'package:moa_app/providers/content_detail_provider.dart'; +import 'package:moa_app/providers/folder_view_provider.dart'; import 'package:moa_app/providers/hashtag_provider.dart'; +import 'package:moa_app/providers/hashtag_view_provider.dart'; import 'package:moa_app/repositories/content_repository.dart'; import 'package:moa_app/screens/add_content/add_image_content.dart'; import 'package:moa_app/utils/general.dart'; @@ -17,6 +20,7 @@ import 'package:moa_app/widgets/image.dart'; import 'package:moa_app/widgets/loading_indicator.dart'; import 'package:moa_app/widgets/moa_widgets/empty_image.dart'; import 'package:moa_app/widgets/moa_widgets/hashtag_box.dart'; +import 'package:moa_app/widgets/snackbar.dart'; class EditContentView extends HookConsumerWidget { const EditContentView({ @@ -39,19 +43,35 @@ class EditContentView extends HookConsumerWidget { var title = useState(content.contentName); var memo = useState(content.contentMemo); + var loading = useState(false); + Future saveEditContent() async { - await ref - .read(contentDetailProvider(id: content.contentId).notifier) - .editContent( - contentId: content.contentId, - contentName: titleController.text, - contentMemo: memoController.text, - hashTagStringList: hashtagList.value.join(','), - ); - // await ref.read(hashtagViewProvider.notifier).refresh(); - // await ref.read(folderViewProvider.notifier).refresh(); - isEditMode.value = false; + try { + loading.value = true; + await ContentRepository.instance.editContent( + contentId: content.contentId, + contentName: titleController.text, + contentMemo: memoController.text, + hashTagStringList: hashtagList.value.join(','), + ); + await ref.read(contentDetailProvider.notifier).editContent( + contentId: content.contentId, + contentName: titleController.text, + contentMemo: memoController.text, + hashTagStringList: hashtagList.value.join(','), + ); + await ref.read(hashtagViewProvider.notifier).refresh(); + await ref.read(folderViewProvider.notifier).refresh(); + isEditMode.value = false; + } catch (e) { + if (context.mounted) { + snackbar.alert( + context, kDebugMode ? e.toString() : '오류가 발생했습니다. 다시 시도해주세요.'); + } + } finally { + loading.value = false; + } } void showEditHashtagModal() { @@ -211,6 +231,7 @@ class EditContentView extends HookConsumerWidget { ), const SizedBox(height: 30), Button( + loading: loading.value, backgroundColor: AppColors.primaryColor, text: '변경 내용 저장', onPressed: saveEditContent, diff --git a/lib/screens/home/folder_detail_view.dart b/lib/screens/home/folder_detail_view.dart index 368bd6a..ee8f848 100644 --- a/lib/screens/home/folder_detail_view.dart +++ b/lib/screens/home/folder_detail_view.dart @@ -1,10 +1,10 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_branch_sdk/flutter_branch_sdk.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:moa_app/constants/color_constants.dart'; import 'package:moa_app/constants/file_constants.dart'; +import 'package:moa_app/models/content_model.dart'; import 'package:moa_app/providers/folder_detail_provider.dart'; import 'package:moa_app/screens/home/widgets/type_header.dart'; import 'package:moa_app/utils/router_provider.dart'; @@ -20,11 +20,9 @@ class FolderDetailView extends HookConsumerWidget { const FolderDetailView({ super.key, required this.folderName, - required this.id, required this.contentCount, }); final String folderName; - final String id; final int contentCount; @override @@ -34,25 +32,18 @@ class FolderDetailView extends HookConsumerWidget { var pageNum = useState(0); var hasMore = useState(true); var loading = useState(false); - var folderDetailAsync = ref.watch(folderDetailProvider(folderId: id)); + var folderDetailRefresher = useState(false); + var folderDetailNotifier = ref.watch(folderDetailProvider.notifier); Future pullToRefresh() async { - ref.refresh(folderDetailProvider(folderId: id)).value; + ref.refresh(folderDetailProvider).value; } void shareFolder() async { var encodeFolderName = Uri.encodeFull(folderName); - if (Platform.isIOS) { - var currentStatus = - await FlutterBranchSdk.getTrackingAuthorizationStatus(); - if (currentStatus == AppTrackingStatus.notDetermined) { - await FlutterBranchSdk.requestTrackingAuthorization(); - } - } BranchUniversalObject buo = BranchUniversalObject( canonicalIdentifier: - '${GoRoutes.folder.fullPath}/$id?folderName=$encodeFolderName&c=$contentCount', - + '${GoRoutes.folder.fullPath}/$encodeFolderName?c=$contentCount', title: '모아 폴더 공유', contentDescription: folderName, // imageUrl: @@ -64,6 +55,7 @@ class FolderDetailView extends HookConsumerWidget { feature: 'share', campaign: 'example_campaign', ); + BranchResponse response = await FlutterBranchSdk.getShortUrl( buo: buo, linkProperties: linkProperties); if (response.success) { @@ -77,15 +69,24 @@ class FolderDetailView extends HookConsumerWidget { void getContentList({required int page}) async { loading.value = true; - var length = await ref - .read(folderDetailProvider(folderId: id).notifier) - .loadMore(folderId: id, page: page); + var res = await folderDetailNotifier.fetchItem( + folderName: folderName, page: page); + if (page == 0) { + contentList.value = res; + } else { + contentList.value = [...contentList.value, ...res]; + } loading.value = false; - if (length < 10) { + if (res.length < 10) { hasMore.value = false; } } + useEffect(() { + getContentList(page: pageNum.value); + return null; + }, [folderDetailRefresher.value]); + useEffect(() { controller.addListener(() { /// load date at when scroll reached -100 @@ -122,47 +123,34 @@ class FolderDetailView extends HookConsumerWidget { return FadeTransition(opacity: animation, child: child); }, duration: const Duration(milliseconds: 300), - child: folderDetailAsync.when( - loading: () => const LoadingIndicator(), - error: (error, stackTrace) { - return const Center( - child: Text( - '에러가 발생했어요.\n다시 시도해주세요.', - textAlign: TextAlign.center, - ), - ); - }, - data: (contentList) { - return () { - if (contentList != null) { - return contentList.isEmpty - ? const EmptyContent(text: '저장된 취향이 없어요!\n취향을 저장해 주세요.') - : Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: Column( - children: [ - const SizedBox(height: 30), - TypeHeader( - count: contentCount, onPressFilter: () {}), - Expanded( - child: DynamicGridList( - controller: controller, - contentList: contentList, - pullToRefresh: pullToRefresh, - folderNameProp: folderName, - ), - ), - (loading.value && pageNum.value != 0) - ? const LoadingIndicator() - : const SizedBox(), - ], + child: () { + if (loading.value && pageNum.value == 0) { + return const LoadingIndicator(); + } + return contentList.value.isEmpty + ? const EmptyContent(text: '저장된 취향이 없어요!\n취향을 저장해 주세요.') + : Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: Column( + children: [ + const SizedBox(height: 30), + TypeHeader(count: contentCount, onPressFilter: () {}), + Expanded( + child: DynamicGridList( + controller: controller, + contentList: contentList.value, + pullToRefresh: pullToRefresh, + folderNameProp: folderName, + folderDetailRefresher: folderDetailRefresher, ), - ); - } - return const SizedBox(); - }(); - }, - ), + ), + (loading.value && pageNum.value != 0) + ? const LoadingIndicator() + : const SizedBox(), + ], + ), + ); + }(), )), ); } diff --git a/lib/screens/home/home.dart b/lib/screens/home/home.dart index 3369c5f..4153443 100644 --- a/lib/screens/home/home.dart +++ b/lib/screens/home/home.dart @@ -72,47 +72,46 @@ class Home extends HookConsumerWidget { headerSliverBuilder: (context, innerBoxIsScrolled) { return [ SliverAppBar( - toolbarHeight: 110, - titleSpacing: 15, - backgroundColor: AppColors.backgroundColor, - flexibleSpace: FlexibleSpaceBar( - background: Stack( - children: [ - Positioned( - right: 15, - top: 3, - child: Image( - width: 150, - height: 182, - image: Assets.moaBannerImg, + toolbarHeight: 110, + titleSpacing: 15, + backgroundColor: AppColors.backgroundColor, + flexibleSpace: FlexibleSpaceBar( + background: Stack( + children: [ + Positioned( + right: 15, + top: 3, + child: Image( + width: 150, + height: 182, + image: Assets.moaBannerImg, + ), ), - ), - ], - ), - ), - title: userAsync.when( - error: (error, stackTrace) { - return const SizedBox(); - }, - loading: () => Container( - margin: const EdgeInsets.only(right: 150), - alignment: Alignment.centerLeft, - child: const LoadingIndicator(), + ], + ), ), - data: (userInfo) { - return Container( + title: userAsync.when( + error: (error, stackTrace) { + return const SizedBox(); + }, + loading: () => Container( margin: const EdgeInsets.only(right: 150), alignment: Alignment.centerLeft, - child: RichText( - text: TextSpan( - text: '안녕하세요,\n${userInfo?.nickname}님!', - style: const H1TextStyle(), + child: const LoadingIndicator(), + ), + data: (userInfo) { + return Container( + margin: const EdgeInsets.only(right: 150), + alignment: Alignment.centerLeft, + child: RichText( + text: TextSpan( + text: '안녕하세요,\n${userInfo?.nickname}님!', + style: const H1TextStyle(), + ), ), - ), - ); - }, - ), - ), + ); + }, + )), SliverPersistentHeader( delegate: PersistentTabBar( tabController: tabController, @@ -200,13 +199,10 @@ class PersistentTabBar extends SliverPersistentHeaderDelegate { children: [ RichText( text: TextSpan( - style: const Body1TextStyle().merge( - const TextStyle( + style: const TextStyle( color: AppColors.blackColor, fontSize: 24, - fontWeight: FontConstants.fontWeightNormal, - ), - ), + fontWeight: FontConstants.fontWeightNormal), children: [ const TextSpan( text: '지금까지 모아온\n', @@ -282,10 +278,10 @@ class PersistentTabBar extends SliverPersistentHeaderDelegate { } @override - double get maxExtent => isEditScreen ? 98 : 117; + double get maxExtent => isEditScreen ? 99 : 117; @override - double get minExtent => isEditScreen ? 98 : 117; + double get minExtent => isEditScreen ? 99 : 117; @override bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { diff --git a/lib/screens/home/tab_view/folder_tab_view.dart b/lib/screens/home/tab_view/folder_tab_view.dart index 14378dd..73a4caa 100644 --- a/lib/screens/home/tab_view/folder_tab_view.dart +++ b/lib/screens/home/tab_view/folder_tab_view.dart @@ -11,7 +11,6 @@ import 'package:moa_app/constants/file_constants.dart'; import 'package:moa_app/models/folder_model.dart'; import 'package:moa_app/providers/folder_view_provider.dart'; import 'package:moa_app/repositories/folder_repository.dart'; -import 'package:moa_app/screens/home/folder_detail_view.dart'; import 'package:moa_app/screens/home/home.dart'; import 'package:moa_app/utils/general.dart'; import 'package:moa_app/utils/logger.dart'; @@ -59,25 +58,17 @@ class FolderTabView extends HookConsumerWidget { ); } - void goFolderDetailView({ - required String folderName, - required int contentCount, - required String folderId, - }) { + void goFolderDetailView( + {required String folderName, required int contentCount}) { context.go( - '${GoRoutes.folder.fullPath}/$folderId?folderName=$folderName&c=$contentCount', - extra: FolderDetailView( - folderName: folderName, - id: folderId, - contentCount: contentCount, - )); + '${GoRoutes.folder.fullPath}/$folderName?c=$contentCount', + ); } void showEditFolderModal({required String folderName}) { General.instance.showBottomSheet( context: context, child: EditContent( - maxLength: 10, title: '폴더명 수정', updatedContentName: updatedContentName, contentName: folderName, @@ -233,7 +224,6 @@ class FolderTabView extends HookConsumerWidget { onPress: () => goFolderDetailView( folderName: item.folderName, contentCount: item.count, - folderId: item.folderId, ), ); }, diff --git a/lib/screens/on_boarding/input_name_view.dart b/lib/screens/on_boarding/input_name_view.dart index 6dba370..d654833 100644 --- a/lib/screens/on_boarding/input_name_view.dart +++ b/lib/screens/on_boarding/input_name_view.dart @@ -9,7 +9,6 @@ import 'package:moa_app/repositories/non_member_repository.dart'; import 'package:moa_app/repositories/user_repository.dart'; import 'package:moa_app/screens/on_boarding/notice_view.dart'; import 'package:moa_app/utils/router_provider.dart'; -import 'package:moa_app/utils/utils.dart'; import 'package:moa_app/widgets/button.dart'; import 'package:moa_app/widgets/edit_text.dart'; import 'package:moa_app/widgets/moa_widgets/error_text.dart'; @@ -34,6 +33,13 @@ class InputNameView extends HookWidget { var isNextPage = useState(false); var focusNode = useFocusNode(); + bool validateNickname(String value) { + const pattern = r'^[가-힣]{2,8}$'; // 정규식 패턴: 한글 2~8글자 + var regex = RegExp(pattern); + + return regex.hasMatch(value); + } + void inputUserName() async { if (!isMember) { await NonMemberRepository.instance diff --git a/lib/screens/setting/setting.dart b/lib/screens/setting/setting.dart index d5d0e9d..4409133 100644 --- a/lib/screens/setting/setting.dart +++ b/lib/screens/setting/setting.dart @@ -10,12 +10,10 @@ import 'package:moa_app/providers/token_provider.dart'; import 'package:moa_app/providers/user_provider.dart'; import 'package:moa_app/screens/setting/widgets/setting_list_tile.dart'; import 'package:moa_app/utils/router_provider.dart'; -import 'package:moa_app/utils/utils.dart'; import 'package:moa_app/widgets/alert_dialog.dart'; import 'package:moa_app/widgets/button.dart'; import 'package:moa_app/widgets/edit_text.dart'; import 'package:moa_app/widgets/loading_indicator.dart'; -import 'package:moa_app/widgets/moa_widgets/error_text.dart'; import 'package:moa_app/widgets/snackbar.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -166,7 +164,6 @@ class Setting extends HookConsumerWidget { nickname.value = value; }, hintText: userInfo?.nickname, - maxLength: 8, ) : InkWell( overlayColor: MaterialStateProperty.all( @@ -183,8 +180,7 @@ class Setting extends HookConsumerWidget { editNicknameMode.value ? Button( loading: loading.value, - disabled: nickname.value.isEmpty || - !validateNickname(nickname.value), + disabled: nickname.value == '', onPressed: () => editMyNickname( nickname: nickname.value, ), @@ -209,13 +205,6 @@ class Setting extends HookConsumerWidget { ], ), const SizedBox(height: 3), - ErrorText( - alignment: MainAxisAlignment.center, - errorText: '이름은 한글 2~8자로 입력할 수 있어요.', - errorValidate: nickname.value.isNotEmpty && - !validateNickname(nickname.value), - ), - const SizedBox(height: 3), Text( userInfo?.email ?? '', style: const Body1TextStyle().merge(TextStyle( diff --git a/lib/screens/setting/widgets/edit_folder.dart b/lib/screens/setting/widgets/edit_folder.dart index eb87b2f..3675ada 100644 --- a/lib/screens/setting/widgets/edit_folder.dart +++ b/lib/screens/setting/widgets/edit_folder.dart @@ -47,7 +47,6 @@ class EditFolder extends HookConsumerWidget { context: context, isScrollControlled: true, child: EditContent( - maxLength: 10, title: '폴더명 수정', updatedContentName: updatedContentName, contentName: folderName, diff --git a/lib/screens/setting/widgets/setting_list_tile.dart b/lib/screens/setting/widgets/setting_list_tile.dart index faa4ec7..80bd983 100644 --- a/lib/screens/setting/widgets/setting_list_tile.dart +++ b/lib/screens/setting/widgets/setting_list_tile.dart @@ -19,9 +19,7 @@ class SettingListTile extends StatelessWidget { contentPadding: const EdgeInsets.symmetric(horizontal: 20), title: Text( title, - style: const H3TextStyle().merge( - const TextStyle(fontWeight: FontConstants.fontWeightMedium), - ), + style: const H3TextStyle(), ), trailing: trailing ?? Transform.rotate( diff --git a/lib/utils/router_provider.dart b/lib/utils/router_provider.dart index b419cca..5be9052 100644 --- a/lib/utils/router_provider.dart +++ b/lib/utils/router_provider.dart @@ -199,24 +199,23 @@ final routeProvider = Provider( GoRoute( parentNavigatorKey: _rootNavigatorKey, name: GoRoutes.folder.name, - path: '${GoRoutes.folder.path}/:folderId', + path: '${GoRoutes.folder.path}/:folderName', pageBuilder: (context, state) { - String folderId = state.pathParameters['folderId']!; late String decodeFolderName = - state.uri.queryParameters['folderName']!; + state.pathParameters['folderName']!; - if (isStringEncoded( - state.uri.queryParameters['folderName']!)) { + var parseCount = int.parse(state.uri.queryParameters['c']!); + + if (isStringEncoded(state.pathParameters['folderName']!)) { decodeFolderName = Uri.decodeFull( - state.uri.queryParameters['folderName'] ?? ''); + state.pathParameters['folderName'] ?? ''); } - var parseCount = int.parse(state.uri.queryParameters['c']!); + return buildIosPageTransitions( context: context, state: state, child: FolderDetailView( folderName: decodeFolderName, - id: folderId, contentCount: parseCount, ), ); diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 04334ec..46ecc86 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -38,10 +38,3 @@ bool isStringEncoded(String value) { return false; } } - -bool validateNickname(String value) { - const pattern = r'^[가-힣]{2,8}$'; // 정규식 패턴: 한글 2~8글자 - var regex = RegExp(pattern); - - return regex.hasMatch(value); -} diff --git a/lib/widgets/app_bar.dart b/lib/widgets/app_bar.dart index 6027c11..4fe8d80 100644 --- a/lib/widgets/app_bar.dart +++ b/lib/widgets/app_bar.dart @@ -55,15 +55,15 @@ class AppBarBack extends StatelessWidget implements PreferredSizeWidget { elevation: 0, titleSpacing: 0.0, centerTitle: true, - bottom: PreferredSize( - preferredSize: Size.fromHeight(bottomBorderStyle.height), - child: Container( - color: isBottomBorderDisplayed - ? bottomBorderStyle.color - : AppColors.whiteColor, - height: bottomBorderStyle.height, - ), - ), + bottom: isBottomBorderDisplayed + ? PreferredSize( + preferredSize: Size.fromHeight(bottomBorderStyle.height), + child: Container( + color: bottomBorderStyle.color, + height: bottomBorderStyle.height, + ), + ) + : null, actions: actions, ); } diff --git a/lib/widgets/moa_widgets/dynamic_grid_list.dart b/lib/widgets/moa_widgets/dynamic_grid_list.dart index 7b5b568..e70425c 100644 --- a/lib/widgets/moa_widgets/dynamic_grid_list.dart +++ b/lib/widgets/moa_widgets/dynamic_grid_list.dart @@ -34,7 +34,7 @@ class DynamicGridList extends HookWidget { required String folderName, String? contentUrl, }) async { - await context.push( + var val = await context.push( '${GoRoutes.content.fullPath}/$contentId', extra: ContentView( id: contentId, diff --git a/lib/widgets/moa_widgets/error_text.dart b/lib/widgets/moa_widgets/error_text.dart index fc86f5a..a1fcf91 100644 --- a/lib/widgets/moa_widgets/error_text.dart +++ b/lib/widgets/moa_widgets/error_text.dart @@ -10,12 +10,10 @@ class ErrorText extends HookWidget { required this.errorText, required this.errorValidate, this.padding, - this.alignment, }); final String errorText; final bool errorValidate; final EdgeInsets? padding; - final MainAxisAlignment? alignment; @override Widget build(BuildContext context) { @@ -28,7 +26,6 @@ class ErrorText extends HookWidget { ? Padding( padding: padding ?? const EdgeInsets.only(top: 5), child: Row( - mainAxisAlignment: alignment ?? MainAxisAlignment.start, children: [ Image( image: Assets.alert, diff --git a/pubspec.yaml b/pubspec.yaml index d030c0f..5b94e82 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,8 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.3+18 +version: 1.0.1+15 + environment: sdk: ">=3.0.0 <4.0.0" @@ -97,10 +98,10 @@ dev_dependencies: flutter_lints: ^2.0.1 test: ^1.22.0 mockito: ^5.3.2 + build_runner: ^2.3.3 # Rename App Package # flutter pub run change_app_package_name:main com.new.package.name change_app_package_name: ^1.1.0 - build_runner: ^2.3.3 freezed: ^2.3.2 json_serializable: ^6.5.4 riverpod_generator: ^2.2.1