├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ └── project.pbxproj ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── RunnerTests │ └── RunnerTests.swift └── .gitignore ├── lib ├── features │ ├── onboarding_screen │ │ └── presenter │ │ │ ├── widgets │ │ │ ├── scroll_chips_widget.dart │ │ │ └── chip_button.dart │ │ │ ├── bloc │ │ │ ├── on_boarding_event.dart │ │ │ ├── on_boarding_state.dart │ │ │ └── on_boarding_bloc.dart │ │ │ └── onboarding_screen.dart │ ├── home_screen │ │ ├── domain │ │ │ ├── entities │ │ │ │ ├── author_from_book_entity.dart │ │ │ │ └── book_from_author_entity.dart │ │ │ └── repositories │ │ │ │ └── books_repository.dart │ │ ├── presenter │ │ │ ├── bloc │ │ │ │ ├── home_event.dart │ │ │ │ ├── home_state.dart │ │ │ │ └── home_bloc.dart │ │ │ └── page │ │ │ │ ├── widgets │ │ │ │ ├── book_swipper │ │ │ │ │ ├── bloc │ │ │ │ │ │ ├── books_swipper_event.dart │ │ │ │ │ │ ├── books_swipper_state.dart │ │ │ │ │ │ └── books_swipper_bloc.dart │ │ │ │ │ └── books_swipper.dart │ │ │ │ ├── avatar_widget.dart │ │ │ │ └── book_card.dart │ │ │ │ └── home_screen.dart │ │ └── data │ │ │ └── datasources │ │ │ └── books_repository_impl.dart │ ├── shared │ │ └── app_shell │ │ │ ├── bloc │ │ │ ├── app_shell_event.dart │ │ │ ├── app_shell_state.dart │ │ │ └── app_shell_bloc.dart │ │ │ └── app_shell.dart │ └── detail_book │ │ └── presenter │ │ ├── widgets │ │ ├── animated_text.dart │ │ └── card_detail_book.dart │ │ └── detail_book_screen.dart ├── core │ └── constants │ │ └── app_colors.dart └── main.dart ├── screenshots ├── book-summary-app-gif.gif └── screenshot-book-sumary.png ├── android ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── book_summary_app │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── build.gradle └── settings.gradle ├── .gitignore ├── README.md ├── test └── widget_test.dart ├── analysis_options.yaml ├── .metadata ├── pubspec.yaml ├── pubspec.lock └── assets └── icons └── triangle-fixed.svg /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /lib/features/onboarding_screen/presenter/widgets/scroll_chips_widget.dart: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /screenshots/book-summary-app-gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/screenshots/book-summary-app-gif.gif -------------------------------------------------------------------------------- /screenshots/screenshot-book-sumary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/screenshots/screenshot-book-sumary.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolojoaquinp/book_summary_app/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/book_summary_app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.book_summary_app 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/features/home_screen/domain/entities/author_from_book_entity.dart: -------------------------------------------------------------------------------- 1 | class AuthorFromBookEntity { 2 | final String id; 3 | final String name; 4 | 5 | const AuthorFromBookEntity({ 6 | required this.id, 7 | required this.name, 8 | }); 9 | } -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip 6 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/to/reference-keystore 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/core/constants/app_colors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppColors { 4 | static Color greenLime = const Color(0xffCCFF36); 5 | static Color violetTropitalIndigo = const Color(0xff8583FF); 6 | static Color yellowSelective = const Color(0xffFFBD12); 7 | static Color gunMetal = const Color(0xff20282F); 8 | } -------------------------------------------------------------------------------- /ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /lib/features/home_screen/domain/repositories/books_repository.dart: -------------------------------------------------------------------------------- 1 | // import 'package:book_summary_app/features/home_screen/data/models/book_from_author_model.dart'; 2 | 3 | // typedef GetFutureBooksFromAuthor = Future,String>>; 4 | 5 | abstract class BooksRepository { 6 | //Future> getBooks(); 7 | // GetFutureBooksFromAuthor getBooksFromAuthorId(String idAuthor); 8 | } -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = "../build" 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(":app") 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/features/shared/app_shell/bloc/app_shell_event.dart: -------------------------------------------------------------------------------- 1 | part of 'app_shell_bloc.dart'; 2 | 3 | sealed class AppShellEvent extends Equatable { 4 | const AppShellEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | class AppShellPageChangedEvent extends AppShellEvent { 10 | const AppShellPageChangedEvent(this.pageIndex); 11 | 12 | final int pageIndex; 13 | 14 | @override 15 | List get props => [pageIndex]; 16 | } 17 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/home_screen/presenter/bloc/home_event.dart: -------------------------------------------------------------------------------- 1 | part of 'home_bloc.dart'; 2 | 3 | sealed class HomeEvent extends Equatable { 4 | const HomeEvent(); 5 | 6 | } 7 | 8 | class HomeInitialEvent extends HomeEvent { 9 | const HomeInitialEvent(); 10 | @override 11 | List get props => []; 12 | } 13 | 14 | 15 | class NavigationAnimationEventInitial extends HomeEvent { 16 | const NavigationAnimationEventInitial(); 17 | 18 | @override 19 | List get props => []; 20 | } 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /lib/features/shared/app_shell/bloc/app_shell_state.dart: -------------------------------------------------------------------------------- 1 | part of 'app_shell_bloc.dart'; 2 | 3 | class AppShellState extends Equatable { 4 | final int currentPageIndex; 5 | 6 | const AppShellState({ 7 | this.currentPageIndex = 0, 8 | }); 9 | 10 | AppShellState copyWith({ 11 | int? currentPageIndex, 12 | }) { 13 | return AppShellState( 14 | currentPageIndex: currentPageIndex ?? this.currentPageIndex, 15 | ); 16 | } 17 | 18 | @override 19 | List get props => [currentPageIndex]; 20 | } -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/shared/app_shell/bloc/app_shell_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | part 'app_shell_event.dart'; 5 | part 'app_shell_state.dart'; 6 | 7 | class AppShellBloc extends Bloc { 8 | AppShellBloc() : super(const AppShellState()) { 9 | on(_onPageChanged); 10 | } 11 | 12 | void _onPageChanged( 13 | AppShellPageChangedEvent event, 14 | Emitter emit, 15 | ) { 16 | emit(state.copyWith(currentPageIndex: event.pageIndex)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/features/onboarding_screen/presenter/bloc/on_boarding_event.dart: -------------------------------------------------------------------------------- 1 | part of 'on_boarding_bloc.dart'; 2 | 3 | sealed class OnBoardingEvent extends Equatable { 4 | const OnBoardingEvent(); 5 | 6 | } 7 | 8 | class AddCategoryEvent extends OnBoardingEvent { 9 | const AddCategoryEvent({ 10 | required this.category, 11 | }); 12 | 13 | final String category; 14 | 15 | @override 16 | List get props => [category]; 17 | } 18 | 19 | class NavigateToNewScreenEvent extends OnBoardingEvent { 20 | const NavigateToNewScreenEvent(); 21 | 22 | @override 23 | List get props => []; 24 | } -------------------------------------------------------------------------------- /lib/features/home_screen/presenter/page/widgets/book_swipper/bloc/books_swipper_event.dart: -------------------------------------------------------------------------------- 1 | part of 'books_swipper_bloc.dart'; 2 | 3 | sealed class BooksSwipperEvent extends Equatable { 4 | const BooksSwipperEvent(); 5 | 6 | 7 | } 8 | class BooksPageInitialized extends BooksSwipperEvent { 9 | const BooksPageInitialized(); 10 | 11 | @override 12 | List get props => []; 13 | } 14 | 15 | 16 | 17 | class BooksPageChanged extends BooksSwipperEvent { 18 | final double currentPage; 19 | 20 | const BooksPageChanged(this.currentPage); 21 | 22 | @override 23 | List get props => []; 24 | } 25 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:book_summary_app/features/onboarding_screen/presenter/onboarding_screen.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() => runApp(const MyApp()); 5 | 6 | class MyApp extends StatelessWidget { 7 | const MyApp({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return MaterialApp( 12 | title: 'Book Summary App', 13 | theme: ThemeData( 14 | colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), 15 | useMaterial3: true, 16 | ), 17 | home: OnboardingScreen() 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /lib/features/detail_book/presenter/widgets/animated_text.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AnimatedFadeInWidget extends StatelessWidget { 4 | const AnimatedFadeInWidget({ 5 | super.key, 6 | required this.widgetHOW, 7 | required this.duration, 8 | }); 9 | 10 | final Widget widgetHOW; 11 | final Duration duration; 12 | @override 13 | Widget build(BuildContext context) { 14 | return TweenAnimationBuilder( 15 | duration: duration, 16 | tween: Tween(begin: 0.0, end: 1.0), 17 | curve: const Interval(0.75,1.0,), 18 | builder: (context, value, child) { 19 | return Opacity( 20 | opacity: value, 21 | child: widgetHOW, 22 | ); 23 | }, 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/home_screen/domain/entities/book_from_author_entity.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | class BookFromAuthorEntity { 4 | final String imageUrl; 5 | final String bookId; 6 | final String workId; 7 | final String bookUrl; 8 | final String title; 9 | // final List authors; 10 | final String rating; 11 | final String totalRatings; 12 | final String publishedYear; 13 | final String totalEditions; 14 | 15 | const BookFromAuthorEntity({ 16 | required this.imageUrl, 17 | required this.bookId, 18 | required this.workId, 19 | required this.bookUrl, 20 | required this.title, 21 | // required this.authors, 22 | required this.rating, 23 | required this.totalRatings, 24 | required this.publishedYear, 25 | required this.totalEditions, 26 | }); 27 | } -------------------------------------------------------------------------------- /lib/features/home_screen/presenter/page/widgets/book_swipper/bloc/books_swipper_state.dart: -------------------------------------------------------------------------------- 1 | part of 'books_swipper_bloc.dart'; 2 | 3 | sealed class BooksSwipperState extends Equatable { 4 | const BooksSwipperState(); 5 | 6 | } 7 | 8 | final class BooksSwipperInitial extends BooksSwipperState { 9 | @override 10 | List get props => []; 11 | } 12 | 13 | 14 | class BooksWidgetLoading extends BooksSwipperState { 15 | @override 16 | List get props => []; 17 | } 18 | 19 | class BooksWidgetLoaded extends BooksSwipperState { 20 | final PageController pageController; 21 | final double currentPage; 22 | 23 | BooksWidgetLoaded({ 24 | required this.pageController, 25 | required this.currentPage, 26 | }); 27 | 28 | @override 29 | List get props => [pageController, currentPage]; 30 | } -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "7.3.0" apply false 22 | id "org.jetbrains.kotlin.android" version "1.7.10" apply false 23 | } 24 | 25 | include ":app" 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Symbolication related 35 | app.*.symbols 36 | 37 | # Obfuscation related 38 | app.*.map.json 39 | 40 | # Android Studio will place build artifacts here 41 | /android/app/debug 42 | /android/app/profile 43 | /android/app/release 44 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/features/onboarding_screen/presenter/bloc/on_boarding_state.dart: -------------------------------------------------------------------------------- 1 | part of 'on_boarding_bloc.dart'; 2 | 3 | enum AnimationStep { initial, header, list, button, completed } 4 | 5 | class OnBoardingState extends Equatable { 6 | const OnBoardingState({ 7 | required this.categories, 8 | required this.shouldAnimate, 9 | }); 10 | 11 | final List categories; 12 | final bool shouldAnimate; 13 | 14 | OnBoardingState copyWith({ 15 | List? categories, 16 | bool? shouldAnimate, 17 | }) { 18 | return OnBoardingState( 19 | categories: categories ?? this.categories, 20 | shouldAnimate: shouldAnimate ?? this.shouldAnimate, 21 | ); 22 | } 23 | 24 | @override 25 | List get props => [categories, shouldAnimate]; 26 | } 27 | 28 | class OnBoardingInitial extends OnBoardingState { 29 | OnBoardingInitial({required super.categories, required super.shouldAnimate}); 30 | } 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Book Summary App 3 | 4 | An app to follow and watch your favorites book. Research about your books and watch the reviews from the readers with an interactive interface. 5 | 6 | 7 | Inspiration: 8 | [Link Here](https://dribbble.com/shots/20092016-Book-Summary-Mobile-IOS-App-Prototype) 9 | 10 | 11 | 12 | ## Screenshots 13 | 14 | ![App Ticket Bus Screenshot](./screenshots/screenshot-book-sumary.png) 15 | 16 | 17 | ## Features 18 | 19 | - OnBoarding chips animation 20 | - PageView animated 21 | - Hero Flip Animation 22 | - Tween animation card detail 23 | 24 | 25 | ## Video Demo 26 | 27 | ![App Ticket Bus Gif Video Demostration](./screenshots/book-summary-app-gif.gif) 28 | 29 | 30 | ## License 31 | 32 | [MIT](https://choosealicense.com/licenses/mit/) 33 | 34 | 35 | ## Support 36 | 37 | For support, email paolojoaquinpintoperez@gmail.com or join our community in youtube [Pacha code](https://www.youtube.com/@paolojoaquinp). 38 | 39 | -------------------------------------------------------------------------------- /lib/features/home_screen/presenter/page/widgets/avatar_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AvatarWidget extends StatelessWidget { 4 | const AvatarWidget({ 5 | super.key, 6 | required this.name, 7 | }); 8 | 9 | final String name; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Padding( 14 | padding: const EdgeInsets.only(right: 16), 15 | child: Column( 16 | children: [ 17 | const CircleAvatar( 18 | radius: 32, 19 | backgroundImage: NetworkImage( 20 | 'https://picsum.photos/200/300?random=1', 21 | ), 22 | ), 23 | const SizedBox(height: 8), 24 | Text( 25 | name, 26 | style: const TextStyle( 27 | color: Colors.grey, 28 | fontSize: 14, 29 | ), 30 | ), 31 | ], 32 | ), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/features/onboarding_screen/presenter/bloc/on_boarding_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | part 'on_boarding_event.dart'; 5 | part 'on_boarding_state.dart'; 6 | 7 | class OnBoardingBloc extends Bloc { 8 | OnBoardingBloc() : super(const OnBoardingState(categories: [], shouldAnimate: false,)) { 9 | on((event, emit) { 10 | }); 11 | on(_onAddCategoryEvent); 12 | on(_onNavigateToNewScreenEvent); 13 | } 14 | 15 | void _onAddCategoryEvent(AddCategoryEvent event, Emitter emit) { 16 | final category = event.category; 17 | final updateCategories = List.from(state.categories)..add(category); 18 | emit(state.copyWith(categories: updateCategories)); 19 | } 20 | 21 | void _onNavigateToNewScreenEvent(NavigateToNewScreenEvent event, Emitter emit) { 22 | emit(state.copyWith(shouldAnimate: true)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/home_screen/presenter/bloc/home_state.dart: -------------------------------------------------------------------------------- 1 | part of 'home_bloc.dart'; 2 | 3 | sealed class HomeState extends Equatable { 4 | const HomeState(); 5 | 6 | } 7 | 8 | final class HomeInitial extends HomeState { 9 | const HomeInitial(); 10 | 11 | @override 12 | List get props => []; 13 | } 14 | 15 | class NavigationAnimationState extends HomeState { 16 | const NavigationAnimationState(); 17 | 18 | @override 19 | List get props => []; 20 | 21 | } 22 | 23 | class HomeLoadingState extends HomeState { 24 | const HomeLoadingState(); 25 | 26 | @override 27 | List get props => []; 28 | } 29 | class HomeLoadedState extends HomeState { 30 | const HomeLoadedState(z); 31 | 32 | // final List data; 33 | 34 | @override 35 | List get props => []; 36 | } 37 | 38 | class HomeErrorState extends HomeState { 39 | const HomeErrorState({required this.message}); 40 | 41 | final String message; 42 | 43 | @override 44 | List get props => [message]; 45 | } -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/features/home_screen/presenter/page/widgets/book_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BookCard extends StatelessWidget { 4 | const BookCard({super.key, 5 | required this.title, 6 | required this.subtitle, 7 | required this.background, 8 | required this.index, 9 | }); 10 | 11 | final String title; 12 | final String subtitle; 13 | final Color background; 14 | final int index; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Container( 19 | margin: const EdgeInsets.all(8.0), 20 | decoration: BoxDecoration( 21 | color: background, 22 | borderRadius: BorderRadius.circular(16), 23 | image: DecorationImage( 24 | image: NetworkImage('https://covers.openlibrary.org/b/id/${index + 1}-M.jpg',), 25 | fit: BoxFit.cover 26 | ), 27 | boxShadow: const [ 28 | BoxShadow( 29 | color: Colors.black26, 30 | blurRadius: 8, 31 | offset: Offset(0, 4), 32 | ), 33 | ], 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:book_summary_app/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/home_screen/presenter/page/widgets/book_swipper/bloc/books_swipper_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | part 'books_swipper_event.dart'; 8 | part 'books_swipper_state.dart'; 9 | 10 | class BooksSwipperBloc extends Bloc { 11 | BooksSwipperBloc() : super(BooksSwipperInitial()) { 12 | on(_onInitialized); 13 | on(_onPageChanged); 14 | } 15 | 16 | Future _onInitialized(BooksPageInitialized event, Emitter emit) async { 17 | final pageController = PageController(viewportFraction: 0.7, initialPage: 1); 18 | pageController.addListener(() { 19 | add(BooksPageChanged(pageController.page ?? 1.0)); 20 | }); 21 | emit(BooksWidgetLoaded(pageController: pageController, currentPage: 1.0)); 22 | } 23 | 24 | Future _onPageChanged(BooksPageChanged event, Emitter emit) async { 25 | if (state is BooksWidgetLoaded) { 26 | final currentState = state as BooksWidgetLoaded; 27 | emit(BooksWidgetLoaded( 28 | pageController: currentState.pageController, 29 | currentPage: event.currentPage, 30 | )); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at https://dart.dev/lints. 17 | # 18 | # Instead of disabling a lint rule for the entire project in the 19 | # section below, it can also be suppressed for a single line of code 20 | # or a specific dart file by using the `// ignore: name_of_lint` and 21 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 22 | # producing the lint. 23 | rules: 24 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 25 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 26 | 27 | # Additional information about this file can be found at 28 | # https://dart.dev/guides/language/analysis-options 29 | -------------------------------------------------------------------------------- /lib/features/home_screen/data/datasources/books_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:book_summary_app/features/home_screen/domain/repositories/books_repository.dart'; 2 | 3 | class BooksRepositoryImpl implements BooksRepository { 4 | 5 | 6 | 7 | // GetFutureBooksFromAuthor getBooksFromAuthorId(String idAuthor) async { 8 | // try { 9 | // final response = await _dio.get( 10 | // '$_baseUrl/getAuthorBooks', 11 | // queryParameters: { 12 | // 'authorID': '1077326', 13 | // }, 14 | // options: Options( 15 | // headers: { 16 | // 'x-rapidapi-key': _apiKey, 17 | // 'x-rapidapi-host': _apiHost, 18 | // 'Content-Type': 'application/json', 19 | // 'Accept': '*/*', 20 | // }, 21 | // ), 22 | // ); 23 | 24 | // if (response.statusCode == 200) { 25 | // // final json = response.data; 26 | // // // Asumiendo que la respuesta contiene una lista de libros 27 | // // final List booksJson = json['books'] ?? []; // Ajusta según la estructura real de tu JSON 28 | // // final List books = booksJson 29 | // // .map((bookJson) => BookFromAuthorModel.fromJson(bookJson)) 30 | // // .toList(); 31 | 32 | // // return Ok(books); 33 | // } 34 | // return Err('Failed to fetch books: ${response.statusCode}'); 35 | // } catch (e) { 36 | // return Err('An unexpected error occurred: $e'); 37 | // } 38 | // } 39 | } -------------------------------------------------------------------------------- /lib/features/onboarding_screen/presenter/widgets/chip_button.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:book_summary_app/core/constants/app_colors.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class ChipButton extends StatelessWidget { 7 | const ChipButton({ 8 | super.key, 9 | required this.label, 10 | required this.onPressed, 11 | required this.isAdded, 12 | }); 13 | 14 | final bool isAdded; 15 | final String label; 16 | final VoidCallback onPressed; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | final selectedColors = [ 21 | AppColors.greenLime, 22 | AppColors.violetTropitalIndigo, 23 | AppColors.yellowSelective, 24 | ]; 25 | final colorBackground = !isAdded 26 | ? AppColors.gunMetal 27 | : selectedColors.isNotEmpty 28 | ? selectedColors[Random().nextInt(3)] 29 | : AppColors.gunMetal; 30 | return GestureDetector( 31 | onTap: onPressed, 32 | child: Container( 33 | padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), 34 | decoration: BoxDecoration( 35 | color: colorBackground, 36 | borderRadius: BorderRadius.circular(50), 37 | ), 38 | child: Text( 39 | label, 40 | style: TextStyle( 41 | color: isAdded 42 | ? Colors.black 43 | : Colors.white, 44 | fontSize: 14, 45 | fontWeight: FontWeight.w500, 46 | ), 47 | ), 48 | ), 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id "dev.flutter.flutter-gradle-plugin" 6 | } 7 | 8 | android { 9 | namespace = "com.example.book_summary_app" 10 | compileSdk = flutter.compileSdkVersion 11 | ndkVersion = flutter.ndkVersion 12 | 13 | compileOptions { 14 | sourceCompatibility = JavaVersion.VERSION_1_8 15 | targetCompatibility = JavaVersion.VERSION_1_8 16 | } 17 | 18 | kotlinOptions { 19 | jvmTarget = JavaVersion.VERSION_1_8 20 | } 21 | 22 | defaultConfig { 23 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 24 | applicationId = "com.example.book_summary_app" 25 | // You can update the following values to match your application needs. 26 | // For more information, see: https://flutter.dev/to/review-gradle-config. 27 | minSdk = flutter.minSdkVersion 28 | targetSdk = flutter.targetSdkVersion 29 | versionCode = flutter.versionCode 30 | versionName = flutter.versionName 31 | } 32 | 33 | buildTypes { 34 | release { 35 | // TODO: Add your own signing config for the release build. 36 | // Signing with the debug keys for now, so `flutter run --release` works. 37 | signingConfig = signingConfigs.debug 38 | } 39 | } 40 | } 41 | 42 | flutter { 43 | source = "../.." 44 | } 45 | -------------------------------------------------------------------------------- /lib/features/home_screen/presenter/bloc/home_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:book_summary_app/features/home_screen/domain/repositories/books_repository.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | 7 | part 'home_event.dart'; 8 | part 'home_state.dart'; 9 | 10 | class HomeBloc extends Bloc { 11 | HomeBloc({required this.repository,}) : super(const HomeInitial()) { 12 | on(_onHomeInitialEvent); 13 | on(_onNavigationAnimationEventInitial); 14 | } 15 | 16 | final BooksRepository repository; 17 | 18 | Future _onNavigationAnimationEventInitial( 19 | NavigationAnimationEventInitial event, 20 | Emitter emit, 21 | ) async { 22 | emit(const NavigationAnimationState()); 23 | await Future.delayed(const Duration(milliseconds: 2100)).then((_){ 24 | emit(const HomeInitial()); 25 | }); 26 | } 27 | 28 | Future _onHomeInitialEvent(HomeEvent event, Emitter emit) async { 29 | // emit(const HomeLoadingState()); 30 | // try { 31 | // final result = await repository.getBooksFromAuthorId('1077326'); 32 | // result.when(ok: (data) { 33 | // if(data.isNotEmpty) { 34 | // print(data); 35 | // emit(HomeLoadedState(data: data)); 36 | // } 37 | // }, err: (err) { 38 | // print(err.toString()); 39 | // emit(HomeErrorState(message: err)); 40 | // }); 41 | // } catch (err){ 42 | // emit(HomeErrorState(message: err.toString())); 43 | // } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/features/detail_book/presenter/widgets/card_detail_book.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CardDetailBook extends StatelessWidget { 4 | const CardDetailBook({ 5 | super.key, 6 | required this.label, 7 | this.isIcon = false, 8 | required this.detailLabel, 9 | }); 10 | 11 | final String label; 12 | final bool isIcon; 13 | final String detailLabel; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Container( 18 | decoration: const BoxDecoration( 19 | borderRadius: BorderRadius.all(Radius.circular(20)), 20 | color: Color(0xff161E26), 21 | ), 22 | padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 12.0), 23 | width: double.maxFinite, 24 | child: Row( 25 | children: [ 26 | if (isIcon) 27 | const Icon( 28 | Icons.star, 29 | color: Color(0xff8482FD), 30 | ), 31 | if (isIcon) 32 | const SizedBox( 33 | width: 6.0, 34 | ), 35 | Column( 36 | crossAxisAlignment: CrossAxisAlignment.start, 37 | children: [ 38 | Text( 39 | label, 40 | style: TextStyle( 41 | color: Colors.white.withOpacity(0.8), 42 | fontSize: 14, 43 | ), 44 | ), 45 | Text( 46 | detailLabel, 47 | style: const TextStyle( 48 | color: Colors.white, 49 | fontSize: 14, 50 | fontWeight: FontWeight.bold), 51 | ), 52 | ], 53 | ), 54 | ], 55 | ), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Book Summary App 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | book_summary_app 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 17 | base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 18 | - platform: android 19 | create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 20 | base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 21 | - platform: ios 22 | create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 23 | base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 24 | - platform: linux 25 | create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 26 | base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 27 | - platform: macos 28 | create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 29 | base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 30 | - platform: web 31 | create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 32 | base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 33 | - platform: windows 34 | create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 35 | base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /lib/features/shared/app_shell/app_shell.dart: -------------------------------------------------------------------------------- 1 | import 'package:book_summary_app/features/home_screen/presenter/page/home_screen.dart'; 2 | import 'package:book_summary_app/features/shared/app_shell/bloc/app_shell_bloc.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | import 'package:flutter_svg/svg.dart'; 6 | 7 | class AppShell extends StatelessWidget { 8 | const AppShell({super.key}); 9 | 10 | static final List _pages = [ 11 | const HomeScreen(), 12 | const Center( 13 | child: Text('data'), 14 | ), 15 | ]; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return BlocProvider( 20 | create: (_) => AppShellBloc(), 21 | child: BlocBuilder( 22 | builder: (context, state) { 23 | return Scaffold( 24 | backgroundColor: const Color(0xff071018), 25 | // backgroundColor: Colors.white, 26 | body: IndexedStack( 27 | index: state.currentPageIndex, 28 | children: _pages, 29 | ), 30 | bottomNavigationBar: BottomNavigationBar( 31 | currentIndex: state.currentPageIndex, 32 | backgroundColor: Colors.transparent, 33 | type: BottomNavigationBarType.fixed, 34 | selectedItemColor: Colors.blue, 35 | unselectedItemColor: Colors.grey, 36 | iconSize: 26.0, 37 | onTap: (index) => context 38 | .read() 39 | .add(AppShellPageChangedEvent(index)), 40 | items: [ 41 | BottomNavigationBarItem( 42 | icon: SvgPicture.asset( 43 | 'assets/icons/triangle-fixed.svg', 44 | alignment: Alignment.center, 45 | height: 22, 46 | width: 22, 47 | fit: BoxFit.cover, 48 | colorFilter: const ColorFilter.mode( 49 | Colors.grey, 50 | BlendMode.srcIn, 51 | ), 52 | ), 53 | activeIcon: SvgPicture.asset( 54 | 'assets/icons/triangle-fixed.svg', 55 | height: 22, 56 | width: 22, 57 | fit: BoxFit.cover, 58 | colorFilter: const ColorFilter.mode( 59 | Colors.blue, 60 | BlendMode.srcIn, 61 | ), 62 | ), 63 | label: '', 64 | ), 65 | const BottomNavigationBarItem( 66 | icon: Icon(Icons.favorite_border,), 67 | activeIcon: Icon(Icons.favorite, color: Colors.blue,), 68 | label: '', 69 | ), 70 | ], 71 | ), 72 | ); 73 | }, 74 | ), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: book_summary_app 2 | description: "A new Flutter project." 3 | # The following line prevents the package from being accidentally published to 4 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 5 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 6 | 7 | # The following defines the version and build number for your application. 8 | # A version number is three numbers separated by dots, like 1.2.43 9 | # followed by an optional build number separated by a +. 10 | # Both the version and the builder number may be overridden in flutter 11 | # build by specifying --build-name and --build-number, respectively. 12 | # In Android, build-name is used as versionName while build-number used as versionCode. 13 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 14 | # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. 15 | # Read more about iOS versioning at 16 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 17 | # In Windows, build-name is used as the major, minor, and patch parts 18 | # of the product and file versions while build-number is used as the build suffix. 19 | version: 1.0.0+1 20 | 21 | environment: 22 | sdk: ^3.5.0 23 | 24 | # Dependencies specify other packages that your package needs in order to work. 25 | # To automatically upgrade your package dependencies to the latest versions 26 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 27 | # dependencies can be manually updated by changing the version numbers below to 28 | # the latest version available on pub.dev. To see which dependencies have newer 29 | # versions available, run `flutter pub outdated`. 30 | dependencies: 31 | flutter: 32 | sdk: flutter 33 | 34 | 35 | # The following adds the Cupertino Icons font to your application. 36 | # Use with the CupertinoIcons class for iOS style icons. 37 | cupertino_icons: ^1.0.8 38 | page_view_dot_indicator: ^2.3.0 39 | flutter_svg: ^2.0.15 40 | flutter_bloc: ^8.1.6 41 | equatable: ^2.0.7 42 | animate_do: ^3.3.4 43 | oxidized: ^6.2.0 44 | dio: ^5.7.0 45 | 46 | dev_dependencies: 47 | flutter_test: 48 | sdk: flutter 49 | 50 | # The "flutter_lints" package below contains a set of recommended lints to 51 | # encourage good coding practices. The lint set provided by the package is 52 | # activated in the `analysis_options.yaml` file located at the root of your 53 | # package. See that file for information about deactivating specific lint 54 | # rules and activating additional ones. 55 | flutter_lints: ^4.0.0 56 | 57 | # For information on the generic Dart part of this file, see the 58 | # following page: https://dart.dev/tools/pub/pubspec 59 | 60 | # The following section is specific to Flutter packages. 61 | flutter: 62 | 63 | # The following line ensures that the Material Icons font is 64 | # included with your application, so that you can use the icons in 65 | # the material Icons class. 66 | uses-material-design: true 67 | 68 | # To add assets to your application, add an assets section, like this: 69 | assets: 70 | - assets/icons/ 71 | # - images/a_dot_ham.jpeg 72 | 73 | # An image asset can refer to one or more resolution-specific "variants", see 74 | # https://flutter.dev/to/resolution-aware-images 75 | 76 | # For details regarding adding assets from package dependencies, see 77 | # https://flutter.dev/to/asset-from-package 78 | 79 | # To add custom fonts to your application, add a fonts section here, 80 | # in this "flutter" section. Each entry in this list should have a 81 | # "family" key with the font family name, and a "fonts" key with a 82 | # list giving the asset and other descriptors for the font. For 83 | # example: 84 | # fonts: 85 | # - family: Schyler 86 | # fonts: 87 | # - asset: fonts/Schyler-Regular.ttf 88 | # - asset: fonts/Schyler-Italic.ttf 89 | # style: italic 90 | # - family: Trajan Pro 91 | # fonts: 92 | # - asset: fonts/TrajanPro.ttf 93 | # - asset: fonts/TrajanPro_Bold.ttf 94 | # weight: 700 95 | # 96 | # For details regarding fonts from package dependencies, 97 | # see https://flutter.dev/to/font-from-package 98 | -------------------------------------------------------------------------------- /lib/features/home_screen/presenter/page/home_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:book_summary_app/features/home_screen/data/datasources/books_repository_impl.dart'; 2 | import 'package:book_summary_app/features/home_screen/presenter/bloc/home_bloc.dart'; 3 | import 'package:book_summary_app/features/home_screen/presenter/page/widgets/avatar_widget.dart'; 4 | import 'package:book_summary_app/features/home_screen/presenter/page/widgets/book_swipper/books_swipper.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_bloc/flutter_bloc.dart'; 7 | 8 | class HomeScreen extends StatelessWidget { 9 | const HomeScreen({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return BlocProvider( 14 | create: (context) => HomeBloc( 15 | repository: BooksRepositoryImpl() 16 | )..add(const HomeInitialEvent()), 17 | child: const _Page(), 18 | ); 19 | } 20 | } 21 | 22 | class _Page extends StatelessWidget { 23 | const _Page(); 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return const _Body(); 28 | } 29 | } 30 | 31 | class _Body extends StatelessWidget { 32 | const _Body(); 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return BlocBuilder( 37 | builder: (context, state) { 38 | return Stack( 39 | children: [ 40 | SafeArea( 41 | child: Padding( 42 | padding: const EdgeInsets.all(16.0), 43 | child: Column( 44 | crossAxisAlignment: CrossAxisAlignment.start, 45 | children: [ 46 | const Row( 47 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 48 | children: [ 49 | Column( 50 | crossAxisAlignment: CrossAxisAlignment.start, 51 | children: [ 52 | Text( 53 | 'Hello, Kelly', 54 | style: TextStyle( 55 | color: Colors.white, 56 | fontSize: 24, 57 | fontWeight: FontWeight.bold, 58 | ), 59 | ), 60 | SizedBox(height: 4), 61 | Text( 62 | 'These books are perfect for you', 63 | style: TextStyle( 64 | color: Colors.grey, 65 | fontSize: 16, 66 | ), 67 | ), 68 | ], 69 | ), 70 | CircleAvatar( 71 | radius: 24, 72 | backgroundImage: NetworkImage( 73 | 'https://picsum.photos/200/300', 74 | ), 75 | ), 76 | ], 77 | ), 78 | const SizedBox(height: 32), 79 | 80 | Row( 81 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 82 | children: [ 83 | const Text( 84 | 'Authors of books', 85 | style: TextStyle( 86 | color: Colors.white, 87 | fontSize: 20, 88 | fontWeight: FontWeight.bold, 89 | ), 90 | ), 91 | TextButton( 92 | onPressed: () {}, 93 | child: const Text( 94 | 'See All', 95 | style: TextStyle( 96 | color: Color(0xFF6B7AFF), 97 | fontSize: 16, 98 | ), 99 | ), 100 | ), 101 | ], 102 | ), 103 | const SingleChildScrollView( 104 | scrollDirection: Axis.horizontal, 105 | child: Row( 106 | children: [ 107 | AvatarWidget(name: 'Rene S.'), 108 | AvatarWidget(name: 'Gray M.'), 109 | AvatarWidget(name: 'Betty S.'), 110 | AvatarWidget(name: 'Robert S.'), 111 | AvatarWidget(name: 'Robert S.'), 112 | ], 113 | ), 114 | ), 115 | const SizedBox(height: 32), 116 | 117 | // Books section 118 | const Text( 119 | 'Books for you', 120 | style: TextStyle( 121 | color: Colors.white, 122 | fontSize: 20, 123 | fontWeight: FontWeight.bold, 124 | ), 125 | ), 126 | Expanded( 127 | child: BooksSwipper( 128 | onPressed: () { 129 | context 130 | .read() 131 | .add(const NavigationAnimationEventInitial()); 132 | }, 133 | ), 134 | ), 135 | const SizedBox( 136 | height: kBottomNavigationBarHeight, 137 | ), 138 | ], 139 | ), 140 | ), 141 | ), 142 | if (state is NavigationAnimationState) 143 | Expanded( 144 | child: TweenAnimationBuilder( 145 | tween: Tween(begin: 0.0, end: 1.0), 146 | duration: const Duration(milliseconds: 200), 147 | curve: Curves.easeInOut, 148 | builder: (context, value, child) { 149 | return Container( 150 | color: Colors.black.withOpacity(value), 151 | ); 152 | }, 153 | ), 154 | ), 155 | ], 156 | ); 157 | }, 158 | ); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /lib/features/home_screen/presenter/page/widgets/book_swipper/books_swipper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'dart:ui'; 3 | 4 | import 'package:book_summary_app/core/constants/app_colors.dart'; 5 | import 'package:book_summary_app/features/detail_book/presenter/detail_book_screen.dart'; 6 | import 'package:book_summary_app/features/home_screen/presenter/page/widgets/book_card.dart'; 7 | import 'package:book_summary_app/features/home_screen/presenter/page/widgets/book_swipper/bloc/books_swipper_bloc.dart'; 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_bloc/flutter_bloc.dart'; 10 | import 'package:page_view_dot_indicator/page_view_dot_indicator.dart'; 11 | 12 | final List selectedColors = [ 13 | AppColors.greenLime, 14 | AppColors.violetTropitalIndigo, 15 | AppColors.yellowSelective, 16 | AppColors.violetTropitalIndigo, 17 | AppColors.yellowSelective, 18 | ]; 19 | 20 | 21 | class BooksSwipper extends StatelessWidget { 22 | const BooksSwipper({ 23 | required this.onPressed, 24 | super.key, 25 | }); 26 | 27 | final VoidCallback onPressed; 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return BlocProvider( 32 | create: (_) => BooksSwipperBloc()..add(const BooksPageInitialized()), 33 | child: _Body(onPressed: onPressed,), 34 | ); 35 | } 36 | } 37 | 38 | class _Body extends StatelessWidget { 39 | 40 | const _Body({ 41 | required this.onPressed, 42 | }); 43 | 44 | final VoidCallback onPressed; 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | return BlocBuilder( 49 | builder: (context, state) { 50 | if (state is BooksWidgetLoaded) { 51 | return Stack( 52 | clipBehavior: Clip.none, 53 | children: [ 54 | SizedBox( 55 | height: double.infinity, 56 | width: double.infinity, 57 | child: PageView.builder( 58 | clipBehavior: Clip.none, 59 | itemCount: 5, 60 | controller: state.pageController, 61 | itemBuilder: (context, index) { 62 | final diff = state.currentPage - index; 63 | final rotation = -(diff * 0.1); 64 | return GestureDetector( 65 | onTap: () { 66 | onPressed(); 67 | Navigator.push( 68 | context, 69 | PageRouteBuilder( 70 | transitionDuration: const Duration(milliseconds: 1200), 71 | reverseTransitionDuration: const Duration(milliseconds: 1200), 72 | pageBuilder: (context, animation, secondaryAnimation) { 73 | return DetailBookScreen( 74 | index: index, 75 | background: selectedColors[index], 76 | ); 77 | }, 78 | transitionsBuilder: (context, animation, secondaryAnimation, child) { 79 | return FadeTransition( 80 | opacity: animation, 81 | child: child, 82 | ); 83 | }, 84 | )); 85 | }, 86 | child: Transform.translate( 87 | offset: Offset(0, diff.abs() * 65), 88 | child: Transform.rotate( 89 | angle: rotation, 90 | child: Hero( 91 | tag: 'title $index', 92 | flightShuttleBuilder: (flightContext, 93 | animation, 94 | flightDirection, 95 | fromHeroContext, 96 | toHeroContext) { 97 | Widget current; 98 | if (flightDirection == HeroFlightDirection.push) { 99 | current = toHeroContext.widget; 100 | } else { 101 | current = fromHeroContext.widget; 102 | } 103 | return AnimatedBuilder( 104 | animation: animation, 105 | builder: (context, _) { 106 | final newValue = 107 | lerpDouble(0.0, 2 * pi, animation.value); 108 | return Transform( 109 | alignment: Alignment.center, 110 | transform: Matrix4.identity() 111 | ..setEntry(3, 2, 0.001) 112 | ..rotateY(newValue ?? 0), 113 | child: current, 114 | ); 115 | }, 116 | ); 117 | }, 118 | child: BookCard( 119 | index: index, 120 | background: selectedColors[index], 121 | title: 'title $index', 122 | subtitle: 'subtitle $index'), 123 | ), 124 | ), 125 | ), 126 | ); 127 | }, 128 | ), 129 | ), 130 | Positioned( 131 | bottom: -50, 132 | left: 0, 133 | right: 0, 134 | child: SizedBox( 135 | width: double.maxFinite, 136 | height: 24, 137 | child: PageViewDotIndicator( 138 | padding: const EdgeInsets.all(0), 139 | alignment: Alignment.center, 140 | fadeEdges: false, 141 | margin: const EdgeInsets.only(left: 8.0), 142 | currentItem: state.currentPage.toInt(), 143 | count: 5, 144 | unselectedColor: Colors.grey, 145 | selectedColor: Colors.white, 146 | ), 147 | ), 148 | ), 149 | ], 150 | ); 151 | } 152 | return const Center(child: CircularProgressIndicator()); 153 | }, 154 | ); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.18.0" 44 | cupertino_icons: 45 | dependency: "direct main" 46 | description: 47 | name: cupertino_icons 48 | sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.0.8" 52 | fake_async: 53 | dependency: transitive 54 | description: 55 | name: fake_async 56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.3.1" 60 | flutter: 61 | dependency: "direct main" 62 | description: flutter 63 | source: sdk 64 | version: "0.0.0" 65 | flutter_lints: 66 | dependency: "direct dev" 67 | description: 68 | name: flutter_lints 69 | sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" 70 | url: "https://pub.dev" 71 | source: hosted 72 | version: "4.0.0" 73 | flutter_test: 74 | dependency: "direct dev" 75 | description: flutter 76 | source: sdk 77 | version: "0.0.0" 78 | leak_tracker: 79 | dependency: transitive 80 | description: 81 | name: leak_tracker 82 | sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" 83 | url: "https://pub.dev" 84 | source: hosted 85 | version: "10.0.5" 86 | leak_tracker_flutter_testing: 87 | dependency: transitive 88 | description: 89 | name: leak_tracker_flutter_testing 90 | sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" 91 | url: "https://pub.dev" 92 | source: hosted 93 | version: "3.0.5" 94 | leak_tracker_testing: 95 | dependency: transitive 96 | description: 97 | name: leak_tracker_testing 98 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 99 | url: "https://pub.dev" 100 | source: hosted 101 | version: "3.0.1" 102 | lints: 103 | dependency: transitive 104 | description: 105 | name: lints 106 | sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" 107 | url: "https://pub.dev" 108 | source: hosted 109 | version: "4.0.0" 110 | matcher: 111 | dependency: transitive 112 | description: 113 | name: matcher 114 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 115 | url: "https://pub.dev" 116 | source: hosted 117 | version: "0.12.16+1" 118 | material_color_utilities: 119 | dependency: transitive 120 | description: 121 | name: material_color_utilities 122 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 123 | url: "https://pub.dev" 124 | source: hosted 125 | version: "0.11.1" 126 | meta: 127 | dependency: transitive 128 | description: 129 | name: meta 130 | sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 131 | url: "https://pub.dev" 132 | source: hosted 133 | version: "1.15.0" 134 | path: 135 | dependency: transitive 136 | description: 137 | name: path 138 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 139 | url: "https://pub.dev" 140 | source: hosted 141 | version: "1.9.0" 142 | sky_engine: 143 | dependency: transitive 144 | description: flutter 145 | source: sdk 146 | version: "0.0.99" 147 | source_span: 148 | dependency: transitive 149 | description: 150 | name: source_span 151 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 152 | url: "https://pub.dev" 153 | source: hosted 154 | version: "1.10.0" 155 | stack_trace: 156 | dependency: transitive 157 | description: 158 | name: stack_trace 159 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 160 | url: "https://pub.dev" 161 | source: hosted 162 | version: "1.11.1" 163 | stream_channel: 164 | dependency: transitive 165 | description: 166 | name: stream_channel 167 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 168 | url: "https://pub.dev" 169 | source: hosted 170 | version: "2.1.2" 171 | string_scanner: 172 | dependency: transitive 173 | description: 174 | name: string_scanner 175 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 176 | url: "https://pub.dev" 177 | source: hosted 178 | version: "1.2.0" 179 | term_glyph: 180 | dependency: transitive 181 | description: 182 | name: term_glyph 183 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 184 | url: "https://pub.dev" 185 | source: hosted 186 | version: "1.2.1" 187 | test_api: 188 | dependency: transitive 189 | description: 190 | name: test_api 191 | sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" 192 | url: "https://pub.dev" 193 | source: hosted 194 | version: "0.7.2" 195 | vector_math: 196 | dependency: transitive 197 | description: 198 | name: vector_math 199 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 200 | url: "https://pub.dev" 201 | source: hosted 202 | version: "2.1.4" 203 | vm_service: 204 | dependency: transitive 205 | description: 206 | name: vm_service 207 | sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc 208 | url: "https://pub.dev" 209 | source: hosted 210 | version: "14.2.4" 211 | sdks: 212 | dart: ">=3.5.0 <4.0.0" 213 | flutter: ">=3.18.0-18.0.pre.54" 214 | -------------------------------------------------------------------------------- /lib/features/detail_book/presenter/detail_book_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:book_summary_app/features/detail_book/presenter/widgets/animated_text.dart'; 2 | import 'package:book_summary_app/features/detail_book/presenter/widgets/card_detail_book.dart'; 3 | import 'package:book_summary_app/features/home_screen/presenter/page/widgets/book_card.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | 7 | class DetailBookScreen extends StatelessWidget { 8 | const DetailBookScreen({super.key, required this.index, required this.background,}); 9 | 10 | final int index; 11 | final Color background; 12 | @override 13 | Widget build(BuildContext context) { 14 | const int transitionDuration = 2000; 15 | return Scaffold( 16 | // backgroundColor: Colors.white, 17 | backgroundColor: const Color(0xff071018), 18 | appBar: AppBar( 19 | iconTheme: const IconThemeData( 20 | color: Colors.white, 21 | ), 22 | title: const Text( 23 | "Book Detail", 24 | style: TextStyle( 25 | color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20), 26 | ), 27 | backgroundColor: const Color(0xff071018), 28 | actions: [ 29 | IconButton( 30 | onPressed: () {}, 31 | icon: const Icon( 32 | Icons.cloud, 33 | color: Colors.white, 34 | )) 35 | ], 36 | ), 37 | body: SingleChildScrollView( 38 | child: Padding( 39 | padding: const EdgeInsets.all(12.0), 40 | child: Column( 41 | crossAxisAlignment: CrossAxisAlignment.start, 42 | children: [ 43 | Container( 44 | color: Colors.transparent, 45 | height: 300, 46 | child: Row( 47 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 48 | children: [ 49 | Hero( 50 | tag: 'title $index', 51 | child: Material( 52 | color: Colors.transparent, 53 | child: SizedBox( 54 | width: MediaQuery.sizeOf(context).width * 0.45, 55 | child: BookCard( 56 | index: index, 57 | background: background, 58 | title: 'title $index', 59 | subtitle: 'sbutitle $index', 60 | ), 61 | ), 62 | ), 63 | ), 64 | // ClipRRect( 65 | // borderRadius: BorderRadius.all(Radius.circular(20)), 66 | // child: Image.network( 67 | // 'https://picsum.photos/250?image=9', 68 | // height: double.maxFinite, 69 | // width: MediaQuery.sizeOf(context).width * 0.45, 70 | // fit: BoxFit.cover, 71 | // ), 72 | // ), 73 | SizedBox( 74 | width: MediaQuery.sizeOf(context).width * 0.45, 75 | child: const Column( 76 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 77 | children: [ 78 | AnimatedFadeInWidget( 79 | duration: Duration( 80 | milliseconds: transitionDuration + 100), 81 | widgetHOW: CardDetailBook( 82 | label: 'Raiting', 83 | detailLabel: '8.6/10', 84 | isIcon: true), 85 | ), 86 | AnimatedFadeInWidget( 87 | duration: Duration(milliseconds: transitionDuration + 350), 88 | widgetHOW: CardDetailBook( 89 | label: 'Duration', 90 | detailLabel: '12 min', 91 | ), 92 | ), 93 | AnimatedFadeInWidget( 94 | duration: Duration(milliseconds: transitionDuration + 650), 95 | widgetHOW: CardDetailBook( 96 | label: 'Emotions', 97 | detailLabel: 'Doubts', 98 | ), 99 | ), 100 | ], 101 | ), 102 | ) 103 | ], 104 | ), 105 | ), 106 | const SizedBox( 107 | height: 16, 108 | ), 109 | const AnimatedFadeInWidget( 110 | duration: Duration( 111 | milliseconds: transitionDuration + 100), // 1500 delay + 3000 animación, 112 | widgetHOW: Text( 113 | 'Don\'t Believe\nEverything You Think', 114 | style: TextStyle( 115 | color: Colors.white, 116 | fontSize: 28.0, 117 | fontWeight: FontWeight.bold, 118 | height: 1.4), 119 | ), 120 | ), 121 | const SizedBox(height: 6.0), 122 | const AnimatedFadeInWidget( 123 | duration: Duration( 124 | milliseconds: transitionDuration + 250), 125 | widgetHOW: Text( 126 | 'Book by Joseph Nguyen', 127 | style: TextStyle( 128 | color: Colors.yellow, 129 | fontSize: 16.0, 130 | fontWeight: FontWeight.bold, 131 | ), 132 | ), 133 | ), 134 | const SizedBox(height: 16.0), 135 | const AnimatedFadeInWidget( 136 | duration: Duration( 137 | milliseconds: transitionDuration + 350), 138 | widgetHOW: Text( 139 | 'In this book, you\'ll discover the root cause of all psychological and emotional suffering and how to achieve freedom of mind to effortlessly create the life you\'ve always wanted to live.\n\nAlthough pain is inevitable, suffering is optional.', 140 | style: TextStyle( 141 | color: Colors.white, 142 | fontSize: 16.0, 143 | ), 144 | ), 145 | ), 146 | const SizedBox(height: 16.0), 147 | AnimatedFadeInWidget( 148 | duration: const Duration(milliseconds: transitionDuration + 100), 149 | widgetHOW: Align( 150 | alignment: Alignment.bottomCenter, 151 | child: ElevatedButton( 152 | onPressed: () {}, 153 | style: ElevatedButton.styleFrom( 154 | padding: const EdgeInsets.symmetric(vertical: 24), 155 | maximumSize: 156 | Size(MediaQuery.sizeOf(context).width * 0.8, 86), 157 | minimumSize: 158 | Size(MediaQuery.sizeOf(context).width * 0.8, 46), 159 | backgroundColor: Colors.lime, 160 | foregroundColor: Colors.black, 161 | ), 162 | child: const Text('I want to read'), 163 | ), 164 | ), 165 | ), 166 | ], 167 | ), 168 | ), 169 | ), 170 | ); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /lib/features/onboarding_screen/presenter/onboarding_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:animate_do/animate_do.dart'; 2 | import 'package:book_summary_app/features/onboarding_screen/presenter/bloc/on_boarding_bloc.dart'; 3 | import 'package:book_summary_app/features/onboarding_screen/presenter/widgets/chip_button.dart'; 4 | import 'package:book_summary_app/features/shared/app_shell/app_shell.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_bloc/flutter_bloc.dart'; 7 | import 'package:page_view_dot_indicator/page_view_dot_indicator.dart'; 8 | 9 | final List categories = [ 10 | "Self Acceptance", 11 | "Fears", 12 | "Memory", 13 | "Personal boundaries", 14 | "Parents", 15 | "Doubts", 16 | "Controlling emotions", 17 | "Parenting", 18 | "Personal boundaries_1", 19 | "Self Acceptance_1", 20 | "Fears_1", 21 | "Controlling emotions_1", 22 | "Parents_1", 23 | "Doubts_1", 24 | "Parenting_1", 25 | "Memory_1", 26 | "Fears_2", 27 | "Self Acceptance_2", 28 | "Parents_2", 29 | "Personal boundaries_2", 30 | "Parenting_2", 31 | "Doubts_2", 32 | "Controlling emotions_2", 33 | "Memory_2", 34 | "Parenting_", 35 | "Memory_", 36 | "Personal boundaries_", 37 | "Doubts_", 38 | "Parents_", 39 | "Fears_", 40 | "Controlling emotions_", 41 | "Self Acceptance_", 42 | ]; 43 | 44 | class OnboardingScreen extends StatelessWidget { 45 | final int itemCount = categories.length; 46 | final ValueNotifier selectedPageNotifier = ValueNotifier(0); 47 | 48 | OnboardingScreen({super.key}); 49 | 50 | @override 51 | Widget build(BuildContext context) { 52 | const int itemsPerPage = 12; 53 | final int pageCount = (itemCount / itemsPerPage).ceil(); 54 | 55 | return BlocProvider( 56 | create: (context) => OnBoardingBloc(), 57 | child: _Page( 58 | selectedPageNotifier: selectedPageNotifier, 59 | pageCount: pageCount, 60 | itemCount: itemCount, 61 | ), 62 | ); 63 | } 64 | } 65 | 66 | class _Page extends StatelessWidget { 67 | const _Page({ 68 | required this.selectedPageNotifier, 69 | required this.pageCount, 70 | required this.itemCount, 71 | }); 72 | 73 | final ValueNotifier selectedPageNotifier; 74 | final int pageCount; 75 | final int itemCount; 76 | 77 | @override 78 | Widget build(BuildContext context) { 79 | return BlocBuilder( 80 | builder: (context, state) { 81 | return Scaffold( 82 | backgroundColor: Colors.black, 83 | body: Column( 84 | crossAxisAlignment: CrossAxisAlignment.start, 85 | children: [ 86 | const SizedBox( 87 | height: kToolbarHeight, 88 | ), 89 | ValueListenableBuilder( 90 | valueListenable: selectedPageNotifier, 91 | builder: (context, selectedPage, _) { 92 | return Row( 93 | mainAxisAlignment: MainAxisAlignment.end, 94 | children: [ 95 | FadeOutRight( 96 | animate: state.shouldAnimate, 97 | duration: const Duration(milliseconds: 800), 98 | child: Container( 99 | width: MediaQuery.sizeOf(context).width * 0.3, 100 | padding: const EdgeInsets.only(right: 16.0), 101 | child: PageViewDotIndicator( 102 | padding: const EdgeInsets.all(0), 103 | alignment: Alignment.centerRight, 104 | fadeEdges: false, 105 | margin: const EdgeInsets.only(left: 8.0), 106 | currentItem: selectedPage, 107 | count: pageCount, 108 | unselectedColor: Colors.grey, 109 | selectedColor: Colors.white, 110 | boxShape: BoxShape.rectangle, 111 | unselectedSize: const Size(8, 8), 112 | size: const Size(18, 8), 113 | borderRadius: BorderRadius.circular(5), 114 | ), 115 | ), 116 | ) 117 | ], 118 | ); 119 | }, 120 | ), 121 | SizedBox( 122 | height: MediaQuery.sizeOf(context).height * 0.07, 123 | ), 124 | FadeOutUp( 125 | animate: state.shouldAnimate, 126 | duration: const Duration(milliseconds: 800), 127 | child: const Padding( 128 | padding: EdgeInsets.only(left: 16.0), 129 | child: Text( 130 | 'Choose\nyour goals', 131 | style: TextStyle( 132 | color: Colors.white, 133 | fontSize: 48, 134 | fontWeight: FontWeight.bold, 135 | letterSpacing: -1, 136 | height: 1.2, 137 | ), 138 | ), 139 | ), 140 | ), 141 | const Expanded(child: SizedBox()), 142 | NotificationListener( 143 | onNotification: (scrollNotification) { 144 | if (scrollNotification is ScrollUpdateNotification) { 145 | final currentPage = (scrollNotification.metrics.pixels / 146 | scrollNotification.metrics.viewportDimension) 147 | .round(); 148 | selectedPageNotifier.value = currentPage; 149 | } 150 | return true; 151 | }, 152 | child: FadeOutLeft( 153 | animate: state.shouldAnimate, 154 | duration: const Duration(milliseconds: 800), 155 | child: SingleChildScrollView( 156 | scrollDirection: Axis.horizontal, 157 | child: Column( 158 | children: List.generate(4, (rowIndex) { 159 | return Padding( 160 | padding: const EdgeInsets.only( 161 | bottom: 16, 162 | ), 163 | child: Row( 164 | children: List.generate( 165 | itemCount ~/ 4, 166 | (columnIndex) { 167 | final int itemIndex = 168 | rowIndex * (itemCount ~/ 4) + columnIndex; 169 | final bool isAdded = state.categories 170 | .contains(categories[itemIndex]); 171 | return Padding( 172 | padding: const EdgeInsets.only( 173 | right: 16, 174 | ), 175 | child: ChipButton( 176 | isAdded: isAdded, 177 | label: categories[itemIndex], 178 | onPressed: () { 179 | final bool isAlreadySelected = state 180 | .categories 181 | .contains(categories[itemIndex]); 182 | if (state.categories.length < 3 && !isAlreadySelected) { 183 | context.read().add(AddCategoryEvent(category: categories[itemIndex])); 184 | if (state.categories.length == 2) { 185 | Future.delayed(const Duration(milliseconds: 700)); 186 | context.read().add(const NavigateToNewScreenEvent()); 187 | Future.delayed(const Duration(milliseconds: 800), () { 188 | Navigator.push( 189 | context, 190 | PageRouteBuilder( 191 | transitionDuration: const Duration(milliseconds: 500), 192 | reverseTransitionDuration: const Duration(milliseconds: 500), 193 | pageBuilder: (context, animation, secondaryAnimation) { 194 | return const AppShell(); 195 | }, 196 | transitionsBuilder: (context, animation, secondaryAnimation, child) { 197 | return FadeTransition( 198 | opacity: animation, 199 | child: child, 200 | ); 201 | }, 202 | )); 203 | }); 204 | } 205 | } 206 | }, 207 | ), 208 | ); 209 | }, 210 | ), 211 | ), 212 | ); 213 | }), 214 | ), 215 | ), 216 | ), 217 | ), 218 | const SizedBox( 219 | height: kBottomNavigationBarHeight, 220 | ), 221 | ], 222 | ), 223 | ); 224 | }, 225 | ); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /assets/icons/triangle-fixed.svg: -------------------------------------------------------------------------------- 1 | 2 | hey 3 | 4 | 5 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXContainerItemProxy section */ 20 | 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { 21 | isa = PBXContainerItemProxy; 22 | containerPortal = 97C146E61CF9000F007C117D /* Project object */; 23 | proxyType = 1; 24 | remoteGlobalIDString = 97C146ED1CF9000F007C117D; 25 | remoteInfo = Runner; 26 | }; 27 | /* End PBXContainerItemProxy section */ 28 | 29 | /* Begin PBXCopyFilesBuildPhase section */ 30 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 31 | isa = PBXCopyFilesBuildPhase; 32 | buildActionMask = 2147483647; 33 | dstPath = ""; 34 | dstSubfolderSpec = 10; 35 | files = ( 36 | ); 37 | name = "Embed Frameworks"; 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXCopyFilesBuildPhase section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 44 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 45 | 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 46 | 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 48 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 49 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 50 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 51 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 52 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 53 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 55 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 56 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 57 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 331C8082294A63A400263BE5 /* RunnerTests */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 331C807B294A618700263BE5 /* RunnerTests.swift */, 75 | ); 76 | path = RunnerTests; 77 | sourceTree = ""; 78 | }; 79 | 9740EEB11CF90186004384FC /* Flutter */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 83 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 84 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 85 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 86 | ); 87 | name = Flutter; 88 | sourceTree = ""; 89 | }; 90 | 97C146E51CF9000F007C117D = { 91 | isa = PBXGroup; 92 | children = ( 93 | 9740EEB11CF90186004384FC /* Flutter */, 94 | 97C146F01CF9000F007C117D /* Runner */, 95 | 97C146EF1CF9000F007C117D /* Products */, 96 | 331C8082294A63A400263BE5 /* RunnerTests */, 97 | ); 98 | sourceTree = ""; 99 | }; 100 | 97C146EF1CF9000F007C117D /* Products */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 97C146EE1CF9000F007C117D /* Runner.app */, 104 | 331C8081294A63A400263BE5 /* RunnerTests.xctest */, 105 | ); 106 | name = Products; 107 | sourceTree = ""; 108 | }; 109 | 97C146F01CF9000F007C117D /* Runner */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 113 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 114 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 115 | 97C147021CF9000F007C117D /* Info.plist */, 116 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 117 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 118 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 119 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 120 | ); 121 | path = Runner; 122 | sourceTree = ""; 123 | }; 124 | /* End PBXGroup section */ 125 | 126 | /* Begin PBXNativeTarget section */ 127 | 331C8080294A63A400263BE5 /* RunnerTests */ = { 128 | isa = PBXNativeTarget; 129 | buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; 130 | buildPhases = ( 131 | 331C807D294A63A400263BE5 /* Sources */, 132 | 331C807F294A63A400263BE5 /* Resources */, 133 | ); 134 | buildRules = ( 135 | ); 136 | dependencies = ( 137 | 331C8086294A63A400263BE5 /* PBXTargetDependency */, 138 | ); 139 | name = RunnerTests; 140 | productName = RunnerTests; 141 | productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; 142 | productType = "com.apple.product-type.bundle.unit-test"; 143 | }; 144 | 97C146ED1CF9000F007C117D /* Runner */ = { 145 | isa = PBXNativeTarget; 146 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 147 | buildPhases = ( 148 | 9740EEB61CF901F6004384FC /* Run Script */, 149 | 97C146EA1CF9000F007C117D /* Sources */, 150 | 97C146EB1CF9000F007C117D /* Frameworks */, 151 | 97C146EC1CF9000F007C117D /* Resources */, 152 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 153 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 154 | ); 155 | buildRules = ( 156 | ); 157 | dependencies = ( 158 | ); 159 | name = Runner; 160 | productName = Runner; 161 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 162 | productType = "com.apple.product-type.application"; 163 | }; 164 | /* End PBXNativeTarget section */ 165 | 166 | /* Begin PBXProject section */ 167 | 97C146E61CF9000F007C117D /* Project object */ = { 168 | isa = PBXProject; 169 | attributes = { 170 | BuildIndependentTargetsInParallel = YES; 171 | LastUpgradeCheck = 1510; 172 | ORGANIZATIONNAME = ""; 173 | TargetAttributes = { 174 | 331C8080294A63A400263BE5 = { 175 | CreatedOnToolsVersion = 14.0; 176 | TestTargetID = 97C146ED1CF9000F007C117D; 177 | }; 178 | 97C146ED1CF9000F007C117D = { 179 | CreatedOnToolsVersion = 7.3.1; 180 | LastSwiftMigration = 1100; 181 | }; 182 | }; 183 | }; 184 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 185 | compatibilityVersion = "Xcode 9.3"; 186 | developmentRegion = en; 187 | hasScannedForEncodings = 0; 188 | knownRegions = ( 189 | en, 190 | Base, 191 | ); 192 | mainGroup = 97C146E51CF9000F007C117D; 193 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 194 | projectDirPath = ""; 195 | projectRoot = ""; 196 | targets = ( 197 | 97C146ED1CF9000F007C117D /* Runner */, 198 | 331C8080294A63A400263BE5 /* RunnerTests */, 199 | ); 200 | }; 201 | /* End PBXProject section */ 202 | 203 | /* Begin PBXResourcesBuildPhase section */ 204 | 331C807F294A63A400263BE5 /* Resources */ = { 205 | isa = PBXResourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | 97C146EC1CF9000F007C117D /* Resources */ = { 212 | isa = PBXResourcesBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 216 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 217 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 218 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | /* End PBXResourcesBuildPhase section */ 223 | 224 | /* Begin PBXShellScriptBuildPhase section */ 225 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 226 | isa = PBXShellScriptBuildPhase; 227 | alwaysOutOfDate = 1; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | ); 231 | inputPaths = ( 232 | "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", 233 | ); 234 | name = "Thin Binary"; 235 | outputPaths = ( 236 | ); 237 | runOnlyForDeploymentPostprocessing = 0; 238 | shellPath = /bin/sh; 239 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 240 | }; 241 | 9740EEB61CF901F6004384FC /* Run Script */ = { 242 | isa = PBXShellScriptBuildPhase; 243 | alwaysOutOfDate = 1; 244 | buildActionMask = 2147483647; 245 | files = ( 246 | ); 247 | inputPaths = ( 248 | ); 249 | name = "Run Script"; 250 | outputPaths = ( 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | shellPath = /bin/sh; 254 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 255 | }; 256 | /* End PBXShellScriptBuildPhase section */ 257 | 258 | /* Begin PBXSourcesBuildPhase section */ 259 | 331C807D294A63A400263BE5 /* Sources */ = { 260 | isa = PBXSourcesBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | 97C146EA1CF9000F007C117D /* Sources */ = { 268 | isa = PBXSourcesBuildPhase; 269 | buildActionMask = 2147483647; 270 | files = ( 271 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 272 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | /* End PBXSourcesBuildPhase section */ 277 | 278 | /* Begin PBXTargetDependency section */ 279 | 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { 280 | isa = PBXTargetDependency; 281 | target = 97C146ED1CF9000F007C117D /* Runner */; 282 | targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; 283 | }; 284 | /* End PBXTargetDependency section */ 285 | 286 | /* Begin PBXVariantGroup section */ 287 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 288 | isa = PBXVariantGroup; 289 | children = ( 290 | 97C146FB1CF9000F007C117D /* Base */, 291 | ); 292 | name = Main.storyboard; 293 | sourceTree = ""; 294 | }; 295 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 296 | isa = PBXVariantGroup; 297 | children = ( 298 | 97C147001CF9000F007C117D /* Base */, 299 | ); 300 | name = LaunchScreen.storyboard; 301 | sourceTree = ""; 302 | }; 303 | /* End PBXVariantGroup section */ 304 | 305 | /* Begin XCBuildConfiguration section */ 306 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 307 | isa = XCBuildConfiguration; 308 | buildSettings = { 309 | ALWAYS_SEARCH_USER_PATHS = NO; 310 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 311 | CLANG_ANALYZER_NONNULL = YES; 312 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 313 | CLANG_CXX_LIBRARY = "libc++"; 314 | CLANG_ENABLE_MODULES = YES; 315 | CLANG_ENABLE_OBJC_ARC = YES; 316 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 317 | CLANG_WARN_BOOL_CONVERSION = YES; 318 | CLANG_WARN_COMMA = YES; 319 | CLANG_WARN_CONSTANT_CONVERSION = YES; 320 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 321 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 322 | CLANG_WARN_EMPTY_BODY = YES; 323 | CLANG_WARN_ENUM_CONVERSION = YES; 324 | CLANG_WARN_INFINITE_RECURSION = YES; 325 | CLANG_WARN_INT_CONVERSION = YES; 326 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 327 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 328 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 329 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 330 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 331 | CLANG_WARN_STRICT_PROTOTYPES = YES; 332 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 333 | CLANG_WARN_UNREACHABLE_CODE = YES; 334 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 335 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 336 | COPY_PHASE_STRIP = NO; 337 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 338 | ENABLE_NS_ASSERTIONS = NO; 339 | ENABLE_STRICT_OBJC_MSGSEND = YES; 340 | ENABLE_USER_SCRIPT_SANDBOXING = NO; 341 | GCC_C_LANGUAGE_STANDARD = gnu99; 342 | GCC_NO_COMMON_BLOCKS = YES; 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 350 | MTL_ENABLE_DEBUG_INFO = NO; 351 | SDKROOT = iphoneos; 352 | SUPPORTED_PLATFORMS = iphoneos; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | VALIDATE_PRODUCT = YES; 355 | }; 356 | name = Profile; 357 | }; 358 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 359 | isa = XCBuildConfiguration; 360 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 361 | buildSettings = { 362 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 363 | CLANG_ENABLE_MODULES = YES; 364 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 365 | DEVELOPMENT_TEAM = GP9FGC24R3; 366 | ENABLE_BITCODE = NO; 367 | INFOPLIST_FILE = Runner/Info.plist; 368 | LD_RUNPATH_SEARCH_PATHS = ( 369 | "$(inherited)", 370 | "@executable_path/Frameworks", 371 | ); 372 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bookSummaryApp; 373 | PRODUCT_NAME = "$(TARGET_NAME)"; 374 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 375 | SWIFT_VERSION = 5.0; 376 | VERSIONING_SYSTEM = "apple-generic"; 377 | }; 378 | name = Profile; 379 | }; 380 | 331C8088294A63A400263BE5 /* Debug */ = { 381 | isa = XCBuildConfiguration; 382 | buildSettings = { 383 | BUNDLE_LOADER = "$(TEST_HOST)"; 384 | CODE_SIGN_STYLE = Automatic; 385 | CURRENT_PROJECT_VERSION = 1; 386 | GENERATE_INFOPLIST_FILE = YES; 387 | MARKETING_VERSION = 1.0; 388 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bookSummaryApp.RunnerTests; 389 | PRODUCT_NAME = "$(TARGET_NAME)"; 390 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 391 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 392 | SWIFT_VERSION = 5.0; 393 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; 394 | }; 395 | name = Debug; 396 | }; 397 | 331C8089294A63A400263BE5 /* Release */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | BUNDLE_LOADER = "$(TEST_HOST)"; 401 | CODE_SIGN_STYLE = Automatic; 402 | CURRENT_PROJECT_VERSION = 1; 403 | GENERATE_INFOPLIST_FILE = YES; 404 | MARKETING_VERSION = 1.0; 405 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bookSummaryApp.RunnerTests; 406 | PRODUCT_NAME = "$(TARGET_NAME)"; 407 | SWIFT_VERSION = 5.0; 408 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; 409 | }; 410 | name = Release; 411 | }; 412 | 331C808A294A63A400263BE5 /* Profile */ = { 413 | isa = XCBuildConfiguration; 414 | buildSettings = { 415 | BUNDLE_LOADER = "$(TEST_HOST)"; 416 | CODE_SIGN_STYLE = Automatic; 417 | CURRENT_PROJECT_VERSION = 1; 418 | GENERATE_INFOPLIST_FILE = YES; 419 | MARKETING_VERSION = 1.0; 420 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bookSummaryApp.RunnerTests; 421 | PRODUCT_NAME = "$(TARGET_NAME)"; 422 | SWIFT_VERSION = 5.0; 423 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; 424 | }; 425 | name = Profile; 426 | }; 427 | 97C147031CF9000F007C117D /* Debug */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | ALWAYS_SEARCH_USER_PATHS = NO; 431 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 432 | CLANG_ANALYZER_NONNULL = YES; 433 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 434 | CLANG_CXX_LIBRARY = "libc++"; 435 | CLANG_ENABLE_MODULES = YES; 436 | CLANG_ENABLE_OBJC_ARC = YES; 437 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 438 | CLANG_WARN_BOOL_CONVERSION = YES; 439 | CLANG_WARN_COMMA = YES; 440 | CLANG_WARN_CONSTANT_CONVERSION = YES; 441 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 442 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 443 | CLANG_WARN_EMPTY_BODY = YES; 444 | CLANG_WARN_ENUM_CONVERSION = YES; 445 | CLANG_WARN_INFINITE_RECURSION = YES; 446 | CLANG_WARN_INT_CONVERSION = YES; 447 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 448 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 449 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 450 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 451 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 452 | CLANG_WARN_STRICT_PROTOTYPES = YES; 453 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 454 | CLANG_WARN_UNREACHABLE_CODE = YES; 455 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 456 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 457 | COPY_PHASE_STRIP = NO; 458 | DEBUG_INFORMATION_FORMAT = dwarf; 459 | ENABLE_STRICT_OBJC_MSGSEND = YES; 460 | ENABLE_TESTABILITY = YES; 461 | ENABLE_USER_SCRIPT_SANDBOXING = NO; 462 | GCC_C_LANGUAGE_STANDARD = gnu99; 463 | GCC_DYNAMIC_NO_PIC = NO; 464 | GCC_NO_COMMON_BLOCKS = YES; 465 | GCC_OPTIMIZATION_LEVEL = 0; 466 | GCC_PREPROCESSOR_DEFINITIONS = ( 467 | "DEBUG=1", 468 | "$(inherited)", 469 | ); 470 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 471 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 472 | GCC_WARN_UNDECLARED_SELECTOR = YES; 473 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 474 | GCC_WARN_UNUSED_FUNCTION = YES; 475 | GCC_WARN_UNUSED_VARIABLE = YES; 476 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 477 | MTL_ENABLE_DEBUG_INFO = YES; 478 | ONLY_ACTIVE_ARCH = YES; 479 | SDKROOT = iphoneos; 480 | TARGETED_DEVICE_FAMILY = "1,2"; 481 | }; 482 | name = Debug; 483 | }; 484 | 97C147041CF9000F007C117D /* Release */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | ALWAYS_SEARCH_USER_PATHS = NO; 488 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 489 | CLANG_ANALYZER_NONNULL = YES; 490 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 491 | CLANG_CXX_LIBRARY = "libc++"; 492 | CLANG_ENABLE_MODULES = YES; 493 | CLANG_ENABLE_OBJC_ARC = YES; 494 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 495 | CLANG_WARN_BOOL_CONVERSION = YES; 496 | CLANG_WARN_COMMA = YES; 497 | CLANG_WARN_CONSTANT_CONVERSION = YES; 498 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 499 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 500 | CLANG_WARN_EMPTY_BODY = YES; 501 | CLANG_WARN_ENUM_CONVERSION = YES; 502 | CLANG_WARN_INFINITE_RECURSION = YES; 503 | CLANG_WARN_INT_CONVERSION = YES; 504 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 505 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 506 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 507 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 508 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 509 | CLANG_WARN_STRICT_PROTOTYPES = YES; 510 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 511 | CLANG_WARN_UNREACHABLE_CODE = YES; 512 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 513 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 514 | COPY_PHASE_STRIP = NO; 515 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 516 | ENABLE_NS_ASSERTIONS = NO; 517 | ENABLE_STRICT_OBJC_MSGSEND = YES; 518 | ENABLE_USER_SCRIPT_SANDBOXING = NO; 519 | GCC_C_LANGUAGE_STANDARD = gnu99; 520 | GCC_NO_COMMON_BLOCKS = YES; 521 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 522 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 523 | GCC_WARN_UNDECLARED_SELECTOR = YES; 524 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 525 | GCC_WARN_UNUSED_FUNCTION = YES; 526 | GCC_WARN_UNUSED_VARIABLE = YES; 527 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 528 | MTL_ENABLE_DEBUG_INFO = NO; 529 | SDKROOT = iphoneos; 530 | SUPPORTED_PLATFORMS = iphoneos; 531 | SWIFT_COMPILATION_MODE = wholemodule; 532 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 533 | TARGETED_DEVICE_FAMILY = "1,2"; 534 | VALIDATE_PRODUCT = YES; 535 | }; 536 | name = Release; 537 | }; 538 | 97C147061CF9000F007C117D /* Debug */ = { 539 | isa = XCBuildConfiguration; 540 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 541 | buildSettings = { 542 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 543 | CLANG_ENABLE_MODULES = YES; 544 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 545 | DEVELOPMENT_TEAM = GP9FGC24R3; 546 | ENABLE_BITCODE = NO; 547 | INFOPLIST_FILE = Runner/Info.plist; 548 | LD_RUNPATH_SEARCH_PATHS = ( 549 | "$(inherited)", 550 | "@executable_path/Frameworks", 551 | ); 552 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bookSummaryApp; 553 | PRODUCT_NAME = "$(TARGET_NAME)"; 554 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 555 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 556 | SWIFT_VERSION = 5.0; 557 | VERSIONING_SYSTEM = "apple-generic"; 558 | }; 559 | name = Debug; 560 | }; 561 | 97C147071CF9000F007C117D /* Release */ = { 562 | isa = XCBuildConfiguration; 563 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 564 | buildSettings = { 565 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 566 | CLANG_ENABLE_MODULES = YES; 567 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 568 | DEVELOPMENT_TEAM = GP9FGC24R3; 569 | ENABLE_BITCODE = NO; 570 | INFOPLIST_FILE = Runner/Info.plist; 571 | LD_RUNPATH_SEARCH_PATHS = ( 572 | "$(inherited)", 573 | "@executable_path/Frameworks", 574 | ); 575 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bookSummaryApp; 576 | PRODUCT_NAME = "$(TARGET_NAME)"; 577 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 578 | SWIFT_VERSION = 5.0; 579 | VERSIONING_SYSTEM = "apple-generic"; 580 | }; 581 | name = Release; 582 | }; 583 | /* End XCBuildConfiguration section */ 584 | 585 | /* Begin XCConfigurationList section */ 586 | 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { 587 | isa = XCConfigurationList; 588 | buildConfigurations = ( 589 | 331C8088294A63A400263BE5 /* Debug */, 590 | 331C8089294A63A400263BE5 /* Release */, 591 | 331C808A294A63A400263BE5 /* Profile */, 592 | ); 593 | defaultConfigurationIsVisible = 0; 594 | defaultConfigurationName = Release; 595 | }; 596 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 597 | isa = XCConfigurationList; 598 | buildConfigurations = ( 599 | 97C147031CF9000F007C117D /* Debug */, 600 | 97C147041CF9000F007C117D /* Release */, 601 | 249021D3217E4FDB00AE95B9 /* Profile */, 602 | ); 603 | defaultConfigurationIsVisible = 0; 604 | defaultConfigurationName = Release; 605 | }; 606 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 607 | isa = XCConfigurationList; 608 | buildConfigurations = ( 609 | 97C147061CF9000F007C117D /* Debug */, 610 | 97C147071CF9000F007C117D /* Release */, 611 | 249021D4217E4FDB00AE95B9 /* Profile */, 612 | ); 613 | defaultConfigurationIsVisible = 0; 614 | defaultConfigurationName = Release; 615 | }; 616 | /* End XCConfigurationList section */ 617 | }; 618 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 619 | } 620 | --------------------------------------------------------------------------------