├── ios ├── 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 │ │ ├── LaunchBackground.imageset │ │ │ ├── background.png │ │ │ └── Contents.json │ │ └── BrandingImage.imageset │ │ │ └── Contents.json │ ├── Runner.entitlements │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── .gitignore └── Podfile ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png ├── splash │ ├── img │ │ ├── dark-1x.png │ │ ├── dark-2x.png │ │ ├── dark-3x.png │ │ ├── dark-4x.png │ │ ├── light-1x.png │ │ ├── light-2x.png │ │ ├── light-3x.png │ │ └── light-4x.png │ ├── splash.js │ └── style.css ├── manifest.json └── index.html ├── lib ├── img │ ├── logo_350.png │ ├── star_img.png │ ├── todoImage.jpg │ ├── placeholder.jpg │ ├── businessman-min.png │ ├── cnameicon.svg │ └── editicon.svg ├── screenshots │ ├── addtodo.png │ ├── profile.png │ ├── dashboard.png │ ├── homepage1.png │ ├── homepage2.png │ ├── description.png │ └── splashscreen.png ├── Widgets │ ├── Profile │ │ ├── string_extension.dart │ │ ├── todos_big_container.dart │ │ ├── todos_stats_comp.dart │ │ ├── name_text.dart │ │ ├── profile_circle.dart │ │ └── todos_container.dart │ ├── DetailPage │ │ ├── todo_description.dart │ │ └── todo_info_section.dart │ ├── Dashboard │ │ ├── complete_todo_list.dart │ │ ├── completed_task_info.dart │ │ ├── clear_todos_btn.dart │ │ └── complete_todo_card.dart │ ├── ChangeName │ │ └── change_name_text.dart │ ├── Welcome │ │ ├── welcome_tf.dart │ │ └── welcome_text.dart │ ├── Todo │ │ ├── todo_list.dart │ │ ├── edit_tf.dart │ │ ├── custom_tf.dart │ │ └── todo_card.dart │ └── HomePage │ │ ├── Grettings │ │ └── greetings.dart │ │ ├── Info │ │ └── info_widget.dart │ │ └── Tasks │ │ └── task_info.dart ├── provider │ ├── shared_prefences_helper.dart │ └── todos_provider.dart ├── generated_plugin_registrant.dart ├── Models │ └── todo.dart ├── Pages │ ├── dashboard_page.dart │ ├── profile_page.dart │ ├── home_page.dart │ ├── calendar_page.dart │ ├── welcome_screen.dart │ ├── detail_screen.dart │ ├── change_name_page.dart │ ├── main_screen.dart │ └── edit_todo.dart ├── main.dart ├── langs │ ├── en.json │ └── tr.json ├── Review │ └── review_service.dart └── translations │ ├── locale_keys.g.dart │ └── codegen_loader.g.dart ├── app_icons ├── iosicon.png ├── androidicon.png └── appiconios.png ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── drawable-hdpi │ │ │ │ │ └── splash.png │ │ │ │ ├── drawable-mdpi │ │ │ │ │ └── splash.png │ │ │ │ ├── drawable-xhdpi │ │ │ │ │ └── splash.png │ │ │ │ ├── drawable │ │ │ │ │ ├── background.png │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ ├── background.png │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-xxhdpi │ │ │ │ │ └── splash.png │ │ │ │ ├── drawable-xxxhdpi │ │ │ │ │ └── splash.png │ │ │ │ ├── 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 │ │ │ │ ├── values-v31 │ │ │ │ │ └── styles.xml │ │ │ │ ├── values-night │ │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── yagizdokumaci │ │ │ │ │ └── todo_app │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── .metadata ├── test └── widget_test.dart ├── analysis_options.yaml ├── README.md └── pubspec.yaml /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/favicon.png -------------------------------------------------------------------------------- /lib/img/logo_350.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/img/logo_350.png -------------------------------------------------------------------------------- /lib/img/star_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/img/star_img.png -------------------------------------------------------------------------------- /app_icons/iosicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/app_icons/iosicon.png -------------------------------------------------------------------------------- /lib/img/todoImage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/img/todoImage.jpg -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/icons/Icon-512.png -------------------------------------------------------------------------------- /app_icons/androidicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/app_icons/androidicon.png -------------------------------------------------------------------------------- /app_icons/appiconios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/app_icons/appiconios.png -------------------------------------------------------------------------------- /lib/img/placeholder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/img/placeholder.jpg -------------------------------------------------------------------------------- /lib/img/businessman-min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/img/businessman-min.png -------------------------------------------------------------------------------- /lib/screenshots/addtodo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/screenshots/addtodo.png -------------------------------------------------------------------------------- /lib/screenshots/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/screenshots/profile.png -------------------------------------------------------------------------------- /web/splash/img/dark-1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/splash/img/dark-1x.png -------------------------------------------------------------------------------- /web/splash/img/dark-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/splash/img/dark-2x.png -------------------------------------------------------------------------------- /web/splash/img/dark-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/splash/img/dark-3x.png -------------------------------------------------------------------------------- /web/splash/img/dark-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/splash/img/dark-4x.png -------------------------------------------------------------------------------- /web/splash/img/light-1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/splash/img/light-1x.png -------------------------------------------------------------------------------- /web/splash/img/light-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/splash/img/light-2x.png -------------------------------------------------------------------------------- /web/splash/img/light-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/splash/img/light-3x.png -------------------------------------------------------------------------------- /web/splash/img/light-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/splash/img/light-4x.png -------------------------------------------------------------------------------- /lib/screenshots/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/screenshots/dashboard.png -------------------------------------------------------------------------------- /lib/screenshots/homepage1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/screenshots/homepage1.png -------------------------------------------------------------------------------- /lib/screenshots/homepage2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/screenshots/homepage2.png -------------------------------------------------------------------------------- /lib/screenshots/description.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/screenshots/description.png -------------------------------------------------------------------------------- /lib/screenshots/splashscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/lib/screenshots/splashscreen.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/android/app/src/main/res/drawable-hdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/android/app/src/main/res/drawable-mdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/android/app/src/main/res/drawable-xhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/android/app/src/main/res/drawable/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/android/app/src/main/res/drawable-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/android/app/src/main/res/drawable-xxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/android/app/src/main/res/drawable-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagizdo/Todo-Moon/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/yagizdo/Todo-Moon/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /web/splash/splash.js: -------------------------------------------------------------------------------- 1 | function removeSplashFromWeb() { 2 | const elem = document.getElementById("splash"); 3 | if (elem) { 4 | elem.remove(); 5 | } 6 | document.body.style.background = "transparent"; 7 | } 8 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/yagizdokumaci/todo_app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.yagizdokumaci.todo_app 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/img/cnameicon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /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/Widgets/Profile/string_extension.dart: -------------------------------------------------------------------------------- 1 | extension StringCasingExtension on String { 2 | String toCapitalized() => 3 | length > 0 ? '${this[0].toUpperCase()}${substring(1).toLowerCase()}' : ''; 4 | String toTitleCase() => replaceAll(RegExp(' +'), ' ') 5 | .split(' ') 6 | .map((str) => str.toCapitalized()) 7 | .join(' '); 8 | } 9 | -------------------------------------------------------------------------------- /.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: 18116933e77adc82f80866c928266a5b4f1ed645 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /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/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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/provider/shared_prefences_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | class SharedPreferencesHelper { 4 | static SharedPreferences? _instance; 5 | static SharedPreferences get instance => _instance!; 6 | 7 | static Future init() async { 8 | _instance ??= await SharedPreferences.getInstance(); 9 | return _instance!; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "background.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 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 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "LaunchImage.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "LaunchImage@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "LaunchImage@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/BrandingImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "BrandingImage.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "BrandingImage@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "BrandingImage@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/img/editicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /web/splash/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin:0; 3 | height:100%; 4 | background: #ffffff; 5 | 6 | background-size: 100% 100%; 7 | } 8 | 9 | .center { 10 | margin: 0; 11 | position: absolute; 12 | top: 50%; 13 | left: 50%; 14 | -ms-transform: translate(-50%, -50%); 15 | transform: translate(-50%, -50%); 16 | } 17 | 18 | .contain { 19 | display:block; 20 | width:100%; height:100%; 21 | object-fit: contain; 22 | } 23 | 24 | .stretch { 25 | display:block; 26 | width:100%; height:100%; 27 | } 28 | 29 | .cover { 30 | display:block; 31 | width:100%; height:100%; 32 | object-fit: cover; 33 | } 34 | 35 | @media (prefers-color-scheme: dark) { 36 | body { 37 | margin:0; 38 | height:100%; 39 | background: #ffffff; 40 | 41 | background-size: 100% 100%; 42 | } 43 | } 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 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/Widgets/DetailPage/todo_description.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_size_text/auto_size_text.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:todo_app/Models/todo.dart'; 5 | 6 | class TodoDescription extends StatelessWidget { 7 | TodoDescription({Key? key, required this.todo, required this.textFontSize}) 8 | : super(key: key); 9 | Todo todo; 10 | double textFontSize; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Padding( 15 | padding: EdgeInsets.only(left: 20.w, right: 20.w, top: 20.h), 16 | child: Container( 17 | alignment: Alignment.topCenter, 18 | child: AutoSizeText( 19 | todo.description, 20 | textAlign: TextAlign.start, 21 | style: TextStyle(fontSize: textFontSize), 22 | ), 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/generated_plugin_registrant.dart: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // ignore_for_file: directives_ordering 6 | // ignore_for_file: lines_longer_than_80_chars 7 | // ignore_for_file: depend_on_referenced_packages 8 | 9 | import 'package:flutter_native_splash/flutter_native_splash_web.dart'; 10 | import 'package:fluttertoast/fluttertoast_web.dart'; 11 | import 'package:image_picker_for_web/image_picker_for_web.dart'; 12 | import 'package:shared_preferences_web/shared_preferences_web.dart'; 13 | import 'package:url_launcher_web/url_launcher_web.dart'; 14 | 15 | import 'package:flutter_web_plugins/flutter_web_plugins.dart'; 16 | 17 | // ignore: public_member_api_docs 18 | void registerPlugins(Registrar registrar) { 19 | FlutterNativeSplashWeb.registerWith(registrar); 20 | FluttertoastWebPlugin.registerWith(registrar); 21 | ImagePickerPlugin.registerWith(registrar); 22 | SharedPreferencesPlugin.registerWith(registrar); 23 | UrlLauncherPlugin.registerWith(registrar); 24 | registrar.registerMessageHandler(); 25 | } 26 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo_app", 3 | "short_name": "todo_app", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /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 that Flutter provides. 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 | void main() { 12 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 13 | // Build our app and trigger a frame. 14 | //await tester.pumpWidget(MyApp()); 15 | 16 | // Verify that our counter starts at 0. 17 | expect(find.text('0'), findsOneWidget); 18 | expect(find.text('1'), findsNothing); 19 | 20 | // Tap the '+' icon and trigger a frame. 21 | await tester.tap(find.byIcon(Icons.add)); 22 | await tester.pump(); 23 | 24 | // Verify that our counter has incremented. 25 | expect(find.text('0'), findsNothing); 26 | expect(find.text('1'), findsOneWidget); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /lib/Widgets/Dashboard/complete_todo_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:todo_app/provider/todos_provider.dart'; 4 | 5 | import 'complete_todo_card.dart'; 6 | 7 | class CompleteTodoList extends StatefulWidget { 8 | const CompleteTodoList({Key? key}) : super(key: key); 9 | 10 | @override 11 | _CompleteTodoListState createState() => _CompleteTodoListState(); 12 | } 13 | 14 | class _CompleteTodoListState extends State { 15 | @override 16 | Widget build(BuildContext context) { 17 | return Padding( 18 | padding: const EdgeInsets.only(top: 20.0), 19 | child: Consumer( 20 | builder: (context, state, child) => SizedBox( 21 | height: MediaQuery.of(context).size.height / 1.65, 22 | child: ListView.builder( 23 | itemCount: state.completedTodos.length, 24 | itemBuilder: (context, index) { 25 | return CompleteTodoCard( 26 | todo: state.completedTodos[index], 27 | ); 28 | }), 29 | ), 30 | ), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 17 | 20 | -------------------------------------------------------------------------------- /lib/Widgets/ChangeName/change_name_text.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:todo_app/translations/locale_keys.g.dart'; 4 | 5 | class ChangeNameText extends StatelessWidget { 6 | const ChangeNameText({Key? key}) : super(key: key); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Padding( 11 | padding: const EdgeInsets.only(top: 10), 12 | child: Column( 13 | children: [ 14 | Padding( 15 | padding: EdgeInsets.only(top: 10.0, left: 10, right: 10), 16 | child: Text( 17 | LocaleKeys.changename_title.tr(), 18 | style: TextStyle( 19 | fontSize: 25, 20 | fontWeight: FontWeight.bold, 21 | color: Colors.black), 22 | ), 23 | ), 24 | Padding( 25 | padding: const EdgeInsets.only(top: 20.0), 26 | child: Image.asset( 27 | 'lib/img/businessman-min.png', 28 | width: 170, 29 | ), 30 | ), 31 | ], 32 | )); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/Models/todo.dart: -------------------------------------------------------------------------------- 1 | class Todo { 2 | String title; 3 | String description; 4 | bool complete = false; 5 | String category; 6 | int dateMilliseconds; 7 | int timeMilliseconds; 8 | 9 | Todo( 10 | {required this.title, 11 | this.description = '', 12 | this.complete = false, 13 | required this.dateMilliseconds, 14 | required this.timeMilliseconds, 15 | this.category = 'Uncategorized'}); 16 | 17 | //toObject 18 | Todo.fromMap(Map map) 19 | : title = map['title'] as String, 20 | description = map['description'] as String, 21 | complete = map['complete'] as bool, 22 | category = map['category'] as String, 23 | dateMilliseconds = map['dateMilliseconds'] as int, 24 | timeMilliseconds = map['timeMilliseconds'] as int; 25 | 26 | //toJson 27 | Map toJson() { 28 | final Map data = {}; 29 | data['title'] = title; 30 | data['description'] = description; 31 | data['complete'] = complete; 32 | data['category'] = category; 33 | data['dateMilliseconds'] = dateMilliseconds; 34 | data['timeMilliseconds'] = timeMilliseconds; 35 | return data; 36 | } 37 | 38 | void toggleCompleted() { 39 | complete = !complete; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/Pages/dashboard_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:hexcolor/hexcolor.dart'; 4 | import 'package:todo_app/Widgets/Dashboard/complete_todo_list.dart'; 5 | import 'package:todo_app/Widgets/Dashboard/completed_task_info.dart'; 6 | import 'package:todo_app/translations/locale_keys.g.dart'; 7 | 8 | class DashboardPage extends StatefulWidget { 9 | const DashboardPage({Key? key}) : super(key: key); 10 | 11 | @override 12 | _DashboardPageState createState() => _DashboardPageState(); 13 | } 14 | 15 | class _DashboardPageState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: dashboardAB(), 20 | body: Container( 21 | color: HexColor('#f9f6e8'), 22 | child: Column( 23 | children: const [CompletedTaskInfo(), CompleteTodoList()], 24 | ), 25 | ), 26 | ); 27 | } 28 | } 29 | 30 | AppBar dashboardAB() { 31 | return AppBar( 32 | centerTitle: true, 33 | backgroundColor: HexColor('#f9f6e8'), 34 | elevation: 0, 35 | title: Text( 36 | LocaleKeys.dashboard_title.tr(), 37 | style: TextStyle(fontSize: 25, color: Colors.black), 38 | ), 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /lib/Widgets/Welcome/welcome_tf.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class WelcomCustomTF extends StatelessWidget { 4 | WelcomCustomTF({Key? key, required this.controller, required this.labelText}) 5 | : super(key: key); 6 | 7 | String labelText; 8 | TextEditingController controller; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Padding( 13 | padding: const EdgeInsets.only(left: 2.0, right: 2.0, top: 20.0), 14 | child: TextFormField( 15 | maxLength: 15, 16 | controller: controller, 17 | validator: (value) { 18 | if (value!.isEmpty) { 19 | return 'Please enter $labelText'; 20 | } 21 | }, 22 | decoration: InputDecoration( 23 | border: OutlineInputBorder( 24 | borderSide: BorderSide.none, 25 | borderRadius: BorderRadius.circular(10.0), 26 | ), 27 | fillColor: Colors.amber.shade50, 28 | filled: true, 29 | suffixIcon: IconButton( 30 | icon: const Icon( 31 | Icons.clear_outlined, 32 | size: 20, 33 | color: Colors.red, 34 | ), 35 | onPressed: () { 36 | controller.text = ''; 37 | }, 38 | ), 39 | hintText: labelText, 40 | ), 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /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 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /lib/Widgets/Welcome/welcome_text.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:todo_app/translations/locale_keys.g.dart'; 4 | 5 | class welcomeText extends StatelessWidget { 6 | const welcomeText({Key? key}) : super(key: key); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Padding( 11 | padding: const EdgeInsets.only(top: 20), 12 | child: Column( 13 | children: [ 14 | Padding( 15 | padding: EdgeInsets.only(top: 10.0, left: 10, right: 10), 16 | child: Text( 17 | LocaleKeys.welcomescreen_title.tr(), 18 | style: TextStyle( 19 | fontSize: 25, 20 | fontWeight: FontWeight.bold, 21 | color: Colors.black), 22 | ), 23 | ), 24 | Padding( 25 | padding: const EdgeInsets.only(top: 20.0), 26 | child: Image.asset( 27 | 'lib/img/businessman-min.png', 28 | width: 170, 29 | ), 30 | ), 31 | Padding( 32 | padding: EdgeInsets.only(top: 10.0, left: 15, right: 15), 33 | child: Text( 34 | LocaleKeys.welcomescreen_subtitle.tr(), 35 | style: TextStyle( 36 | fontSize: 16, 37 | fontWeight: FontWeight.bold, 38 | color: Colors.black), 39 | textAlign: TextAlign.center, 40 | ), 41 | ), 42 | ], 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/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:hexcolor/hexcolor.dart'; 6 | import 'package:provider/provider.dart'; 7 | import 'package:todo_app/Pages/main_screen.dart'; 8 | import 'package:todo_app/Pages/welcome_screen.dart'; 9 | import 'package:todo_app/provider/todos_provider.dart'; 10 | import 'package:todo_app/translations/codegen_loader.g.dart'; 11 | 12 | void main() async { 13 | WidgetsFlutterBinding.ensureInitialized(); 14 | await EasyLocalization.ensureInitialized(); 15 | TodosProvider().initSharedPreferences(); 16 | var userName = await TodosProvider().readName('userName'); 17 | await SystemChrome.setPreferredOrientations([ 18 | DeviceOrientation.portraitUp, 19 | DeviceOrientation.portraitDown, 20 | ]); 21 | runApp( 22 | ChangeNotifierProvider( 23 | create: (BuildContext context) => TodosProvider(), 24 | child: EasyLocalization( 25 | path: 'lib/langs', 26 | supportedLocales: [ 27 | Locale('en'), 28 | Locale('tr'), 29 | ], 30 | assetLoader: CodegenLoader(), 31 | fallbackLocale: Locale('en'), 32 | child: MyApp( 33 | userName: userName.toString(), 34 | ), 35 | ), 36 | ), 37 | ); 38 | } 39 | 40 | class MyApp extends StatelessWidget { 41 | const MyApp({Key? key, required this.userName}) : super(key: key); 42 | final userName; 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return MaterialApp( 47 | title: 'Todo Moon', 48 | debugShowCheckedModeBanner: false, 49 | locale: context.locale, 50 | supportedLocales: context.supportedLocales, 51 | theme: ThemeData( 52 | primaryColor: HexColor('#f9f6e8'), 53 | ), 54 | localizationsDelegates: context.localizationDelegates, 55 | home: userName.toString().contains('null') 56 | ? const WelcomeScreen() 57 | : const MainScreen(), 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Todo Moon 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleLocalizations 16 | 17 | en 18 | tr 19 | 20 | CFBundleName 21 | todo_app 22 | CFBundlePackageType 23 | APPL 24 | CFBundleShortVersionString 25 | $(MARKETING_VERSION) 26 | CFBundleSignature 27 | ???? 28 | CFBundleVersion 29 | $(CURRENT_PROJECT_VERSION) 30 | LSRequiresIPhoneOS 31 | 32 | NSPhotoLibraryUsageDescription 33 | App needs access to photo lib for profile images 34 | UIBackgroundModes 35 | 36 | remote-notification 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIMainStoryboardFile 41 | Main 42 | UIStatusBarHidden 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | 48 | UISupportedInterfaceOrientations~ipad 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationPortraitUpsideDown 52 | UIInterfaceOrientationLandscapeLeft 53 | UIInterfaceOrientationLandscapeRight 54 | 55 | UIViewControllerBasedStatusBarAppearance 56 | 57 | CADisableMinimumFrameDurationOnPhone 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /lib/langs/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "homescreen": { 3 | "hello_text": "Hello", 4 | "subtitle_text": "How is your work life balance this week?", 5 | "goodjob_text": "Good Job {}!", 6 | "goodjob_subtitle_text": "Your life is well-balanced", 7 | "taskstitle": "Your tasks", 8 | "taskssubtitle": "You have {} tasks for {}" 9 | }, 10 | "dashboard": { 11 | "tasktitle": "Your tasks", 12 | "taskssubtitle": "You have {} tasks completed all time", 13 | "alertdialog": { 14 | "title": "Are you sure?", 15 | "subtitle": "You do realize that all todos you complete will be deleted, right?", 16 | "delete": "Delete completed todos!", 17 | "cancel": "Cancel" 18 | }, 19 | "title": "Dashboard" 20 | }, 21 | "profile": { 22 | "completed_text": "Completed", 23 | "uncompleted_text": "Uncomplete", 24 | "alltasks_text": "All Tasks", 25 | "title": "Profile", 26 | "stats": "Statistics" 27 | }, 28 | "changename": { 29 | "name_tf": "Name", 30 | "surname_tf": "Surname", 31 | "title": "Change Name", 32 | "cancel_btn": "Cancel", 33 | "done_btn": "Done" 34 | }, 35 | "addtodo": { 36 | "title": "Add Todo", 37 | "title_tf": "Title", 38 | "desc_tf": "Description", 39 | "category_tf": "Category", 40 | "date": "Select Date\nDefault Date: {}", 41 | "time": "Select Time\nDefault Time : {}", 42 | "add_btn": "Add Todo", 43 | "cancel_btn": "Cancel", 44 | "selected": "Selected {}", 45 | "error_text": "Please enter {}" 46 | }, 47 | "edittodo": { 48 | "title": "Edit Task", 49 | "title_tf": "Title", 50 | "category_tf": "Category", 51 | "desc_tf": "Description", 52 | "selecteddate": "Selected Date : {}", 53 | "selectedtime": "Selected Time : {}", 54 | "default_date": "Task Date : {}", 55 | "default_time": "Task Time : {}", 56 | "edit_btn": "Finish editing", 57 | "close_btn": "Close" 58 | }, 59 | "welcomescreen": { 60 | "title": "Welcome", 61 | "subtitle": "Please provide your name and surname to address you", 62 | "done_button": "Done", 63 | "name_tf": "Name", 64 | "surname_tf": "Surname" 65 | } 66 | } -------------------------------------------------------------------------------- /lib/Widgets/Profile/todos_big_container.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:hexcolor/hexcolor.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | import '../../provider/todos_provider.dart'; 7 | 8 | class TodosBigContainer extends StatelessWidget { 9 | TodosBigContainer( 10 | {Key? key, 11 | required this.containerHeight, 12 | required this.containerWidth, 13 | required this.numberfontSize, 14 | required this.textfontSize, 15 | required this.backgroundColor, 16 | required this.text}) 17 | : super(key: key); 18 | 19 | double containerHeight; 20 | double containerWidth; 21 | double numberfontSize; 22 | double textfontSize; 23 | String backgroundColor; 24 | String text; 25 | @override 26 | Widget build(BuildContext context) { 27 | return Consumer( 28 | builder: (context, state, child) { 29 | return Container( 30 | height: containerHeight, 31 | width: containerWidth, 32 | decoration: BoxDecoration( 33 | color: HexColor(backgroundColor), 34 | borderRadius: const BorderRadius.all( 35 | Radius.circular(14.0), 36 | ), 37 | ), 38 | child: Column( 39 | mainAxisAlignment: MainAxisAlignment.center, 40 | crossAxisAlignment: CrossAxisAlignment.center, 41 | children: [ 42 | Text( 43 | text, 44 | style: TextStyle( 45 | color: HexColor('#393939'), 46 | fontSize: textfontSize, 47 | fontWeight: FontWeight.w600), 48 | ), 49 | SizedBox(height: 10.h), 50 | Text( 51 | '${state.allTodos.length}', 52 | style: TextStyle( 53 | color: HexColor('#393939'), 54 | fontSize: numberfontSize, 55 | fontWeight: FontWeight.w700), 56 | ), 57 | ], 58 | ), 59 | ); 60 | }, 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/Widgets/Dashboard/completed_task_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:todo_app/provider/todos_provider.dart'; 5 | import 'package:todo_app/translations/locale_keys.g.dart'; 6 | 7 | import 'clear_todos_btn.dart'; 8 | 9 | class CompletedTaskInfo extends StatefulWidget { 10 | const CompletedTaskInfo({Key? key}) : super(key: key); 11 | 12 | @override 13 | _Task_InfoState createState() => _Task_InfoState(); 14 | } 15 | 16 | // ignore: camel_case_types 17 | class _Task_InfoState extends State { 18 | @override 19 | Widget build(BuildContext context) { 20 | return Padding( 21 | padding: const EdgeInsets.symmetric(horizontal: 24.0), 22 | child: Row( 23 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 24 | children: [ 25 | Padding( 26 | padding: const EdgeInsets.only(top: 5.0), 27 | child: Column( 28 | crossAxisAlignment: CrossAxisAlignment.start, 29 | children: [ 30 | Row( 31 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 32 | children: [ 33 | Text( 34 | LocaleKeys.dashboard_tasktitle.tr(), 35 | style: 36 | TextStyle(fontSize: 20, fontWeight: FontWeight.bold), 37 | ), 38 | ClearTodosBtn(), 39 | ], 40 | ), 41 | Consumer( 42 | builder: (context, state, child) => Text( 43 | LocaleKeys.dashboard_taskssubtitle 44 | .tr(args: ['${state.completedTodos.length}']), 45 | style: const TextStyle( 46 | fontSize: 14, 47 | fontWeight: FontWeight.bold, 48 | color: Colors.grey), 49 | ), 50 | ) 51 | ], 52 | ), 53 | ), 54 | ], 55 | ), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/langs/tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "homescreen": { 3 | "hello_text": "Merhaba", 4 | "subtitle_text": "Bu hafta iş yaşam dengeniz nasıl?", 5 | "goodjob_text": "İyi iş {}!", 6 | "goodjob_subtitle_text": "Hayatınız gayet dengeli", 7 | "taskstitle": "İşleriniz", 8 | "taskssubtitle": "{} tarihi için {} işiniz var" 9 | }, 10 | "dashboard": { 11 | "tasktitle": "İşleriniz", 12 | "taskssubtitle": "Toplamda {} tane iş bitirmişsiniz", 13 | "alertdialog": { 14 | "title": "Emin misiniz?", 15 | "subtitle": "Tamamlanmış tüm işleriniz silinecek. Bunun farkındasınız değil mi?", 16 | "delete": "Tamamlanmış tüm işleri sil!", 17 | "cancel": "Vazgeç" 18 | }, 19 | "title": "Panel" 20 | }, 21 | "profile": { 22 | "completed_text": "Tamamlanmış", 23 | "uncompleted_text": "Tamamlanmamış", 24 | "alltasks_text": "Tüm İşleriniz", 25 | "title": "Profil", 26 | "stats": "İstatistik" 27 | }, 28 | "changename": { 29 | "name_tf": "İsim", 30 | "surname_tf": "Soyad", 31 | "title": "İsminizi Değiştirin", 32 | "cancel_btn": "Vazgeç", 33 | "done_btn": "Değiştir" 34 | }, 35 | "addtodo": { 36 | "title": "İş Ekle", 37 | "title_tf": "Başlık", 38 | "desc_tf": "Açıklama", 39 | "category_tf": "Kategori", 40 | "date": "Tarih Seçin\nVarsayılan Tarih: {}", 41 | "time": "Saat Seçin\nVarsayılan Saat: {}", 42 | "add_btn": "İş Ekle", 43 | "cancel_btn": "Vazgeç", 44 | "selected": "Seçilen {}", 45 | "error_text": "Lütfen {} giriniz" 46 | }, 47 | "edittodo": { 48 | "title": "İşi Düzenle", 49 | "title_tf": "Başlık", 50 | "category_tf": "Kategori", 51 | "desc_tf": "Açıklama", 52 | "selecteddate": "Seçilen Tarih : {}", 53 | "selectedtime": "Seçilen Saat : {}", 54 | "default_date": "İşin Tarihi : {}", 55 | "default_time": "İşin Saati : {}", 56 | "edit_btn": "Düzenlemeyi bitir", 57 | "close_btn": "Kapat" 58 | }, 59 | "welcomescreen": { 60 | "title": "Hoşgeldin", 61 | "subtitle": "Size hitap etmek için lütfen adınızı ve soyadınızı belirtin", 62 | "done_button": "Tamam", 63 | "name_tf": "İsim", 64 | "surname_tf": "Soyad" 65 | } 66 | } -------------------------------------------------------------------------------- /lib/Review/review_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:in_app_review/in_app_review.dart'; 2 | import 'package:shared_preferences/shared_preferences.dart'; 3 | import 'package:todo_app/provider/shared_prefences_helper.dart'; 4 | 5 | const KEY = 'FIRST_TIME_OPEN'; 6 | const COUNTER = 'OPEN_COUNTER'; 7 | 8 | class ReviewService { 9 | late SharedPreferences _sharedPreferences; 10 | late int openCounter; 11 | 12 | final InAppReview _inAppReview = InAppReview.instance; 13 | Future isSecondTimeOpen() async { 14 | _sharedPreferences = await SharedPreferencesHelper.instance; 15 | openCounter = _sharedPreferences.getInt(COUNTER) ?? 1; 16 | try { 17 | dynamic isSecondTime = _sharedPreferences.getBool(KEY); 18 | if (openCounter == 3) { 19 | _sharedPreferences.setBool(KEY, true); 20 | openCounter += 1; 21 | _sharedPreferences.setInt(COUNTER, openCounter); 22 | return true; 23 | } else if (openCounter == 15) { 24 | _sharedPreferences.setBool(KEY, true); 25 | openCounter += 1; 26 | _sharedPreferences.setInt(COUNTER, openCounter); 27 | return true; 28 | } else if (openCounter == 150) { 29 | _sharedPreferences.setBool(KEY, true); 30 | openCounter += 1; 31 | _sharedPreferences.setInt(COUNTER, openCounter); 32 | return true; 33 | } else if (openCounter == 400) { 34 | _sharedPreferences.setBool(KEY, true); 35 | openCounter += 1; 36 | _sharedPreferences.setInt(COUNTER, openCounter); 37 | return true; 38 | } else { 39 | _sharedPreferences.setBool(KEY, false); 40 | openCounter += 1; 41 | _sharedPreferences.setInt(COUNTER, openCounter); 42 | return false; 43 | } 44 | } catch (e) { 45 | return false; 46 | } 47 | } 48 | 49 | Future showRating() async { 50 | try { 51 | final available = await _inAppReview.isAvailable(); 52 | if (available) { 53 | _inAppReview.requestReview(); 54 | } else { 55 | _inAppReview.openStoreListing( 56 | appStoreId: 'com.yagizdokumaci.todomoon', 57 | ); 58 | } 59 | return true; 60 | } catch (e) { 61 | return false; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/Widgets/Todo/todo_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:todo_app/Widgets/Todo/todo_card.dart'; 4 | import 'package:todo_app/provider/todos_provider.dart'; 5 | 6 | class TodoWidget extends StatefulWidget { 7 | const TodoWidget({Key? key}) : super(key: key); 8 | 9 | @override 10 | _TodoWidgetState createState() => _TodoWidgetState(); 11 | } 12 | 13 | class _TodoWidgetState extends State { 14 | @override 15 | void initState() { 16 | super.initState(); 17 | } 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Consumer( 22 | builder: (context, state, child) => SizedBox( 23 | height: MediaQuery.of(context).size.height / 2.68, 24 | child: ListView.builder( 25 | itemCount: state.unCompletedTodos.where((Todo) { 26 | return DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds) 27 | .day == 28 | DateTime.now().day && 29 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds) 30 | .month == 31 | DateTime.now().month && 32 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds) 33 | .year == 34 | DateTime.now().year; 35 | }).length, 36 | itemBuilder: (context, index) { 37 | return TodoCard( 38 | todo: state.unCompletedTodos.where((Todo) { 39 | return DateTime.fromMillisecondsSinceEpoch( 40 | Todo.dateMilliseconds) 41 | .day == 42 | DateTime.now().day && 43 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds) 44 | .month == 45 | DateTime.now().month && 46 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds) 47 | .year == 48 | DateTime.now().year; 49 | }).toList()[index], 50 | ); 51 | }), 52 | ), 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 14 | 18 | 22 | 27 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /lib/Widgets/Todo/edit_tf.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import '../../translations/locale_keys.g.dart'; 5 | 6 | class EditTF extends StatelessWidget { 7 | EditTF( 8 | {Key? key, 9 | required this.hint, 10 | required this.controller, 11 | required this.labelText}) 12 | : super(key: key); 13 | 14 | String labelText; 15 | String hint; 16 | TextEditingController controller; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Padding( 21 | padding: const EdgeInsets.only(left: 20.0, right: 20.0, top: 15.0), 22 | child: TextFormField( 23 | textInputAction: labelText.contains(LocaleKeys.edittodo_desc_tf.tr()) || 24 | labelText.contains(LocaleKeys.edittodo_title_tf.tr()) 25 | ? TextInputAction.next 26 | : TextInputAction.done, 27 | maxLength: labelText.contains(LocaleKeys.addtodo_title_tf.tr()) 28 | ? 15 29 | : labelText.contains(LocaleKeys.edittodo_category_tf.tr()) 30 | ? 15 31 | : 250, 32 | maxLines: 33 | labelText.contains(LocaleKeys.edittodo_desc_tf.tr()) ? null : 1, 34 | controller: controller, 35 | validator: (value) { 36 | if (labelText.contains(LocaleKeys.edittodo_title_tf.tr())) { 37 | if (value!.isEmpty 38 | // || RegExp(r"\s").hasMatch(value.toString()) 39 | ) { 40 | return LocaleKeys.addtodo_error_text.tr(args: [labelText]); 41 | } 42 | } 43 | }, 44 | decoration: InputDecoration( 45 | border: OutlineInputBorder( 46 | borderSide: BorderSide.none, 47 | borderRadius: BorderRadius.circular(10.0), 48 | ), 49 | fillColor: Colors.amber.shade50, 50 | filled: true, 51 | suffixIcon: IconButton( 52 | icon: const Icon( 53 | Icons.clear_outlined, 54 | size: 20, 55 | color: Colors.red, 56 | ), 57 | onPressed: () { 58 | controller.text = ''; 59 | }, 60 | ), 61 | hintText: labelText, 62 | hintStyle: const TextStyle(color: Colors.black)), 63 | ), 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/Widgets/Todo/custom_tf.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:todo_app/translations/locale_keys.g.dart'; 4 | 5 | class CustomTF extends StatelessWidget { 6 | CustomTF( 7 | {Key? key, 8 | required this.hint, 9 | required this.controller, 10 | required this.labelText}) 11 | : super(key: key); 12 | 13 | String labelText; 14 | String hint; 15 | TextEditingController controller; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Padding( 20 | padding: const EdgeInsets.only(left: 20.0, right: 20.0, top: 15.0), 21 | child: TextFormField( 22 | textInputAction: labelText.contains(LocaleKeys.addtodo_desc_tf.tr()) || 23 | labelText.contains(LocaleKeys.addtodo_title_tf.tr()) 24 | ? TextInputAction.next 25 | : TextInputAction.done, 26 | maxLength: labelText.contains(LocaleKeys.addtodo_title_tf.tr()) 27 | ? 15 28 | : labelText.contains(LocaleKeys.addtodo_category_tf.tr()) 29 | ? 15 30 | : 250, 31 | maxLines: 32 | labelText.contains(LocaleKeys.addtodo_desc_tf.tr()) ? null : 1, 33 | controller: controller, 34 | validator: (value) { 35 | if (labelText.contains(LocaleKeys.addtodo_title_tf.tr())) { 36 | if (value!.isEmpty 37 | //|| RegExp(r"\s").hasMatch(value.toString(),) 38 | ) { 39 | return LocaleKeys.addtodo_error_text.tr(args: [labelText]); 40 | } 41 | } 42 | }, 43 | decoration: InputDecoration( 44 | border: OutlineInputBorder( 45 | borderSide: BorderSide.none, 46 | borderRadius: BorderRadius.circular(10.0), 47 | ), 48 | fillColor: Colors.amber.shade50, 49 | filled: true, 50 | suffixIcon: IconButton( 51 | icon: const Icon( 52 | Icons.clear_outlined, 53 | size: 20, 54 | color: Colors.red, 55 | ), 56 | onPressed: () { 57 | controller.text = ''; 58 | }, 59 | ), 60 | hintText: labelText, 61 | hintStyle: const TextStyle(color: Colors.black)), 62 | ), 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/Widgets/Profile/todos_stats_comp.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:hexcolor/hexcolor.dart'; 5 | import 'package:todo_app/Widgets/Profile/todos_big_container.dart'; 6 | import 'package:todo_app/Widgets/Profile/todos_container.dart'; 7 | 8 | import '../../translations/locale_keys.g.dart'; 9 | 10 | class TodosStats extends StatelessWidget { 11 | const TodosStats({Key? key}) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Stack( 16 | fit: StackFit.expand, 17 | children: [ 18 | Padding( 19 | padding: EdgeInsets.only(left: 18.w), 20 | child: Text( 21 | LocaleKeys.profile_stats.tr(), 22 | style: TextStyle( 23 | fontWeight: FontWeight.bold, 24 | fontSize: 20.w, 25 | color: HexColor('#393939'), 26 | ), 27 | ), 28 | ), 29 | // Completed Todos 30 | Positioned( 31 | top: 50.h, 32 | left: 20.w, 33 | child: TodosContainer( 34 | containerHeight: 160.h, 35 | containerWidth: 160.w, 36 | numberfontSize: 45.w, 37 | textfontSize: 22.w, 38 | backgroundColor: '#FF9D78', 39 | text: LocaleKeys.profile_completed_text.tr(), 40 | ), 41 | ), 42 | 43 | // Uncompleted Todos 44 | Positioned( 45 | top: 50.h, 46 | left: 205.w, 47 | child: TodosContainer( 48 | containerHeight: 160.h, 49 | containerWidth: 160.w, 50 | numberfontSize: 45.w, 51 | textfontSize: context.locale == Locale('en') ? 22.w : 18.w, 52 | backgroundColor: '#FFC8B4', 53 | text: LocaleKeys.profile_uncompleted_text.tr(), 54 | ), 55 | ), 56 | 57 | // All Todos 58 | Positioned( 59 | top: 240.h, 60 | left: 20.w, 61 | child: TodosBigContainer( 62 | containerHeight: 160.h, 63 | containerWidth: 345.w, 64 | numberfontSize: 45.w, 65 | textfontSize: 22.w, 66 | backgroundColor: '#F9F6E9', 67 | text: LocaleKeys.profile_alltasks_text.tr(), 68 | ), 69 | ) 70 | ], 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter - Todo App 2 | 3 | Todo App I made with Flutter. 4 | 5 | Desing : https://dribbble.com/shots/8935948-Work-life-Balance-app 6 | 7 | #### App Store 8 | Download on the App Store 9 | 10 | #### Google Play 11 | 12 | Get it on Google Play 13 | 14 | ## Run Locally 15 | 16 | Clone the project 17 | 18 | ```bash 19 | git clone https://github.com/yagizdo/Todo-Moon 20 | ``` 21 | 22 | Go to the project directory 23 | 24 | ```bash 25 | cd Todo-Moon 26 | ``` 27 | 28 | Install dependencies 29 | 30 | ```bash 31 | flutter pub get 32 | ``` 33 | 34 | Run App 35 | 36 | ```bash 37 | flutter run 38 | ``` 39 | 40 | 41 | ## What will be add :question: 42 | 43 | - [x] Dynamic Todos 44 | - [x] HomePage UI 45 | - [X] Add Todo Page 46 | - [x] Shared Preferences for Add Todo Page 47 | - [x] State Management (Provider) 48 | - [ ] Dark Mode 49 | - [x] Splash Screen 50 | 51 | 52 | ## Libraries I use in the application: 53 | - Provider : https://pub.dev/packages/provider 54 | - Shared Preferences : https://pub.dev/packages/shared_preferences 55 | - Slidable : https://pub.dev/packages/flutter_slidable 56 | - Font Awesome Flutter : https://pub.dev/packages/font_awesome_flutter 57 | - Hex Color : https://pub.dev/packages/hexcolor 58 | - Percent Indicator : https://pub.dev/packages/percent_indicator 59 | - Flutter Toast : https://pub.dev/packages/fluttertoast 60 | - Flutter Launcher Icons : https://pub.dev/packages/flutter_launcher_icons 61 | - Modal Bottom Sheet : https://pub.dev/packages/modal_bottom_sheet 62 | - Flutter Native Splash : https://pub.dev/packages/flutter_native_splash 63 | 64 | 65 | 66 | ## App Video 67 | 68 | 69 | https://user-images.githubusercontent.com/31064552/183441566-ade1c1c1-81fa-4b75-844b-2d762a11a61e.mp4 70 | 71 | 72 | ## Contributing 73 | 74 | Contributions are always welcome! 75 | -------------------------------------------------------------------------------- /lib/Widgets/HomePage/Grettings/greetings.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_size_text/auto_size_text.dart'; 2 | import 'package:easy_localization/easy_localization.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:hexcolor/hexcolor.dart'; 5 | import 'package:provider/provider.dart'; 6 | import 'package:todo_app/provider/todos_provider.dart'; 7 | 8 | import '../../../translations/locale_keys.g.dart'; 9 | 10 | // Welcome Text Widget 11 | Widget _welcomeText( 12 | String text, double size, FontWeight fontWeight, Color color) { 13 | return AutoSizeText( 14 | text, 15 | style: TextStyle( 16 | fontSize: size, 17 | fontWeight: fontWeight, 18 | color: color, 19 | ), 20 | maxLines: 1, 21 | ); 22 | } 23 | 24 | // ignore: must_be_immutable 25 | class Greetings extends StatelessWidget { 26 | Greetings({Key? key, required this.customFontSize}) : super(key: key); 27 | double customFontSize; 28 | @override 29 | Widget build(BuildContext context) { 30 | return Column( 31 | children: [ 32 | SizedBox( 33 | height: MediaQuery.of(context).size.height / 18, 34 | ), 35 | Container( 36 | height: MediaQuery.of(context).size.height / 7.5, 37 | color: HexColor('#f9f6e8'), 38 | child: Column(children: [ 39 | Row( 40 | mainAxisAlignment: MainAxisAlignment.center, 41 | children: [ 42 | _welcomeText(LocaleKeys.homescreen_hello_text.tr(), 43 | customFontSize, FontWeight.normal, Colors.black), 44 | Consumer( 45 | builder: (context, state, child) => Padding( 46 | padding: const EdgeInsets.only(left: 5.0), 47 | child: _welcomeText(state.name, customFontSize, 48 | FontWeight.bold, Colors.black), 49 | ), 50 | ), 51 | ], 52 | ), 53 | Row( 54 | mainAxisAlignment: MainAxisAlignment.center, 55 | children: [ 56 | Padding( 57 | padding: const EdgeInsets.only(top: 10.0), 58 | child: _welcomeText( 59 | LocaleKeys.homescreen_subtitle_text.tr(), 60 | 15, 61 | FontWeight.normal, 62 | Colors.black, 63 | ), 64 | ), 65 | ], 66 | ), 67 | ]), 68 | ), 69 | ], 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/Widgets/Profile/name_text.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_size_text/auto_size_text.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:flutter_svg/svg.dart'; 5 | import 'package:hexcolor/hexcolor.dart'; 6 | import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 7 | import 'package:provider/provider.dart'; 8 | import 'package:todo_app/provider/todos_provider.dart'; 9 | 10 | import '../../Pages/change_name_page.dart'; 11 | import "string_extension.dart"; 12 | 13 | class NameText extends StatelessWidget { 14 | const NameText({Key? key}) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return LayoutBuilder(builder: (context, constraints) { 19 | return Column( 20 | children: [ 21 | // Name text top padding 22 | const SizedBox( 23 | height: 5, 24 | ), 25 | Row( 26 | mainAxisAlignment: MainAxisAlignment.center, 27 | children: [ 28 | Consumer( 29 | builder: (context, state, child) => AutoSizeText( 30 | '${state.name.toTitleCase()} ${state.surname.toTitleCase()} ', 31 | maxLines: 1, 32 | style: TextStyle( 33 | fontSize: 20.w, 34 | fontWeight: FontWeight.w500, 35 | color: HexColor('#393939')), 36 | ), 37 | ), 38 | GestureDetector( 39 | onTap: () { 40 | /*Navigator.push(context, 41 | MaterialPageRoute(builder: (context) => ChangeNameScreen()));*/ 42 | showCupertinoModalBottomSheet( 43 | shape: RoundedRectangleBorder( 44 | side: BorderSide.none, 45 | borderRadius: BorderRadius.circular(20.0), 46 | ), 47 | context: context, 48 | builder: (context) => SizedBox( 49 | height: MediaQuery.of(context).size.height / 1.2, 50 | child: const ChangeNameScreen())); 51 | }, 52 | child: SvgPicture.asset( 53 | 'lib/img/cnameicon.svg', 54 | color: HexColor('#393939'), 55 | width: 15.w, 56 | ), 57 | ), 58 | ], 59 | ) 60 | ], 61 | ); 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '4' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.2' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | def keyProperties = new Properties() 29 | def keyPropertiesFile = rootProject.file('key.properties') 30 | if(keyPropertiesFile.exists()) { 31 | keyProperties.load(new FileInputStream(keyPropertiesFile)) 32 | } 33 | 34 | 35 | android { 36 | compileSdkVersion 31 37 | 38 | compileOptions { 39 | sourceCompatibility JavaVersion.VERSION_1_8 40 | targetCompatibility JavaVersion.VERSION_1_8 41 | } 42 | 43 | kotlinOptions { 44 | jvmTarget = '1.8' 45 | } 46 | 47 | sourceSets { 48 | main.java.srcDirs += 'src/main/kotlin' 49 | } 50 | 51 | defaultConfig { 52 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 53 | applicationId "com.yagizdokumaci.todo_app" 54 | minSdkVersion 16 55 | targetSdkVersion 30 56 | versionCode flutterVersionCode.toInteger() 57 | versionName flutterVersionName 58 | } 59 | 60 | signingConfigs { 61 | release { 62 | keyAlias keyProperties['keyAlias'] 63 | keyPassword keyProperties['keyPassword'] 64 | storeFile file(keyProperties['storeFile']) 65 | storePassword keyProperties['storePassword'] 66 | } 67 | } 68 | 69 | buildTypes { 70 | release { 71 | // TODO: Add your own signing config for the release build. 72 | // Signing with the debug keys for now, so `flutter run --release` works. 73 | signingConfig signingConfigs.release 74 | } 75 | } 76 | } 77 | 78 | flutter { 79 | source '../..' 80 | } 81 | 82 | dependencies { 83 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 84 | } 85 | -------------------------------------------------------------------------------- /lib/Widgets/Profile/profile_circle.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:hexcolor/hexcolor.dart'; 4 | import 'package:provider/provider.dart'; 5 | import 'package:todo_app/provider/todos_provider.dart'; 6 | 7 | import 'name_text.dart'; 8 | 9 | class ProfileImg extends StatefulWidget { 10 | ProfileImg({Key? key, required this.avatarSize}) : super(key: key); 11 | double avatarSize; 12 | 13 | @override 14 | State createState() => _ProfileImgState(); 15 | } 16 | 17 | class _ProfileImgState extends State { 18 | @override 19 | void initState() { 20 | super.initState(); 21 | Provider.of(context, listen: false).base64ToImage(); 22 | } 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return Container( 27 | width: MediaQuery.of(context).size.width, 28 | child: Stack( 29 | children: [ 30 | Column( 31 | children: [ 32 | GestureDetector( 33 | onTap: () { 34 | setState(() { 35 | Provider.of(context, listen: false) 36 | .pickImage(context); 37 | }); 38 | }, 39 | child: Consumer( 40 | builder: (context, state, child) => state.profileImage != null 41 | ? CircleAvatar( 42 | backgroundImage: MemoryImage(state.profileImage!), 43 | radius: widget.avatarSize, 44 | ) 45 | : CircleAvatar( 46 | child: Text( 47 | '${state.name[0].toUpperCase()}${state.surname[0].toUpperCase()}', 48 | style: const TextStyle( 49 | fontSize: 30, color: Colors.white), 50 | ), 51 | backgroundColor: HexColor('#ff9d73'), 52 | radius: widget.avatarSize, 53 | ), 54 | ), 55 | ), 56 | const NameText(), 57 | ], 58 | ), 59 | Positioned( 60 | top: 70.h, 61 | left: 215.w, 62 | child: Container( 63 | decoration: const BoxDecoration( 64 | color: Colors.white, 65 | borderRadius: BorderRadius.all( 66 | Radius.circular(40), 67 | ), 68 | ), 69 | child: Icon( 70 | Icons.add_circle, 71 | color: HexColor('#FFBA9D'), 72 | ), 73 | ), 74 | ) 75 | ], 76 | ), 77 | ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/Pages/profile_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:hexcolor/hexcolor.dart'; 5 | import 'package:todo_app/Widgets/Profile/profile_circle.dart'; 6 | import 'package:todo_app/translations/locale_keys.g.dart'; 7 | 8 | import '../Widgets/Profile/todos_stats_comp.dart'; 9 | 10 | class ProfilePage extends StatelessWidget { 11 | const ProfilePage({Key? key}) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return ScreenUtilInit( 16 | designSize: const Size(391, 850), 17 | builder: () => LayoutBuilder(builder: (context, constraints) { 18 | return Scaffold( 19 | backgroundColor: HexColor('#F9F6E9'), 20 | // App Bar 21 | appBar: AppBar( 22 | backgroundColor: HexColor('#F9F6E9'), 23 | title: Text( 24 | LocaleKeys.profile_title.tr(), 25 | style: TextStyle(color: Colors.black), 26 | ), 27 | elevation: 0, 28 | ), 29 | body: Stack( 30 | children: [ 31 | Column( 32 | children: [ 33 | Expanded( 34 | flex: 1, 35 | child: Container( 36 | color: HexColor('#F9F6E9'), 37 | ), 38 | ), 39 | // White Container 40 | Expanded( 41 | flex: 42 | // For Pixel 2 - height 633.4285714285714 43 | constraints.maxHeight == 633.4285714285714 ? 5 : 7, 44 | child: Container( 45 | decoration: const BoxDecoration( 46 | color: Colors.white, 47 | borderRadius: BorderRadius.only( 48 | topRight: Radius.circular(30.0), 49 | topLeft: Radius.circular(30.0), 50 | ), 51 | ), 52 | child: Padding( 53 | padding: EdgeInsets.only( 54 | top: constraints.maxHeight == 617 || 55 | constraints.maxHeight == 518 56 | ? 120.h 57 | : 100.h), 58 | child: const TodosStats(), 59 | ), 60 | ), 61 | ) 62 | ], 63 | ), 64 | 65 | // Profile Avatar 66 | Positioned( 67 | top: constraints.maxHeight == 617 ? 25.w : 40.w, 68 | child: ProfileImg( 69 | avatarSize: 45.w, 70 | ), 71 | ) 72 | ], 73 | ), 74 | ); 75 | }), 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/Widgets/Profile/todos_container.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:hexcolor/hexcolor.dart'; 4 | import 'package:provider/provider.dart'; 5 | import 'package:todo_app/provider/todos_provider.dart'; 6 | 7 | class TodosContainer extends StatelessWidget { 8 | TodosContainer( 9 | {Key? key, 10 | required this.containerHeight, 11 | required this.containerWidth, 12 | required this.numberfontSize, 13 | required this.textfontSize, 14 | required this.backgroundColor, 15 | required this.text}) 16 | : super(key: key); 17 | double containerHeight; 18 | double containerWidth; 19 | double numberfontSize; 20 | double textfontSize; 21 | String backgroundColor; 22 | String text; 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return Consumer(builder: (context, state, child) { 27 | return Container( 28 | height: containerHeight, 29 | width: containerWidth, 30 | decoration: BoxDecoration( 31 | color: HexColor(backgroundColor), 32 | borderRadius: const BorderRadius.all( 33 | Radius.circular(14.0), 34 | ), 35 | ), 36 | child: text.contains('Completed') 37 | ? Column( 38 | mainAxisAlignment: MainAxisAlignment.center, 39 | crossAxisAlignment: CrossAxisAlignment.center, 40 | children: [ 41 | Text( 42 | '${state.completedTodos.length}', 43 | style: TextStyle( 44 | color: HexColor('#F9F6E9'), 45 | fontSize: numberfontSize, 46 | fontWeight: FontWeight.w700), 47 | ), 48 | SizedBox(height: 10.h), 49 | Text( 50 | text, 51 | style: TextStyle( 52 | color: HexColor('#F9F6E9'), 53 | fontSize: textfontSize, 54 | fontWeight: FontWeight.w600), 55 | ), 56 | ], 57 | ) 58 | : Column( 59 | mainAxisAlignment: MainAxisAlignment.center, 60 | crossAxisAlignment: CrossAxisAlignment.center, 61 | children: [ 62 | Text( 63 | '${state.unCompletedTodos.length}', 64 | style: TextStyle( 65 | color: HexColor('#F9F6E9'), 66 | fontSize: numberfontSize, 67 | fontWeight: FontWeight.w700), 68 | ), 69 | SizedBox(height: 10.h), 70 | Text( 71 | text, 72 | style: TextStyle( 73 | color: HexColor('#F9F6E9'), 74 | fontSize: textfontSize, 75 | fontWeight: FontWeight.w600), 76 | ), 77 | ], 78 | ), 79 | ); 80 | }); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /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/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 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /lib/translations/locale_keys.g.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:easy_localization/generate.dart 2 | 3 | abstract class LocaleKeys { 4 | static const homescreen_hello_text = 'homescreen.hello_text'; 5 | static const homescreen_subtitle_text = 'homescreen.subtitle_text'; 6 | static const homescreen_goodjob_text = 'homescreen.goodjob_text'; 7 | static const homescreen_goodjob_subtitle_text = 'homescreen.goodjob_subtitle_text'; 8 | static const homescreen_taskstitle = 'homescreen.taskstitle'; 9 | static const homescreen_taskssubtitle = 'homescreen.taskssubtitle'; 10 | static const homescreen = 'homescreen'; 11 | static const dashboard_tasktitle = 'dashboard.tasktitle'; 12 | static const dashboard_taskssubtitle = 'dashboard.taskssubtitle'; 13 | static const dashboard_alertdialog_title = 'dashboard.alertdialog.title'; 14 | static const dashboard_alertdialog_subtitle = 'dashboard.alertdialog.subtitle'; 15 | static const dashboard_alertdialog_delete = 'dashboard.alertdialog.delete'; 16 | static const dashboard_alertdialog_cancel = 'dashboard.alertdialog.cancel'; 17 | static const dashboard_alertdialog = 'dashboard.alertdialog'; 18 | static const dashboard_title = 'dashboard.title'; 19 | static const dashboard = 'dashboard'; 20 | static const profile_completed_text = 'profile.completed_text'; 21 | static const profile_uncompleted_text = 'profile.uncompleted_text'; 22 | static const profile_alltasks_text = 'profile.alltasks_text'; 23 | static const profile_title = 'profile.title'; 24 | static const profile_stats = 'profile.stats'; 25 | static const profile = 'profile'; 26 | static const changename_name_tf = 'changename.name_tf'; 27 | static const changename_surname_tf = 'changename.surname_tf'; 28 | static const changename_title = 'changename.title'; 29 | static const changename_cancel_btn = 'changename.cancel_btn'; 30 | static const changename_done_btn = 'changename.done_btn'; 31 | static const changename = 'changename'; 32 | static const addtodo_title = 'addtodo.title'; 33 | static const addtodo_title_tf = 'addtodo.title_tf'; 34 | static const addtodo_desc_tf = 'addtodo.desc_tf'; 35 | static const addtodo_category_tf = 'addtodo.category_tf'; 36 | static const addtodo_date = 'addtodo.date'; 37 | static const addtodo_time = 'addtodo.time'; 38 | static const addtodo_add_btn = 'addtodo.add_btn'; 39 | static const addtodo_cancel_btn = 'addtodo.cancel_btn'; 40 | static const addtodo_selected = 'addtodo.selected'; 41 | static const addtodo_error_text = 'addtodo.error_text'; 42 | static const addtodo = 'addtodo'; 43 | static const edittodo_title = 'edittodo.title'; 44 | static const edittodo_title_tf = 'edittodo.title_tf'; 45 | static const edittodo_category_tf = 'edittodo.category_tf'; 46 | static const edittodo_desc_tf = 'edittodo.desc_tf'; 47 | static const edittodo_selecteddate = 'edittodo.selecteddate'; 48 | static const edittodo_selectedtime = 'edittodo.selectedtime'; 49 | static const edittodo_default_date = 'edittodo.default_date'; 50 | static const edittodo_default_time = 'edittodo.default_time'; 51 | static const edittodo_edit_btn = 'edittodo.edit_btn'; 52 | static const edittodo_close_btn = 'edittodo.close_btn'; 53 | static const edittodo = 'edittodo'; 54 | static const welcomescreen_title = 'welcomescreen.title'; 55 | static const welcomescreen_subtitle = 'welcomescreen.subtitle'; 56 | static const welcomescreen_done_button = 'welcomescreen.done_button'; 57 | static const welcomescreen_name_tf = 'welcomescreen.name_tf'; 58 | static const welcomescreen_surname_tf = 'welcomescreen.surname_tf'; 59 | static const welcomescreen = 'welcomescreen'; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /lib/Widgets/DetailPage/todo_info_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:hexcolor/hexcolor.dart'; 4 | 5 | import '../../Models/todo.dart'; 6 | 7 | class TodoInfoSection extends StatelessWidget { 8 | TodoInfoSection({Key? key, required this.todo}) : super(key: key); 9 | Todo todo; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | DateTime todoDate = 14 | DateTime.fromMillisecondsSinceEpoch(todo.dateMilliseconds); 15 | DateTime todoTime = 16 | DateTime.fromMillisecondsSinceEpoch(todo.timeMilliseconds); 17 | return Container( 18 | color: Colors.transparent, 19 | child: Column( 20 | children: [ 21 | SizedBox( 22 | height: 20.h, 23 | ), 24 | categoryText(todo.category, context), 25 | SizedBox( 26 | height: 20.h, 27 | ), 28 | Text( 29 | todo.title, 30 | style: TextStyle( 31 | fontWeight: FontWeight.w700, 32 | color: HexColor('#393939'), 33 | fontSize: 24), 34 | ), 35 | Padding( 36 | padding: EdgeInsets.only(left: 20.w, top: 20.h), 37 | child: Row( 38 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 39 | children: [ 40 | Row( 41 | children: [ 42 | const Icon( 43 | Icons.calendar_today, 44 | ), 45 | Text( 46 | ' ${todoDate.day.toString().padLeft(2, '0')}/${todoDate.month.toString().padLeft(2, '0')}/${todoDate.year}', 47 | style: TextStyle( 48 | fontSize: 15, 49 | color: HexColor('#393939'), 50 | fontWeight: FontWeight.w600, 51 | ), 52 | ), 53 | ], 54 | ), 55 | Padding( 56 | padding: EdgeInsets.only(right: 20.w), 57 | child: Row( 58 | children: [ 59 | // Todos time part 60 | const Icon( 61 | Icons.access_time_outlined, 62 | ), 63 | Text( 64 | ' ${todoTime.hour.toString().padLeft(2, '0')}:${todoTime.minute.toString().padLeft(2, '0')}', 65 | style: TextStyle( 66 | fontSize: 15, 67 | color: HexColor('#393939'), 68 | fontWeight: FontWeight.w600, 69 | ), 70 | ), 71 | ], 72 | ), 73 | ) 74 | ], 75 | ), 76 | ), 77 | ], 78 | ), 79 | ); 80 | } 81 | } 82 | 83 | Widget categoryText(String categoryName, BuildContext context) { 84 | return Container( 85 | height: 25.h, 86 | width: 150.w, 87 | decoration: BoxDecoration( 88 | borderRadius: BorderRadius.circular(40.0), 89 | color: HexColor('#d3e3f2'), 90 | ), 91 | child: Padding( 92 | padding: const EdgeInsets.only(left: 10, right: 10), 93 | child: Center( 94 | child: Text( 95 | categoryName, 96 | style: const TextStyle( 97 | color: Colors.blue, fontWeight: FontWeight.bold, fontSize: 14), 98 | ), 99 | ), 100 | ), 101 | ); 102 | } 103 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /lib/Widgets/Dashboard/clear_todos_btn.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttertoast/fluttertoast.dart'; 4 | import 'package:hexcolor/hexcolor.dart'; 5 | import 'package:provider/provider.dart'; 6 | import 'package:todo_app/provider/todos_provider.dart'; 7 | import 'package:todo_app/translations/locale_keys.g.dart'; 8 | 9 | class ClearTodosBtn extends StatelessWidget { 10 | const ClearTodosBtn({Key? key}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return IconButton( 15 | onPressed: () { 16 | if (Provider.of(context, listen: false) 17 | .checkCompletedTodos() == 18 | true) { 19 | Fluttertoast.showToast( 20 | msg: "You do not have any completed todo.", 21 | toastLength: Toast.LENGTH_SHORT, 22 | gravity: ToastGravity.BOTTOM, 23 | timeInSecForIosWeb: 1, 24 | backgroundColor: Colors.red, 25 | textColor: Colors.white, 26 | fontSize: 16.0); 27 | } else { 28 | showDialog( 29 | context: context, 30 | builder: (BuildContext context) { 31 | return AlertDialog( 32 | backgroundColor: HexColor('#f9f6e8'), 33 | title: Text(LocaleKeys.dashboard_alertdialog_title.tr()), 34 | content: Text(LocaleKeys.dashboard_alertdialog_subtitle.tr()), 35 | actions: [ 36 | ElevatedButton( 37 | onPressed: () { 38 | Provider.of(context, listen: false) 39 | .removeCompletedTodos(); 40 | Navigator.of(context).pop(); 41 | Fluttertoast.showToast( 42 | msg: context.locale == Locale('en') 43 | ? 'Deleted!' 44 | : 'Silindi!', 45 | toastLength: Toast.LENGTH_SHORT, 46 | gravity: ToastGravity.BOTTOM, 47 | timeInSecForIosWeb: 1, 48 | backgroundColor: Colors.greenAccent, 49 | textColor: Colors.white, 50 | fontSize: 16.0); 51 | }, 52 | child: 53 | Text(LocaleKeys.dashboard_alertdialog_delete.tr())), 54 | TextButton( 55 | onPressed: () { 56 | Navigator.of(context).pop(); 57 | Fluttertoast.showToast( 58 | msg: context.locale == Locale('en') 59 | ? 'Cancelled!' 60 | : 'Vazgeçildi!', 61 | toastLength: Toast.LENGTH_SHORT, 62 | gravity: ToastGravity.BOTTOM, 63 | timeInSecForIosWeb: 1, 64 | backgroundColor: Colors.orange, 65 | textColor: Colors.white, 66 | fontSize: 16.0); 67 | }, 68 | child: 69 | Text(LocaleKeys.dashboard_alertdialog_cancel.tr())), 70 | ], 71 | ); 72 | }); 73 | } 74 | }, 75 | icon: const Icon( 76 | Icons.delete, 77 | color: Colors.red, 78 | size: 25, 79 | ), 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/Pages/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_app_badger/flutter_app_badger.dart'; 3 | import 'package:hexcolor/hexcolor.dart'; 4 | import 'package:provider/provider.dart'; 5 | import 'package:todo_app/Widgets/HomePage/Grettings/greetings.dart'; 6 | import 'package:todo_app/Widgets/HomePage/Info/info_widget.dart'; 7 | import 'package:todo_app/Widgets/HomePage/Tasks/task_info.dart'; 8 | import 'package:todo_app/Widgets/Todo/todo_list.dart'; 9 | 10 | import '../provider/todos_provider.dart'; 11 | 12 | class HomePage extends StatefulWidget { 13 | const HomePage({Key? key}) : super(key: key); 14 | 15 | @override 16 | _HomePageState createState() => _HomePageState(); 17 | } 18 | 19 | class _HomePageState extends State { 20 | late int badgeValue; 21 | 22 | @override 23 | void initState() { 24 | super.initState(); 25 | // App icon badge 26 | badgeValue = Provider.of(context, listen: false) 27 | .unCompletedTodos 28 | .where((Todo) { 29 | return DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds).day == 30 | DateTime.now().day && 31 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds).month == 32 | DateTime.now().month && 33 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds).year == 34 | DateTime.now().year; 35 | }).length; 36 | FlutterAppBadger.updateBadgeCount(badgeValue); 37 | } 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | return Scaffold( 42 | backgroundColor: HexColor('#f9f6e8'), 43 | body: LayoutBuilder(builder: (context, constraints) { 44 | return Column( 45 | children: [ 46 | constraints.maxWidth < 350 47 | ? Greetings(customFontSize: 25) 48 | : Greetings( 49 | customFontSize: 30, 50 | ), 51 | constraints.maxWidth < 350 52 | ? InfoWidget( 53 | height: 7.4, 54 | width: 1.1, 55 | customFontSize: 13, 56 | ) 57 | // For iphone 11 - height 812 || iphone 13 pro - height 760 58 | : constraints.maxHeight == 812 || constraints.maxHeight == 760 59 | ? InfoWidget(height: 11, width: 1.1, customFontSize: 18) 60 | // For iphone 11 pro, 13 mini, iphone xs - height 728 61 | : constraints.maxHeight == 728 62 | ? InfoWidget( 63 | height: 10.6, width: 1.1, customFontSize: 18) 64 | // For iphone 8,7,iphone se - height 617 65 | : constraints.maxHeight == 617 66 | ? InfoWidget( 67 | height: 8.5, width: 1.1, customFontSize: 18) 68 | // iphone 13 Pro max - 842 69 | : constraints.maxHeight == 842 70 | ? InfoWidget( 71 | height: 11.2, 72 | width: 1.1, 73 | customFontSize: 18) 74 | : constraints.maxHeight == 686 75 | ? InfoWidget( 76 | height: 9.4, 77 | width: 1.1, 78 | customFontSize: 18) 79 | : InfoWidget( 80 | height: 8, 81 | width: 1.1, 82 | customFontSize: 18), 83 | const TaskInfo(), 84 | const Expanded(child: TodoWidget()) 85 | ], 86 | ); 87 | }), 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/Pages/calendar_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hexcolor/hexcolor.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:table_calendar/table_calendar.dart'; 5 | import 'package:todo_app/Widgets/Todo/todo_card.dart'; 6 | import 'package:todo_app/provider/todos_provider.dart'; 7 | 8 | class CalendarPage extends StatefulWidget { 9 | const CalendarPage({Key? key}) : super(key: key); 10 | 11 | @override 12 | _CalendarPageState createState() => _CalendarPageState(); 13 | } 14 | 15 | class _CalendarPageState extends State { 16 | DateTime _focusedDay = DateTime.now(); 17 | DateTime? _selectedDay; 18 | 19 | @override 20 | void initState() { 21 | super.initState(); 22 | _selectedDay = _focusedDay; 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Scaffold( 28 | backgroundColor: HexColor('#f9f6e8'), 29 | body: Padding( 30 | padding: const EdgeInsets.only(top: 30.0), 31 | child: Column( 32 | children: [ 33 | TableCalendar( 34 | rowHeight: 45, 35 | firstDay: DateTime.utc(2010), 36 | lastDay: DateTime.utc(2050), 37 | eventLoader: 38 | Provider.of(context, listen: false).getTodos, 39 | focusedDay: _focusedDay, 40 | selectedDayPredicate: (day) => isSameDay(_selectedDay, day), 41 | calendarFormat: CalendarFormat.month, 42 | calendarStyle: const CalendarStyle( 43 | todayDecoration: BoxDecoration( 44 | color: Colors.amber, shape: BoxShape.circle)), 45 | onDaySelected: (selectedDay, focusedDay) { 46 | setState(() { 47 | _selectedDay = selectedDay; 48 | _focusedDay = focusedDay; // update `_focusedDay` here as well 49 | }); 50 | }, 51 | ), 52 | Expanded( 53 | child: Consumer(builder: (context, state, child) { 54 | return ListView.builder( 55 | // ignore: non_constant_identifier_names 56 | itemCount: state.unCompletedTodos.where((Todo) { 57 | return DateTime.fromMillisecondsSinceEpoch( 58 | Todo.dateMilliseconds) 59 | .day == 60 | _selectedDay?.day && 61 | DateTime.fromMillisecondsSinceEpoch( 62 | Todo.dateMilliseconds) 63 | .month == 64 | _selectedDay?.month && 65 | DateTime.fromMillisecondsSinceEpoch( 66 | Todo.dateMilliseconds) 67 | .year == 68 | _selectedDay?.year; 69 | }).length, 70 | itemBuilder: (context, index) => TodoCard( 71 | // ignore: non_constant_identifier_names 72 | todo: state.unCompletedTodos.where((Todo) { 73 | var todoTime = DateTime.fromMillisecondsSinceEpoch( 74 | Todo.dateMilliseconds); 75 | return todoTime.day == _selectedDay?.day && 76 | DateTime.fromMillisecondsSinceEpoch( 77 | Todo.dateMilliseconds) 78 | .month == 79 | _selectedDay?.month && 80 | DateTime.fromMillisecondsSinceEpoch( 81 | Todo.dateMilliseconds) 82 | .year == 83 | _selectedDay?.year; 84 | }).toList()[index]), 85 | ); 86 | }), 87 | ), 88 | ], 89 | ), 90 | ), 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/Pages/welcome_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:todo_app/Widgets/Welcome/welcome_text.dart'; 5 | import 'package:todo_app/Widgets/Welcome/welcome_tf.dart'; 6 | import 'package:todo_app/provider/todos_provider.dart'; 7 | import 'package:todo_app/translations/locale_keys.g.dart'; 8 | 9 | import 'main_screen.dart'; 10 | 11 | class WelcomeScreen extends StatefulWidget { 12 | const WelcomeScreen({Key? key}) : super(key: key); 13 | 14 | @override 15 | _WelcomeScreenState createState() => _WelcomeScreenState(); 16 | } 17 | 18 | class _WelcomeScreenState extends State { 19 | // ignore: prefer_typing_uninitialized_variables 20 | late var userName; 21 | 22 | @override 23 | void initState() { 24 | super.initState(); 25 | Provider.of(context, listen: false).initSharedPreferences(); 26 | userName = TodosProvider().readName('userName'); 27 | } 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | var nameController = TextEditingController(); 32 | var surnameController = TextEditingController(); 33 | var formKey = GlobalKey(); 34 | return Scaffold( 35 | body: Padding( 36 | padding: const EdgeInsets.only(top: 20.0), 37 | child: SingleChildScrollView( 38 | reverse: true, 39 | child: Column( 40 | children: [ 41 | const welcomeText(), 42 | Form( 43 | key: formKey, 44 | child: Padding( 45 | padding: const EdgeInsets.only( 46 | left: 15.0, right: 15, bottom: 10), 47 | child: Column(children: [ 48 | WelcomCustomTF( 49 | controller: nameController, 50 | labelText: LocaleKeys.welcomescreen_name_tf.tr()), 51 | WelcomCustomTF( 52 | controller: surnameController, 53 | labelText: LocaleKeys.welcomescreen_surname_tf.tr()), 54 | ]), 55 | ), 56 | ), 57 | Consumer( 58 | builder: (context, state, child) => Padding( 59 | padding: const EdgeInsets.only(top: 20.0), 60 | child: SizedBox( 61 | height: MediaQuery.of(context).size.height / 13, 62 | width: MediaQuery.of(context).size.width / 1.2, 63 | child: ElevatedButton( 64 | style: ButtonStyle( 65 | backgroundColor: MaterialStateProperty.all( 66 | Colors.amber.shade600), 67 | shape: MaterialStateProperty.all< 68 | RoundedRectangleBorder>(RoundedRectangleBorder( 69 | borderRadius: BorderRadius.circular(13.0), 70 | )), 71 | ), 72 | onPressed: () { 73 | bool validResult = formKey.currentState!.validate(); 74 | if (validResult == true) { 75 | state.setName(nameController.text); 76 | state.setsurName(surnameController.text); 77 | Navigator.pushReplacement( 78 | context, 79 | MaterialPageRoute( 80 | builder: (context) => 81 | const MainScreen())); 82 | } 83 | }, 84 | child: 85 | Text(LocaleKeys.welcomescreen_done_button.tr())), 86 | ), 87 | ), 88 | ) 89 | ], 90 | )), 91 | ), 92 | ); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/Widgets/HomePage/Info/info_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_size_text/auto_size_text.dart'; 2 | import 'package:easy_localization/easy_localization.dart'; 3 | import 'package:flutter/material.dart'; 4 | // External Libs 5 | import 'package:hexcolor/hexcolor.dart'; 6 | import 'package:percent_indicator/percent_indicator.dart'; 7 | import 'package:provider/provider.dart'; 8 | import 'package:todo_app/provider/todos_provider.dart'; 9 | import 'package:todo_app/translations/locale_keys.g.dart'; 10 | 11 | class InfoWidget extends StatelessWidget { 12 | InfoWidget( 13 | {Key? key, 14 | required this.height, 15 | required this.width, 16 | required this.customFontSize}) 17 | : super(key: key); 18 | double width; 19 | double height; 20 | double customFontSize; 21 | 22 | Widget _circularProgressBar(double percent) { 23 | return CircularPercentIndicator( 24 | radius: 48.0, 25 | lineWidth: 6.0, 26 | animation: true, 27 | percent: percent.isNaN ? 0 : percent, 28 | center: Text( 29 | percent.isNaN 30 | ? '${((percent = 0) * 100).round()}%' 31 | : '${(percent * 100).round()}%', 32 | style: const TextStyle(color: Colors.white, fontSize: 10), 33 | ), 34 | backgroundColor: Colors.white, 35 | progressColor: Colors.orangeAccent, 36 | ); 37 | } 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | double percent = 42 | Provider.of(context).calcTodoPercent(DateTime.now()); 43 | //print(percent); 44 | return Row( 45 | mainAxisAlignment: MainAxisAlignment.center, 46 | children: [ 47 | Stack( 48 | alignment: Alignment.bottomRight, 49 | children: [ 50 | Container( 51 | width: MediaQuery.of(context).size.width / width, 52 | height: MediaQuery.of(context).size.height / height, 53 | decoration: BoxDecoration( 54 | color: HexColor('#ff9d73'), 55 | borderRadius: BorderRadius.circular(20)), 56 | child: Padding( 57 | padding: const EdgeInsets.only(top: 14, bottom: 12, left: 24), 58 | child: Row( 59 | children: [ 60 | Column(children: [ 61 | _circularProgressBar(percent), 62 | ]), 63 | Padding( 64 | padding: const EdgeInsets.only(left: 14.0), 65 | child: Column( 66 | crossAxisAlignment: CrossAxisAlignment.start, 67 | children: [ 68 | Consumer( 69 | builder: (context, state, child) { 70 | return AutoSizeText( 71 | LocaleKeys.homescreen_goodjob_text 72 | .tr(args: [(state.name)]), 73 | maxLines: 2, 74 | style: TextStyle( 75 | color: Colors.white, 76 | fontSize: customFontSize, 77 | fontWeight: FontWeight.bold), 78 | ); 79 | }), 80 | Padding( 81 | padding: const EdgeInsets.symmetric(vertical: 6), 82 | child: Text( 83 | LocaleKeys.homescreen_goodjob_subtitle_text.tr(), 84 | style: const TextStyle( 85 | color: Colors.white, 86 | fontSize: 14, 87 | ), 88 | ), 89 | ) 90 | ], 91 | ), 92 | ), 93 | ], 94 | ), 95 | ), 96 | ) 97 | ], 98 | ), 99 | ], 100 | ); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lib/Pages/detail_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:flutter_svg/flutter_svg.dart'; 4 | import 'package:hexcolor/hexcolor.dart'; 5 | import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 6 | import 'package:todo_app/Models/todo.dart'; 7 | import 'package:todo_app/Widgets/DetailPage/todo_description.dart'; 8 | 9 | import '../Widgets/DetailPage/todo_info_section.dart'; 10 | import 'edit_todo.dart'; 11 | 12 | class DetailScreen extends StatelessWidget { 13 | const DetailScreen({Key? key, required this.todo}) : super(key: key); 14 | final Todo todo; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return ScreenUtilInit( 19 | builder: () => LayoutBuilder( 20 | builder: (context, constraints) { 21 | return Scaffold( 22 | floatingActionButton: FloatingActionButton( 23 | onPressed: () { 24 | showCupertinoModalBottomSheet( 25 | shape: RoundedRectangleBorder( 26 | borderRadius: BorderRadius.circular(10.0), 27 | ), 28 | context: context, 29 | builder: (context) => SizedBox( 30 | height: 31 | // for iphone 11 32 | constraints.maxHeight == 896 || 33 | constraints.maxHeight == 926 34 | ? MediaQuery.of(context).size.height / 1.6 35 | : 36 | // For iphone 11 pro, 12 mini, 12 pro(height 771) 37 | constraints.maxHeight == 812 || 38 | constraints.maxHeight == 771 39 | ? MediaQuery.of(context).size.height / 1.5 40 | : //For iphone 5s 41 | constraints.maxHeight == 522 42 | ? MediaQuery.of(context).size.height / 1 43 | : MediaQuery.of(context).size.height / 1.2, 44 | child: EditTodo( 45 | todo: todo, 46 | ), 47 | ), 48 | ); 49 | }, 50 | child: SvgPicture.asset( 51 | 'lib/img/editicon.svg', 52 | width: 26.w, 53 | ), 54 | backgroundColor: Colors.orangeAccent, 55 | ), 56 | backgroundColor: HexColor('#F9F6E9'), 57 | body: Column( 58 | children: [ 59 | Expanded( 60 | flex: 2, 61 | child: TodoInfoSection( 62 | todo: todo, 63 | ), 64 | ), 65 | Expanded( 66 | flex: constraints.maxHeight == 621 67 | ? 6 68 | : constraints.maxHeight == 522 69 | ? 5 70 | : 7, 71 | child: Container( 72 | decoration: const BoxDecoration( 73 | color: Colors.white, 74 | borderRadius: BorderRadius.only( 75 | topLeft: Radius.circular(30), 76 | topRight: Radius.circular(30), 77 | ), 78 | ), 79 | child: TodoDescription( 80 | todo: todo, 81 | textFontSize: 82 | // for iphone 7 - Height 621 83 | constraints.maxHeight == 621 84 | ? 18.h 85 | : 86 | // for iphone 5S - Height 522 87 | constraints.maxHeight == 522 88 | ? 16.h 89 | : 14.h, 90 | ), 91 | ), 92 | ), 93 | ], 94 | ), 95 | ); 96 | }, 97 | ), 98 | ); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | todo_app 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 108 | 109 | -------------------------------------------------------------------------------- /lib/translations/codegen_loader.g.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:easy_localization/generate.dart 2 | 3 | // ignore_for_file: prefer_single_quotes 4 | 5 | import 'dart:ui'; 6 | 7 | import 'package:easy_localization/easy_localization.dart' show AssetLoader; 8 | 9 | class CodegenLoader extends AssetLoader{ 10 | const CodegenLoader(); 11 | 12 | @override 13 | Future> load(String fullPath, Locale locale ) { 14 | return Future.value(mapLocales[locale.toString()]); 15 | } 16 | 17 | static const Map tr = { 18 | "homescreen": { 19 | "hello_text": "Merhaba", 20 | "subtitle_text": "Bu hafta iş yaşam dengeniz nasıl?", 21 | "goodjob_text": "İyi iş {}!", 22 | "goodjob_subtitle_text": "Hayatınız gayet dengeli", 23 | "taskstitle": "İşleriniz", 24 | "taskssubtitle": "{} tarihi için {} işiniz var" 25 | }, 26 | "dashboard": { 27 | "tasktitle": "İşleriniz", 28 | "taskssubtitle": "Toplamda {} tane iş bitirmişsiniz", 29 | "alertdialog": { 30 | "title": "Emin misiniz?", 31 | "subtitle": "Tamamlanmış tüm işleriniz silinecek. Bunun farkındasınız değil mi?", 32 | "delete": "Tamamlanmış tüm işleri sil!", 33 | "cancel": "Vazgeç" 34 | }, 35 | "title": "Panel" 36 | }, 37 | "profile": { 38 | "completed_text": "Tamamlanmış", 39 | "uncompleted_text": "Tamamlanmamış", 40 | "alltasks_text": "Tüm İşleriniz", 41 | "title": "Profil", 42 | "stats": "İstatistik" 43 | }, 44 | "changename": { 45 | "name_tf": "İsim", 46 | "surname_tf": "Soyad", 47 | "title": "İsminizi Değiştirin", 48 | "cancel_btn": "Vazgeç", 49 | "done_btn": "Değiştir" 50 | }, 51 | "addtodo": { 52 | "title": "İş Ekle", 53 | "title_tf": "Başlık", 54 | "desc_tf": "Açıklama", 55 | "category_tf": "Kategori", 56 | "date": "Tarih Seçin\nVarsayılan Tarih: {}", 57 | "time": "Saat Seçin\nVarsayılan Saat: {}", 58 | "add_btn": "İş Ekle", 59 | "cancel_btn": "Vazgeç", 60 | "selected": "Seçilen {}", 61 | "error_text": "Lütfen {} giriniz" 62 | }, 63 | "edittodo": { 64 | "title": "İşi Düzenle", 65 | "title_tf": "Başlık", 66 | "category_tf": "Kategori", 67 | "desc_tf": "Açıklama", 68 | "selecteddate": "Seçilen Tarih : {}", 69 | "selectedtime": "Seçilen Saat : {}", 70 | "default_date": "İşin Tarihi : {}", 71 | "default_time": "İşin Saati : {}", 72 | "edit_btn": "Düzenlemeyi bitir", 73 | "close_btn": "Kapat" 74 | }, 75 | "welcomescreen": { 76 | "title": "Hoşgeldin", 77 | "subtitle": "Size hitap etmek için lütfen adınızı ve soyadınızı belirtin", 78 | "done_button": "Tamam", 79 | "name_tf": "İsim", 80 | "surname_tf": "Soyad" 81 | } 82 | }; 83 | static const Map en = { 84 | "homescreen": { 85 | "hello_text": "Hello", 86 | "subtitle_text": "How is your work life balance this week?", 87 | "goodjob_text": "Good Job {}!", 88 | "goodjob_subtitle_text": "Your life is well-balanced", 89 | "taskstitle": "Your tasks", 90 | "taskssubtitle": "You have {} tasks for {}" 91 | }, 92 | "dashboard": { 93 | "tasktitle": "Your tasks", 94 | "taskssubtitle": "You have {} tasks completed all time", 95 | "alertdialog": { 96 | "title": "Are you sure?", 97 | "subtitle": "You do realize that all todos you complete will be deleted, right?", 98 | "delete": "Delete completed todos!", 99 | "cancel": "Cancel" 100 | }, 101 | "title": "Dashboard" 102 | }, 103 | "profile": { 104 | "completed_text": "Completed", 105 | "uncompleted_text": "Uncomplete", 106 | "alltasks_text": "All Tasks", 107 | "title": "Profile", 108 | "stats": "Statistics" 109 | }, 110 | "changename": { 111 | "name_tf": "Name", 112 | "surname_tf": "Surname", 113 | "title": "Change Name", 114 | "cancel_btn": "Cancel", 115 | "done_btn": "Done" 116 | }, 117 | "addtodo": { 118 | "title": "Add Todo", 119 | "title_tf": "Title", 120 | "desc_tf": "Description", 121 | "category_tf": "Category", 122 | "date": "Select Date\nDefault Date: {}", 123 | "time": "Select Time\nDefault Time : {}", 124 | "add_btn": "Add Todo", 125 | "cancel_btn": "Cancel", 126 | "selected": "Selected {}", 127 | "error_text": "Please enter {}" 128 | }, 129 | "edittodo": { 130 | "title": "Edit Task", 131 | "title_tf": "Title", 132 | "category_tf": "Category", 133 | "desc_tf": "Description", 134 | "selecteddate": "Selected Date : {}", 135 | "selectedtime": "Selected Time : {}", 136 | "default_date": "Task Date : {}", 137 | "default_time": "Task Time : {}", 138 | "edit_btn": "Finish editing", 139 | "close_btn": "Close" 140 | }, 141 | "welcomescreen": { 142 | "title": "Welcome", 143 | "subtitle": "Please provide your name and surname to address you", 144 | "done_button": "Done", 145 | "name_tf": "Name", 146 | "surname_tf": "Surname" 147 | } 148 | }; 149 | static const Map> mapLocales = {"tr": tr, "en": en}; 150 | } 151 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: todo_app 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+6 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | # Dependencies specify other packages that your package needs in order to work. 24 | # To automatically upgrade your package dependencies to the latest versions 25 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 26 | # dependencies can be manually updated by changing the version numbers below to 27 | # the latest version available on pub.dev. To see which dependencies have newer 28 | # versions available, run `flutter pub outdated`. 29 | dependencies: 30 | flutter: 31 | sdk: flutter 32 | 33 | 34 | # The following adds the Cupertino Icons font to your application. 35 | # Use with the CupertinoIcons class for iOS style icons. 36 | cupertino_icons: ^1.0.2 37 | hexcolor: ^2.0.5 38 | percent_indicator: ^3.4.0 39 | font_awesome_flutter: ^9.2.0 40 | auto_size_text: ^3.0.0 41 | shared_preferences: ^2.0.11 42 | provider: ^6.0.2 43 | flutter_slidable: ^1.2.0 44 | fluttertoast: ^8.0.8 45 | modal_bottom_sheet: ^2.0.0 46 | table_calendar: ^3.0.4 47 | cupertino_list_tile: ^0.2.1 48 | flutter_native_splash: ^2.1.1 49 | flutter_screenutil: ^5.3.1 50 | flutter_svg: ^1.0.3 51 | responsive_framework: ^0.1.7 52 | image_picker: ^0.8.4+11 53 | adaptive_dialog: ^1.4.0 54 | easy_localization: ^3.0.0 55 | flutter_app_badger: ^1.4.0 56 | in_app_review: ^2.0.4 57 | 58 | dev_dependencies: 59 | flutter_test: 60 | sdk: flutter 61 | flutter_launcher_icons: ^0.9.2 62 | flutter_lints: ^1.0.4 63 | 64 | flutter_native_splash: 65 | color: "#ffffff" 66 | image: "lib/img/logo_350.png" 67 | android: true 68 | ios: true 69 | 70 | flutter_lints: ^1.0.4 71 | 72 | flutter_icons: 73 | image_path: "app_icons/appiconios.png" 74 | android: true 75 | ios: true 76 | 77 | 78 | 79 | # The "flutter_lints" package below contains a set of recommended lints to 80 | # encourage good coding practices. The lint set provided by the package is 81 | # activated in the `analysis_options.yaml` file located at the root of your 82 | # package. See that file for information about deactivating specific lint 83 | # rules and activating additional ones. 84 | flutter_lints: ^1.0.0 85 | 86 | # For information on the generic Dart part of this file, see the 87 | # following page: https://dart.dev/tools/pub/pubspec 88 | 89 | # The following section is specific to Flutter. 90 | flutter: 91 | 92 | # The following line ensures that the Material Icons font is 93 | # included with your application, so that you can use the icons in 94 | # the material Icons class. 95 | uses-material-design: true 96 | 97 | # To add assets to your application, add an assets section, like this: 98 | assets: 99 | - lib/img/star_img.png 100 | - lib/img/todoImage.jpg 101 | - lib/img/placeholder.jpg 102 | - lib/img/logo_350.png 103 | - lib/img/businessman-min.png 104 | - lib/img/cnameicon.svg 105 | - lib/img/editicon.svg 106 | - lib/langs/ 107 | # - images/a_dot_ham.jpeg 108 | 109 | # An image asset can refer to one or more resolution-specific "variants", see 110 | # https://flutter.dev/assets-and-images/#resolution-aware. 111 | 112 | # For details regarding adding assets from package dependencies, see 113 | # https://flutter.dev/assets-and-images/#from-packages 114 | 115 | # To add custom fonts to your application, add a fonts section here, 116 | # in this "flutter" section. Each entry in this list should have a 117 | # "family" key with the font family name, and a "fonts" key with a 118 | # list giving the asset and other descriptors for the font. For 119 | # example: 120 | # fonts: 121 | # - family: Schyler 122 | # fonts: 123 | # - asset: fonts/Schyler-Regular.ttf 124 | # - asset: fonts/Schyler-Italic.ttf 125 | # style: italic 126 | # - family: Trajan Pro 127 | # fonts: 128 | # - asset: fonts/TrajanPro.ttf 129 | # - asset: fonts/TrajanPro_Bold.ttf 130 | # weight: 700 131 | # 132 | # For details regarding fonts from package dependencies, 133 | # see https://flutter.dev/custom-fonts/#from-packages 134 | -------------------------------------------------------------------------------- /lib/Widgets/HomePage/Tasks/task_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:todo_app/provider/todos_provider.dart'; 5 | import 'package:todo_app/translations/locale_keys.g.dart'; 6 | 7 | class TaskInfo extends StatefulWidget { 8 | const TaskInfo({Key? key}) : super(key: key); 9 | 10 | @override 11 | _Task_InfoState createState() => _Task_InfoState(); 12 | } 13 | 14 | // ignore: camel_case_types 15 | class _Task_InfoState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | List monthsENNames = [ 19 | '0 index data', 20 | 'January', 21 | 'February', 22 | 'March', 23 | 'April', 24 | 'May', 25 | 'June', 26 | 'July', 27 | 'August', 28 | 'September', 29 | 'October', 30 | 'November', 31 | 'December', 32 | ]; 33 | List monthsTRNames = [ 34 | '0 index data', 35 | 'Ocak', 36 | 'Şubat', 37 | 'Mart', 38 | 'Nisan', 39 | 'Mayıs', 40 | 'Haziran', 41 | 'Temmuz', 42 | 'Ağustos', 43 | 'Eylül', 44 | 'Ekim', 45 | 'Kasım', 46 | 'Aralık', 47 | ]; 48 | return Padding( 49 | padding: const EdgeInsets.only(left: 10, right: 20, top: 15), 50 | child: Row( 51 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 52 | children: [ 53 | Padding( 54 | padding: const EdgeInsets.only(left: 20.0), 55 | child: Column( 56 | crossAxisAlignment: CrossAxisAlignment.start, 57 | children: [ 58 | Text( 59 | LocaleKeys.homescreen_taskstitle.tr(), 60 | style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), 61 | ), 62 | Padding( 63 | padding: const EdgeInsets.only(top: 5.0), 64 | child: Consumer( 65 | builder: (context, state, child) => Text( 66 | context.locale == Locale('en') 67 | ? LocaleKeys.homescreen_taskssubtitle.tr(args: [ 68 | '${state.unCompletedTodos.where((Todo) { 69 | return DateTime.fromMillisecondsSinceEpoch( 70 | Todo.dateMilliseconds) 71 | .day == 72 | DateTime.now().day && 73 | DateTime.fromMillisecondsSinceEpoch( 74 | Todo.dateMilliseconds) 75 | .month == 76 | DateTime.now().month && 77 | DateTime.fromMillisecondsSinceEpoch( 78 | Todo.dateMilliseconds) 79 | .year == 80 | DateTime.now().year; 81 | }).length}', 82 | '${DateTime.now().day.toString().padLeft(2, '0')} ${monthsENNames[DateTime.now().month]}' 83 | ]) 84 | : LocaleKeys.homescreen_taskssubtitle.tr(args: [ 85 | '${DateTime.now().day.toString().padLeft(2, '0')} ${monthsTRNames[DateTime.now().month]}', 86 | '${state.unCompletedTodos.where((Todo) { 87 | return DateTime.fromMillisecondsSinceEpoch( 88 | Todo.dateMilliseconds) 89 | .day == 90 | DateTime.now().day && 91 | DateTime.fromMillisecondsSinceEpoch( 92 | Todo.dateMilliseconds) 93 | .month == 94 | DateTime.now().month && 95 | DateTime.fromMillisecondsSinceEpoch( 96 | Todo.dateMilliseconds) 97 | .year == 98 | DateTime.now().year; 99 | }).length}' 100 | ]), 101 | style: const TextStyle( 102 | fontSize: 14, 103 | fontWeight: FontWeight.bold, 104 | color: Colors.grey), 105 | ), 106 | )) 107 | ], 108 | ), 109 | ), 110 | Padding( 111 | padding: const EdgeInsets.only(right: 15.0), 112 | child: Container( 113 | width: 40, 114 | height: 40, 115 | decoration: const BoxDecoration( 116 | color: Colors.white, 117 | borderRadius: BorderRadius.all(Radius.circular(14))), 118 | child: const Icon(Icons.calendar_today), 119 | ), 120 | ), 121 | ], 122 | ), 123 | ); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /lib/Pages/change_name_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:todo_app/Widgets/Welcome/welcome_tf.dart'; 5 | import 'package:todo_app/provider/todos_provider.dart'; 6 | import 'package:todo_app/translations/locale_keys.g.dart'; 7 | 8 | import '../Widgets/ChangeName/change_name_text.dart'; 9 | 10 | class ChangeNameScreen extends StatefulWidget { 11 | const ChangeNameScreen({Key? key}) : super(key: key); 12 | 13 | @override 14 | _ChangeNameScreenState createState() => _ChangeNameScreenState(); 15 | } 16 | 17 | class _ChangeNameScreenState extends State { 18 | var nameController = TextEditingController(); 19 | var surnameController = TextEditingController(); 20 | // ignore: prefer_typing_uninitialized_variables 21 | late final formKey; 22 | @override 23 | void initState() { 24 | super.initState(); 25 | Provider.of(context, listen: false).initSharedPreferences(); 26 | formKey = GlobalKey(); 27 | } 28 | 29 | @override 30 | void dispose() { 31 | nameController.dispose(); 32 | surnameController.dispose(); 33 | super.dispose(); 34 | } 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | return Scaffold( 39 | //resizeToAvoidBottomInset: false, 40 | body: SingleChildScrollView( 41 | scrollDirection: Axis.vertical, 42 | reverse: true, 43 | child: Column( 44 | crossAxisAlignment: CrossAxisAlignment.end, 45 | children: [ 46 | const Center(child: ChangeNameText()), 47 | Form( 48 | key: formKey, 49 | child: Padding( 50 | padding: 51 | const EdgeInsets.only(left: 15.0, right: 15, bottom: 10), 52 | child: Column(children: [ 53 | WelcomCustomTF( 54 | controller: nameController, 55 | labelText: LocaleKeys.changename_name_tf.tr()), 56 | WelcomCustomTF( 57 | controller: surnameController, 58 | labelText: LocaleKeys.changename_surname_tf.tr()), 59 | ]), 60 | ), 61 | ), 62 | Center( 63 | child: Column( 64 | children: [ 65 | Consumer( 66 | builder: (context, state, child) => Padding( 67 | padding: const EdgeInsets.only(top: 20.0), 68 | child: SizedBox( 69 | height: MediaQuery.of(context).size.height / 13, 70 | width: MediaQuery.of(context).size.width / 1.2, 71 | child: ElevatedButton( 72 | style: ButtonStyle( 73 | backgroundColor: 74 | MaterialStateProperty.all( 75 | Colors.amber.shade600), 76 | shape: MaterialStateProperty.all< 77 | RoundedRectangleBorder>( 78 | RoundedRectangleBorder( 79 | borderRadius: BorderRadius.circular(13.0), 80 | )), 81 | ), 82 | onPressed: () { 83 | bool validResult = 84 | formKey.currentState!.validate(); 85 | if (validResult == true) { 86 | state.setName(nameController.text); 87 | state.setsurName(surnameController.text); 88 | Navigator.of(context).pop(); 89 | } 90 | }, 91 | child: Text(LocaleKeys.changename_done_btn.tr())), 92 | ), 93 | ), 94 | ), 95 | SizedBox( 96 | height: 10, 97 | ), 98 | SizedBox( 99 | height: MediaQuery.of(context).size.height / 13, 100 | width: MediaQuery.of(context).size.width / 1.2, 101 | child: ElevatedButton( 102 | style: ButtonStyle( 103 | backgroundColor: 104 | MaterialStateProperty.all(Colors.white), 105 | shape: 106 | MaterialStateProperty.all( 107 | RoundedRectangleBorder( 108 | side: BorderSide(color: Colors.amber, width: 3), 109 | borderRadius: BorderRadius.circular(13.0), 110 | ), 111 | ), 112 | ), 113 | onPressed: () { 114 | Navigator.of(context).pop(); 115 | }, 116 | child: Text( 117 | LocaleKeys.changename_cancel_btn.tr(), 118 | style: TextStyle( 119 | color: Colors.amber, fontWeight: FontWeight.bold), 120 | ), 121 | ), 122 | ) 123 | ], 124 | ), 125 | ), 126 | ], 127 | )), 128 | ); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /lib/Widgets/Dashboard/complete_todo_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_slidable/flutter_slidable.dart'; 3 | import 'package:fluttertoast/fluttertoast.dart'; 4 | import 'package:hexcolor/hexcolor.dart'; 5 | import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 6 | import 'package:provider/provider.dart'; 7 | import 'package:todo_app/Models/todo.dart'; 8 | import 'package:todo_app/Pages/detail_screen.dart'; 9 | import 'package:todo_app/provider/todos_provider.dart'; 10 | 11 | class CompleteTodoCard extends StatelessWidget { 12 | // ignore: use_key_in_widget_constructors 13 | const CompleteTodoCard({required this.todo}); 14 | 15 | final Todo todo; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return GestureDetector( 20 | onTap: () { 21 | Future(() { 22 | showBarModalBottomSheet( 23 | context: context, 24 | builder: (context) => DetailScreen( 25 | todo: todo, 26 | )); 27 | }); 28 | }, 29 | child: Container( 30 | padding: const EdgeInsets.all(10), 31 | child: Slidable( 32 | key: UniqueKey(), 33 | startActionPane: ActionPane( 34 | motion: const ScrollMotion(), 35 | dismissible: DismissiblePane( 36 | onDismissed: () { 37 | Provider.of(context, listen: false) 38 | .toggleTodo(todo); 39 | Fluttertoast.showToast( 40 | msg: "Uncompleted!!", 41 | toastLength: Toast.LENGTH_SHORT, 42 | gravity: ToastGravity.BOTTOM, 43 | timeInSecForIosWeb: 1, 44 | backgroundColor: Colors.green, 45 | textColor: Colors.white, 46 | fontSize: 16.0); 47 | }, 48 | ), 49 | children: [ 50 | SlidableAction( 51 | onPressed: (BuildContext context) { 52 | Provider.of(context, listen: false) 53 | .toggleTodo(todo); 54 | Fluttertoast.showToast( 55 | msg: "Uncompleted!!", 56 | toastLength: Toast.LENGTH_SHORT, 57 | gravity: ToastGravity.BOTTOM, 58 | timeInSecForIosWeb: 1, 59 | backgroundColor: Colors.green, 60 | textColor: Colors.white, 61 | fontSize: 16.0); 62 | }, 63 | backgroundColor: Colors.green, 64 | label: 'UnComplete!', 65 | ) 66 | ], 67 | ), 68 | endActionPane: ActionPane( 69 | motion: const ScrollMotion(), 70 | dismissible: DismissiblePane( 71 | onDismissed: () { 72 | Provider.of(context, listen: false) 73 | .removeTodo(todo); 74 | Fluttertoast.showToast( 75 | msg: "Removed!", 76 | toastLength: Toast.LENGTH_SHORT, 77 | gravity: ToastGravity.BOTTOM, 78 | timeInSecForIosWeb: 1, 79 | backgroundColor: Colors.red, 80 | textColor: Colors.white, 81 | fontSize: 16.0); 82 | }, 83 | ), 84 | children: [ 85 | SlidableAction( 86 | onPressed: (BuildContext context) { 87 | Provider.of(context, listen: false) 88 | .removeTodo(todo); 89 | Fluttertoast.showToast( 90 | msg: "Removed!", 91 | toastLength: Toast.LENGTH_SHORT, 92 | gravity: ToastGravity.BOTTOM, 93 | timeInSecForIosWeb: 1, 94 | backgroundColor: Colors.red, 95 | textColor: Colors.white, 96 | fontSize: 16.0); 97 | }, 98 | backgroundColor: Colors.red, 99 | label: 'Remove!', 100 | ) 101 | ], 102 | ), 103 | child: Card( 104 | shadowColor: Colors.transparent, 105 | color: Colors.white, 106 | elevation: 20, 107 | shape: const RoundedRectangleBorder( 108 | borderRadius: BorderRadius.all(Radius.circular(20)), 109 | ), 110 | child: Column( 111 | crossAxisAlignment: CrossAxisAlignment.start, 112 | children: [ 113 | Row(children: [ 114 | Padding( 115 | padding: const EdgeInsets.all(18.0), 116 | child: SizedBox( 117 | child: Transform.scale( 118 | scale: 1.4, 119 | child: Checkbox( 120 | shape: const CircleBorder(), 121 | checkColor: Colors.white, 122 | activeColor: Colors.black, 123 | value: todo.complete, 124 | onChanged: (bool? value) { 125 | Provider.of(context, listen: false) 126 | .toggleTodo(todo); 127 | }, 128 | ), 129 | ), 130 | ), 131 | ), 132 | Column( 133 | crossAxisAlignment: CrossAxisAlignment.start, 134 | children: [ 135 | categoryText(todo.category), 136 | titleText(todo.title), 137 | ], 138 | ) 139 | ]), 140 | ], 141 | ), 142 | ), 143 | ), 144 | ), 145 | ); 146 | } 147 | } 148 | 149 | Widget categoryText(String categoryName) { 150 | return Container( 151 | height: 18, 152 | decoration: BoxDecoration( 153 | borderRadius: BorderRadius.circular(20.0), 154 | color: HexColor('#d3e3f2'), 155 | ), 156 | child: Padding( 157 | padding: const EdgeInsets.only(left: 10, right: 10), 158 | child: Center( 159 | child: Text( 160 | categoryName, 161 | style: const TextStyle( 162 | color: Colors.blue, fontWeight: FontWeight.bold, fontSize: 10), 163 | )), 164 | ), 165 | ); 166 | } 167 | 168 | Widget titleText(String titleName) { 169 | return Padding( 170 | padding: const EdgeInsets.only(top: 10.0), 171 | child: Center( 172 | child: Text( 173 | titleName, 174 | style: const TextStyle( 175 | color: Colors.black, fontWeight: FontWeight.bold, fontSize: 15), 176 | )), 177 | ); 178 | } 179 | -------------------------------------------------------------------------------- /lib/Widgets/Todo/todo_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_slidable/flutter_slidable.dart'; 3 | import 'package:fluttertoast/fluttertoast.dart'; 4 | import 'package:hexcolor/hexcolor.dart'; 5 | import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 6 | import 'package:provider/provider.dart'; 7 | import 'package:todo_app/Models/todo.dart'; 8 | import 'package:todo_app/Pages/detail_screen.dart'; 9 | import 'package:todo_app/provider/todos_provider.dart'; 10 | 11 | class TodoCard extends StatelessWidget { 12 | const TodoCard({required this.todo, String? key}); 13 | 14 | final Todo todo; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return GestureDetector( 19 | onTap: () { 20 | Future(() { 21 | showBarModalBottomSheet( 22 | context: context, 23 | builder: (context) => DetailScreen( 24 | todo: todo, 25 | )); 26 | }); 27 | }, 28 | child: Container( 29 | padding: const EdgeInsets.all(8), 30 | child: Slidable( 31 | key: UniqueKey(), 32 | startActionPane: ActionPane( 33 | motion: const ScrollMotion(), 34 | dismissible: DismissiblePane( 35 | onDismissed: () { 36 | Provider.of(context, listen: false) 37 | .toggleTodo(todo); 38 | Fluttertoast.showToast( 39 | msg: "Done!", 40 | toastLength: Toast.LENGTH_SHORT, 41 | gravity: ToastGravity.BOTTOM, 42 | timeInSecForIosWeb: 1, 43 | backgroundColor: Colors.green, 44 | textColor: Colors.white, 45 | fontSize: 16.0); 46 | }, 47 | ), 48 | children: [ 49 | SlidableAction( 50 | onPressed: (BuildContext context) { 51 | Provider.of(context, listen: false) 52 | .toggleTodo(todo); 53 | Fluttertoast.showToast( 54 | msg: "Done!", 55 | toastLength: Toast.LENGTH_SHORT, 56 | gravity: ToastGravity.BOTTOM, 57 | timeInSecForIosWeb: 1, 58 | backgroundColor: Colors.green, 59 | textColor: Colors.white, 60 | fontSize: 16.0); 61 | }, 62 | backgroundColor: Colors.green, 63 | label: 'Done!', 64 | ) 65 | ], 66 | ), 67 | endActionPane: ActionPane( 68 | motion: const ScrollMotion(), 69 | dismissible: DismissiblePane( 70 | onDismissed: () { 71 | Provider.of(context, listen: false) 72 | .removeTodo(todo); 73 | Fluttertoast.showToast( 74 | msg: "Uncompleted!!", 75 | toastLength: Toast.LENGTH_SHORT, 76 | gravity: ToastGravity.BOTTOM, 77 | timeInSecForIosWeb: 1, 78 | backgroundColor: Colors.red, 79 | textColor: Colors.white, 80 | fontSize: 16.0); 81 | }, 82 | ), 83 | children: [ 84 | SlidableAction( 85 | onPressed: (BuildContext context) { 86 | Provider.of(context, listen: false) 87 | .removeTodo(todo); 88 | Fluttertoast.showToast( 89 | msg: "Removed!", 90 | toastLength: Toast.LENGTH_SHORT, 91 | gravity: ToastGravity.BOTTOM, 92 | timeInSecForIosWeb: 1, 93 | backgroundColor: Colors.red, 94 | textColor: Colors.white, 95 | fontSize: 16.0); 96 | }, 97 | backgroundColor: Colors.red, 98 | label: 'Remove!', 99 | ) 100 | ], 101 | ), 102 | child: Card( 103 | shadowColor: Colors.transparent, 104 | color: Colors.white, 105 | elevation: 20, 106 | shape: const RoundedRectangleBorder( 107 | borderRadius: BorderRadius.all(Radius.circular(20)), 108 | ), 109 | child: Column( 110 | crossAxisAlignment: CrossAxisAlignment.start, 111 | children: [ 112 | Row(children: [ 113 | Padding( 114 | padding: const EdgeInsets.all(18.0), 115 | child: SizedBox( 116 | child: Transform.scale( 117 | scale: 1.4, 118 | child: Checkbox( 119 | shape: const CircleBorder(), 120 | checkColor: Colors.white, 121 | activeColor: Colors.black, 122 | value: todo.complete, 123 | onChanged: (bool? value) { 124 | Provider.of(context, listen: false) 125 | .toggleTodo(todo); 126 | Fluttertoast.showToast( 127 | msg: "Done!", 128 | toastLength: Toast.LENGTH_SHORT, 129 | gravity: ToastGravity.BOTTOM, 130 | timeInSecForIosWeb: 1, 131 | backgroundColor: Colors.green, 132 | textColor: Colors.white, 133 | fontSize: 16.0); 134 | }, 135 | ), 136 | ), 137 | ), 138 | ), 139 | Column( 140 | crossAxisAlignment: CrossAxisAlignment.start, 141 | children: [ 142 | categoryText(todo.category), 143 | titleText(todo.title), 144 | ], 145 | ) 146 | ]), 147 | ], 148 | ), 149 | ), 150 | ), 151 | ), 152 | ); 153 | } 154 | } 155 | 156 | Widget categoryText(String categoryName) { 157 | return Container( 158 | height: 18, 159 | decoration: BoxDecoration( 160 | borderRadius: BorderRadius.circular(20.0), 161 | color: HexColor('#d3e3f2'), 162 | ), 163 | child: Padding( 164 | padding: const EdgeInsets.only(left: 10, right: 10), 165 | child: Center( 166 | child: Text( 167 | categoryName, 168 | style: const TextStyle( 169 | color: Colors.blue, fontWeight: FontWeight.bold, fontSize: 10), 170 | )), 171 | ), 172 | ); 173 | } 174 | 175 | Widget titleText(String titleName) { 176 | return Padding( 177 | padding: const EdgeInsets.only(top: 10.0), 178 | child: Center( 179 | child: Text( 180 | titleName, 181 | maxLines: 2, 182 | overflow: TextOverflow.fade, 183 | style: const TextStyle( 184 | color: Colors.black, fontWeight: FontWeight.bold, fontSize: 15), 185 | )), 186 | ); 187 | } 188 | -------------------------------------------------------------------------------- /lib/provider/todos_provider.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | import 'dart:convert'; 3 | import 'dart:typed_data'; 4 | 5 | import 'package:adaptive_dialog/adaptive_dialog.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:image_picker/image_picker.dart'; 8 | import 'package:shared_preferences/shared_preferences.dart'; 9 | import 'package:todo_app/Models/todo.dart'; 10 | import 'package:todo_app/provider/shared_prefences_helper.dart'; 11 | 12 | class TodosProvider extends ChangeNotifier { 13 | SharedPreferences? sharedPreferences; 14 | String _name = ''; 15 | String _surname = ''; 16 | String imageKey = "IMAGE_KEY"; 17 | Uint8List? imagebytes; 18 | Uint8List? profileImage; 19 | 20 | //initial state 21 | List todos = []; 22 | 23 | List todosList = []; 24 | 25 | List completedTodosList = []; 26 | 27 | List getTodos(DateTime day) { 28 | todosList = unCompletedTodos.where((Todo) { 29 | return DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds).day == 30 | day.day && 31 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds).month == 32 | day.month && 33 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds).year == 34 | day.year; 35 | }).toList(); 36 | return todosList; 37 | } 38 | 39 | // getter 40 | String get name => _name; 41 | String get surname => _surname; 42 | UnmodifiableListView get allTodos => 43 | UnmodifiableListView(todos.reversed); 44 | 45 | UnmodifiableListView get completedTodos => 46 | UnmodifiableListView(todos.reversed.where((todo) => todo.complete)); 47 | 48 | UnmodifiableListView get unCompletedTodos => 49 | UnmodifiableListView(todos.reversed.where((todo) => !todo.complete)); 50 | 51 | // methods for To-do 52 | void addTodo(Todo todo) { 53 | todos.add(todo); 54 | saveDataToLocalStorage(); 55 | notifyListeners(); 56 | } 57 | 58 | void removeTodo(Todo todo) { 59 | todos.remove(todo); 60 | updateDataToLocalStorage(); 61 | checkCompletedTodos(); 62 | notifyListeners(); 63 | } 64 | 65 | void toggleTodo(Todo todo) { 66 | var index = todos.indexOf(todo); 67 | todos[index].toggleCompleted(); 68 | updateDataToLocalStorage(); 69 | notifyListeners(); 70 | } 71 | 72 | void editTodo(Todo todo, String titleText, String description, 73 | String category, int dateMilliseconds, int timeMilliseconds) { 74 | todo.title = titleText; 75 | todo.description = description; 76 | todo.category = category; 77 | todo.dateMilliseconds = dateMilliseconds; 78 | todo.timeMilliseconds = timeMilliseconds; 79 | updateDataToLocalStorage(); 80 | notifyListeners(); 81 | } 82 | 83 | // For delete completed todos 84 | bool checkCompletedTodos() { 85 | if (completedTodos.isEmpty) { 86 | notifyListeners(); 87 | return true; 88 | } 89 | notifyListeners(); 90 | return false; 91 | } 92 | 93 | void removeCompletedTodos() { 94 | todos.forEach((todo) { 95 | if (todo.complete) { 96 | completedTodosList.add(todo); 97 | notifyListeners(); 98 | } 99 | }); 100 | todos.removeWhere((todo) => completedTodosList.contains(todo)); 101 | updateDataToLocalStorage(); 102 | notifyListeners(); 103 | } 104 | 105 | // methods for shared preferences 106 | void initSharedPreferences() async { 107 | // sharedPreferences = await SharedPreferences.getInstance(); 108 | await SharedPreferencesHelper.init(); 109 | sharedPreferences = SharedPreferencesHelper.instance; 110 | loadDataFromLocalStorage(); 111 | getName(); 112 | getSurname(); 113 | notifyListeners(); 114 | } 115 | 116 | void saveDataToLocalStorage() { 117 | List? spList = 118 | todos.map((todo) => json.encode(todo.toJson())).toList(); 119 | sharedPreferences!.setStringList('list', spList); 120 | } 121 | 122 | void loadDataFromLocalStorage() { 123 | List? spList = sharedPreferences!.getStringList('list'); 124 | if (spList != null) { 125 | todos = spList.map((item) => Todo.fromMap(json.decode(item))).toList(); 126 | } 127 | } 128 | 129 | void updateDataToLocalStorage() { 130 | List? spList = 131 | todos.map((item) => json.encode(item.toJson())).toList(); 132 | sharedPreferences?.remove('list'); 133 | sharedPreferences!.setStringList('list', spList); 134 | } 135 | 136 | void saveName(String userText) { 137 | _name = userText; 138 | sharedPreferences!.setString('userName', userText); 139 | notifyListeners(); 140 | } 141 | 142 | void savesurname(String userText) { 143 | _surname = userText; 144 | sharedPreferences!.setString('userSurname', userText); 145 | notifyListeners(); 146 | } 147 | 148 | // To-do Percent Method 149 | double calcTodoPercent(DateTime day) { 150 | double percent = (completedTodos 151 | .where((Todo) => 152 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds) 153 | .day == 154 | DateTime.now().day) 155 | .length / 156 | allTodos 157 | .where((Todo) => 158 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds) 159 | .day == 160 | DateTime.now().day) 161 | .length); 162 | return (completedTodos == 0 && unCompletedTodos == 0) ? 0 : percent; 163 | } 164 | 165 | // Name and Surname Methods 166 | void setName(String userText) { 167 | if (userText.isEmpty) { 168 | } else { 169 | saveName(userText); 170 | notifyListeners(); 171 | } 172 | } 173 | 174 | void setsurName(String userText) { 175 | if (userText.isEmpty) { 176 | } else { 177 | savesurname(userText); 178 | notifyListeners(); 179 | } 180 | } 181 | 182 | String? getName() { 183 | String? spName = sharedPreferences?.getString('userName'); 184 | if (spName != null) { 185 | _name = spName; 186 | notifyListeners(); 187 | return spName; 188 | } else { 189 | return null; 190 | } 191 | } 192 | 193 | void getSurname() { 194 | String? spName = sharedPreferences!.getString('userSurname'); 195 | if (spName != null) { 196 | _surname = spName; 197 | notifyListeners(); 198 | } else {} 199 | } 200 | 201 | // Check Name 202 | Future readName(String key) async { 203 | final prefs = await SharedPreferences.getInstance(); 204 | dynamic obj = prefs.get(key); 205 | return obj; 206 | } 207 | 208 | // For profile picture 209 | Future pickImage(BuildContext context) async { 210 | XFile? image; 211 | try { 212 | image = await ImagePicker().pickImage(source: ImageSource.gallery); 213 | } catch (e) { 214 | showOkAlertDialog( 215 | context: context, 216 | title: 'Permission Error', 217 | message: 218 | 'You need to give permission to access the gallery in the settings.'); 219 | } 220 | 221 | if (image != null) { 222 | imagebytes = await image.readAsBytes(); 223 | imageToBase64(imagebytes!); 224 | notifyListeners(); 225 | base64ToImage(); 226 | notifyListeners(); 227 | } 228 | } 229 | 230 | void imageToBase64(Uint8List imageBytes) { 231 | sharedPreferences!.setString(imageKey, base64.encode(imageBytes)); 232 | notifyListeners(); 233 | } 234 | 235 | Uint8List? base64ToImage() { 236 | var data = sharedPreferences!.getString(imageKey); 237 | data == null ? null : profileImage = base64.decode(data); 238 | return profileImage; 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /lib/Pages/main_screen.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 5 | import 'package:hexcolor/hexcolor.dart'; 6 | import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 7 | import 'package:provider/provider.dart'; 8 | import 'package:todo_app/Pages/profile_page.dart'; 9 | import 'package:todo_app/provider/todos_provider.dart'; 10 | 11 | import '../Review/review_service.dart'; 12 | import 'add_todo.dart'; 13 | import 'calendar_page.dart'; 14 | import 'dashboard_page.dart'; 15 | import 'home_page.dart'; 16 | 17 | class MainScreen extends StatefulWidget { 18 | const MainScreen({Key? key}) : super(key: key); 19 | 20 | @override 21 | State createState() => _MainScreenState(); 22 | } 23 | 24 | class _MainScreenState extends State { 25 | //Variables 26 | int currentTab = 0; 27 | var pageList = [ 28 | const HomePage(), 29 | const CalendarPage(), 30 | const AddTodo(), 31 | const DashboardPage(), 32 | const ProfilePage() 33 | ]; 34 | 35 | late int badgeValue; 36 | final ReviewService _reviewService = ReviewService(); 37 | 38 | @override 39 | void initState() { 40 | super.initState(); 41 | Provider.of(context, listen: false).initSharedPreferences(); 42 | badgeValue = Provider.of(context, listen: false) 43 | .unCompletedTodos 44 | .where((Todo) { 45 | return DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds).day == 46 | DateTime.now().day && 47 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds).month == 48 | DateTime.now().month && 49 | DateTime.fromMillisecondsSinceEpoch(Todo.dateMilliseconds).year == 50 | DateTime.now().year; 51 | }).length; 52 | 53 | // App Review 54 | Timer(const Duration(seconds: 2), () { 55 | _reviewService.isSecondTimeOpen().then((secondOpen) { 56 | if (secondOpen) { 57 | _reviewService.showRating(); 58 | } 59 | }); 60 | }); 61 | } 62 | 63 | final PageStorageBucket bucket = PageStorageBucket(); 64 | Widget currentScreen = const HomePage(); 65 | 66 | @override 67 | Widget build(BuildContext context) { 68 | return LayoutBuilder(builder: (context, constraints) { 69 | return Scaffold( 70 | backgroundColor: HexColor('#f3f0e5'), 71 | body: PageStorage( 72 | child: currentScreen, 73 | bucket: bucket, 74 | ), 75 | floatingActionButton: SizedBox( 76 | height: 50, 77 | child: FloatingActionButton( 78 | backgroundColor: HexColor('#000000'), 79 | child: const Icon(Icons.add), 80 | onPressed: () { 81 | setState(() { 82 | showCupertinoModalBottomSheet( 83 | shape: RoundedRectangleBorder( 84 | borderRadius: BorderRadius.circular(100.0), 85 | ), 86 | context: context, 87 | builder: (context) => SizedBox( 88 | height: 89 | // for iphone 11 90 | constraints.maxHeight == 896 || 91 | constraints.maxHeight == 926 92 | ? MediaQuery.of(context).size.height / 1.45 93 | : 94 | // For iphone 11 pro, 12 mini, 12 pro 95 | constraints.maxHeight == 812 96 | ? MediaQuery.of(context).size.height / 1.35 97 | : 98 | // for iphone 12 99 | constraints.maxHeight == 844 100 | ? MediaQuery.of(context).size.height / 1.4 101 | : 102 | // for iphone 8 plus 103 | constraints.maxHeight == 736 104 | ? MediaQuery.of(context).size.height / 105 | 1.3 106 | : 107 | // for iphone 7 108 | constraints.maxHeight == 667 109 | ? MediaQuery.of(context) 110 | .size 111 | .height / 112 | 1.22 113 | : 114 | // for iphone 5S and iPhone SE 1. Gen 115 | constraints.maxHeight == 568 116 | ? MediaQuery.of(context) 117 | .size 118 | .height / 119 | 1.1 120 | : 121 | // For Pixel 2 - height 683.4285714285714 122 | constraints.maxHeight == 123 | 683.4285714285714 124 | ? MediaQuery.of(context) 125 | .size 126 | .height / 127 | 1.2 128 | : MediaQuery.of(context) 129 | .size 130 | .height / 131 | 1.4, 132 | child: const AddTodo()), 133 | ); 134 | currentTab = 5; 135 | }); 136 | }, 137 | ), 138 | ), 139 | floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, 140 | bottomNavigationBar: BottomAppBar( 141 | child: SizedBox( 142 | height: 50, 143 | child: Row( 144 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 145 | children: [ 146 | Row( 147 | crossAxisAlignment: CrossAxisAlignment.start, 148 | children: [ 149 | MaterialButton( 150 | minWidth: 40, 151 | onPressed: () { 152 | setState(() { 153 | currentScreen = const HomePage(); 154 | currentTab = 0; 155 | }); 156 | }, 157 | child: Column( 158 | mainAxisAlignment: MainAxisAlignment.center, 159 | children: [ 160 | FaIcon( 161 | FontAwesomeIcons.home, 162 | color: currentTab == 0 ? Colors.black : Colors.grey, 163 | ) 164 | ], 165 | ), 166 | ), 167 | Padding( 168 | padding: const EdgeInsets.only(left: 20.0), 169 | child: MaterialButton( 170 | minWidth: 40, 171 | onPressed: () { 172 | setState(() { 173 | currentScreen = const CalendarPage(); 174 | currentTab = 1; 175 | }); 176 | }, 177 | child: Column( 178 | mainAxisAlignment: MainAxisAlignment.center, 179 | children: [ 180 | FaIcon( 181 | FontAwesomeIcons.calendar, 182 | color: 183 | currentTab == 1 ? Colors.black : Colors.grey, 184 | ), 185 | ], 186 | ), 187 | ), 188 | ), 189 | ], 190 | ), 191 | // Right Tab Icons 192 | Row( 193 | crossAxisAlignment: CrossAxisAlignment.start, 194 | children: [ 195 | MaterialButton( 196 | minWidth: 40, 197 | onPressed: () { 198 | setState(() { 199 | currentScreen = const DashboardPage(); 200 | currentTab = 3; 201 | }); 202 | }, 203 | child: Column( 204 | mainAxisAlignment: MainAxisAlignment.center, 205 | children: [ 206 | FaIcon( 207 | FontAwesomeIcons.clipboardCheck, 208 | color: currentTab == 3 ? Colors.black : Colors.grey, 209 | ) 210 | ], 211 | ), 212 | ), 213 | Padding( 214 | padding: const EdgeInsets.only(left: 25.0), 215 | child: MaterialButton( 216 | minWidth: 40, 217 | onPressed: () { 218 | setState(() { 219 | currentScreen = const ProfilePage(); 220 | currentTab = 4; 221 | }); 222 | }, 223 | child: Column( 224 | mainAxisAlignment: MainAxisAlignment.center, 225 | children: [ 226 | FaIcon( 227 | FontAwesomeIcons.user, 228 | color: 229 | currentTab == 4 ? Colors.black : Colors.grey, 230 | ), 231 | ], 232 | ), 233 | ), 234 | ), 235 | ], 236 | ), 237 | ], 238 | ), 239 | ), 240 | ), 241 | ); 242 | }); 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /lib/Pages/edit_todo.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:fluttertoast/fluttertoast.dart'; 5 | import 'package:hexcolor/hexcolor.dart'; 6 | import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 7 | import 'package:provider/provider.dart'; 8 | import 'package:todo_app/Models/todo.dart'; 9 | import 'package:todo_app/Widgets/Todo/edit_tf.dart'; 10 | import 'package:todo_app/provider/todos_provider.dart'; 11 | import 'package:todo_app/translations/locale_keys.g.dart'; 12 | 13 | class EditTodo extends StatefulWidget { 14 | EditTodo({Key? key, required this.todo}) : super(key: key); 15 | Todo todo; 16 | 17 | @override 18 | _EditTodoState createState() => _EditTodoState(); 19 | } 20 | 21 | class _EditTodoState extends State { 22 | var formKey = GlobalKey(); 23 | TextEditingController? titleController; 24 | TextEditingController? descController; 25 | TextEditingController? categoryController; 26 | 27 | DateTime? _selectedDate; 28 | DateTime? _selectedTime; 29 | String dateTextValue = 30 | '${DateTime.now().day}:${DateTime.now().month.toString().padLeft(2, '0')}:${DateTime.now().year}'; 31 | 32 | var todoDate; 33 | var todoTime; 34 | 35 | @override 36 | void initState() { 37 | super.initState(); 38 | titleController = TextEditingController(text: widget.todo.title); 39 | descController = TextEditingController(text: widget.todo.description); 40 | categoryController = TextEditingController(text: widget.todo.category); 41 | 42 | todoDate = 43 | DateTime.fromMillisecondsSinceEpoch(widget.todo.dateMilliseconds); 44 | todoTime = 45 | DateTime.fromMillisecondsSinceEpoch(widget.todo.timeMilliseconds); 46 | } 47 | 48 | @override 49 | void dispose() { 50 | titleController?.dispose(); 51 | categoryController?.dispose(); 52 | descController?.dispose(); 53 | super.dispose(); 54 | } 55 | 56 | @override 57 | Widget build(BuildContext context) { 58 | return Scaffold( 59 | body: SingleChildScrollView( 60 | scrollDirection: Axis.vertical, 61 | reverse: true, 62 | child: Form( 63 | key: formKey, 64 | child: Center( 65 | child: Stack( 66 | alignment: Alignment.topRight, 67 | children: [ 68 | Column( 69 | mainAxisSize: MainAxisSize.min, 70 | children: [ 71 | Padding( 72 | padding: EdgeInsets.only(top: 100.0), 73 | child: Text( 74 | LocaleKeys.edittodo_title.tr(), 75 | style: TextStyle( 76 | fontSize: 20, fontWeight: FontWeight.bold), 77 | ), 78 | ), 79 | EditTF( 80 | hint: LocaleKeys.edittodo_title_tf.tr(), 81 | controller: titleController!, 82 | labelText: LocaleKeys.edittodo_title_tf.tr()), 83 | EditTF( 84 | hint: LocaleKeys.edittodo_desc_tf.tr(), 85 | controller: descController!, 86 | labelText: LocaleKeys.edittodo_desc_tf.tr()), 87 | EditTF( 88 | hint: LocaleKeys.edittodo_category_tf.tr(), 89 | controller: categoryController!, 90 | labelText: LocaleKeys.edittodo_category_tf.tr()), 91 | 92 | Row( 93 | children: [ 94 | // Cupertino DatwTime Picker 95 | const SizedBox( 96 | width: 20, 97 | ), 98 | Expanded( 99 | // DATE 100 | child: SizedBox( 101 | width: MediaQuery.of(context).size.width / 2.5, 102 | height: MediaQuery.of(context).size.height / 14, 103 | child: ElevatedButton( 104 | style: ButtonStyle( 105 | backgroundColor: 106 | MaterialStateProperty.all( 107 | Colors.amber.shade800), 108 | shape: MaterialStateProperty.all< 109 | RoundedRectangleBorder>( 110 | RoundedRectangleBorder( 111 | borderRadius: BorderRadius.circular(13.0), 112 | ), 113 | ), 114 | ), 115 | onPressed: () { 116 | showCupertinoModalBottomSheet( 117 | shape: RoundedRectangleBorder( 118 | borderRadius: BorderRadius.circular(10.0), 119 | ), 120 | context: context, 121 | builder: (context) => Container( 122 | color: HexColor('#f9f6e8'), 123 | height: 124 | MediaQuery.of(context).size.height / 125 | 1.8, 126 | child: Column( 127 | children: [ 128 | Expanded( 129 | flex: 10, 130 | child: CupertinoDatePicker( 131 | initialDateTime: DateTime 132 | .fromMillisecondsSinceEpoch( 133 | widget.todo 134 | .dateMilliseconds), 135 | minimumYear: 2022, 136 | maximumYear: 137 | (DateTime.now().year + 138 | 30), 139 | minimumDate: DateTime.fromMillisecondsSinceEpoch( 140 | // 18 141 | widget.todo.dateMilliseconds) 142 | .day != 143 | DateTime.now() 144 | .day // 19 145 | && 146 | DateTime.fromMillisecondsSinceEpoch( 147 | widget 148 | .todo 149 | .dateMilliseconds) 150 | .day >= 151 | DateTime.now().day 152 | ? DateTime.now() 153 | : todoDate, 154 | mode: CupertinoDatePickerMode 155 | .date, 156 | onDateTimeChanged: (datetime) { 157 | setState(() { 158 | _selectedDate = datetime; 159 | }); 160 | })), 161 | Expanded( 162 | flex: 2, 163 | child: CupertinoButton( 164 | child: Text( 165 | context.locale == Locale('en') 166 | ? 'Ok' 167 | : 'Tamam', 168 | style: 169 | TextStyle(fontSize: 25), 170 | ), 171 | onPressed: () { 172 | Navigator.of(context).pop(); 173 | }), 174 | ) 175 | ], 176 | )), 177 | ); 178 | }, 179 | child: Container( 180 | margin: const EdgeInsets.only(top: 10), 181 | alignment: Alignment.center, 182 | child: FittedBox( 183 | child: _selectedDate == null 184 | ? Text(LocaleKeys.edittodo_default_date 185 | .tr(args: [ 186 | '${todoDate.day.toString().padLeft(2, '0')}.${todoDate.month.toString().padLeft(2, '0')}.${todoDate.year}' 187 | ])) 188 | : Text(LocaleKeys.edittodo_selecteddate 189 | .tr(args: [ 190 | '${_selectedDate?.day.toString().padLeft(2, '0')}.${_selectedDate?.month.toString().padLeft(2, '0')}.${_selectedDate?.year}' 191 | ])), 192 | )), 193 | ), 194 | ), 195 | ), 196 | const SizedBox( 197 | width: 20, 198 | ), 199 | Expanded( 200 | // TIME 201 | child: SizedBox( 202 | width: MediaQuery.of(context).size.width / 2.5, 203 | height: MediaQuery.of(context).size.height / 14, 204 | child: ElevatedButton( 205 | style: ButtonStyle( 206 | backgroundColor: 207 | MaterialStateProperty.all( 208 | Colors.amber.shade800), 209 | shape: MaterialStateProperty.all< 210 | RoundedRectangleBorder>( 211 | RoundedRectangleBorder( 212 | borderRadius: BorderRadius.circular(13.0), 213 | ), 214 | ), 215 | ), 216 | onPressed: () { 217 | showCupertinoModalBottomSheet( 218 | shape: RoundedRectangleBorder( 219 | borderRadius: BorderRadius.circular(10.0), 220 | ), 221 | context: context, 222 | builder: (context) => Column( 223 | children: [ 224 | Expanded( 225 | flex: 10, 226 | child: CupertinoDatePicker( 227 | use24hFormat: true, 228 | initialDateTime: DateTime 229 | .fromMillisecondsSinceEpoch( 230 | widget.todo 231 | .timeMilliseconds), 232 | mode: 233 | CupertinoDatePickerMode.time, 234 | onDateTimeChanged: (datetime) { 235 | setState(() { 236 | _selectedTime = datetime; 237 | }); 238 | })), 239 | Expanded( 240 | flex: 2, 241 | child: CupertinoButton( 242 | child: Text( 243 | context.locale == Locale('en') 244 | ? 'Ok' 245 | : 'Tamam', 246 | style: TextStyle(fontSize: 25), 247 | ), 248 | onPressed: () { 249 | Navigator.of(context).pop(); 250 | }), 251 | ) 252 | ], 253 | ), 254 | ); 255 | }, 256 | child: Container( 257 | margin: const EdgeInsets.only(top: 10), 258 | alignment: Alignment.center, 259 | child: FittedBox( 260 | child: _selectedTime == null 261 | ? Text(LocaleKeys.edittodo_default_time 262 | .tr(args: [ 263 | '${todoTime.hour.toString().padLeft(2, '0')}:${todoTime.minute.toString().padLeft(2, '0')}' 264 | ])) 265 | : Text(LocaleKeys.edittodo_selectedtime 266 | .tr(args: [ 267 | '${_selectedTime?.hour.toString().padLeft(2, '0')}:${_selectedTime?.minute.toString().padLeft(2, '0')}' 268 | ])), 269 | )), 270 | ), 271 | ), 272 | ), 273 | SizedBox( 274 | width: 20, 275 | ), 276 | ], 277 | ), 278 | // Edit button 279 | Padding( 280 | padding: const EdgeInsets.only(top: 20.0, bottom: 40), 281 | child: SizedBox( 282 | width: 300, 283 | height: 50, 284 | child: ElevatedButton( 285 | style: ElevatedButton.styleFrom( 286 | primary: Colors.orangeAccent), 287 | onPressed: () { 288 | setState(() { 289 | if (formKey.currentState!.validate()) { 290 | Provider.of(context, 291 | listen: false) 292 | .editTodo( 293 | widget.todo, 294 | titleController!.text, 295 | descController!.text, 296 | categoryController!.text, 297 | _selectedDate 298 | ?.millisecondsSinceEpoch == 299 | null 300 | ? widget.todo.dateMilliseconds 301 | : _selectedDate! 302 | .millisecondsSinceEpoch, 303 | _selectedTime 304 | ?.millisecondsSinceEpoch == 305 | null 306 | ? widget.todo.timeMilliseconds 307 | : _selectedTime! 308 | .millisecondsSinceEpoch); 309 | 310 | titleController?.text = ''; 311 | descController?.text = ''; 312 | categoryController?.text = ''; 313 | Navigator.of(context) 314 | .popUntil((route) => route.isFirst); 315 | Fluttertoast.showToast( 316 | msg: "Done!", 317 | toastLength: Toast.LENGTH_SHORT, 318 | gravity: ToastGravity.BOTTOM, 319 | timeInSecForIosWeb: 1, 320 | backgroundColor: Colors.black, 321 | textColor: Colors.white, 322 | fontSize: 16.0); 323 | } 324 | }); 325 | }, 326 | child: Text(LocaleKeys.edittodo_edit_btn.tr()))), 327 | ) 328 | ], 329 | ), 330 | Positioned( 331 | top: 90, 332 | right: 10, 333 | child: TextButton( 334 | onPressed: () { 335 | Navigator.pop(context); 336 | }, 337 | child: Text(LocaleKeys.edittodo_close_btn.tr())), 338 | ) 339 | ], 340 | ), 341 | ), 342 | ), 343 | ), 344 | ); 345 | } 346 | } 347 | --------------------------------------------------------------------------------