diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 00000000..7750ad13
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,4 @@
+## June 11, 2019
+
+* Added dependency injection
+* Refactored dio client
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..aaaf6208
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Zubair Rehman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index d99f6c4c..c3a22f7e 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,16 @@
-# Smart-Insti-App 📱🏫
-This app aims to solve the day-to-day problems that students and faculty face in IIT Bhilai and aims to consolidate a lot of useful applications into single app. This could include features like Time Table, Classroom Vacancy, Lost and Found, Chatrooms on various topics like Internet Issues. It could also have a broadcast feature which would be very useful in emergency situations.
-
-## Techstack 👩💻
-Flutter, Firebase
-
-## Maintainers ☀️
- |[@Ananya](https://github.com/Ananyaiitbhilai)|[@chaitanyabisht](https://github.com/chaitanyabisht) |[@Maanas Talwar](https://github.com/maanas-talwar)| [@Satvik Vemuganti](https://github.com/VickyMerzOwn)|
-|------|-------|---------|--------|
-
-## Other details 📑
-This project is in its first iteration hence have to be started from scratch. A basic experience in app development is preferred.
-
-## Contribution Guidelines ✨
-Please go through the Wiki. Even a small contribution helps. All forms of contributions including documentation changes are highly welcomed and valued.
-- [How to create a PR?](https://github.com/OpenLake/Not-a-Mess/wiki/How-to-create-a-PR%3F)
-- [PR Format Guidelines](https://github.com/OpenLake/Not-a-Mess/wiki/PR-Format-Guidelines)
+# smart_insti
+
+A new Flutter project.
+
+## Getting Started
+
+This project is a starting point for a Flutter application.
+
+A few resources to get you started if this is your first Flutter project:
+
+- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
+- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
+
+For help getting started with Flutter development, view the
+[online documentation](https://docs.flutter.dev/), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 00000000..a7acf245
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,29 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at
+ # https://dart-lang.github.io/linter/lints/index.html.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/android/app/build.gradle b/android/app/build.gradle
new file mode 100644
index 00000000..383c6726
--- /dev/null
+++ b/android/app/build.gradle
@@ -0,0 +1,71 @@
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+ localPropertiesFile.withReader('UTF-8') { reader ->
+ localProperties.load(reader)
+ }
+}
+
+def flutterRoot = localProperties.getProperty('flutter.sdk')
+if (flutterRoot == null) {
+ throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+ flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+ flutterVersionName = '1.0'
+}
+
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
+
+android {
+ compileSdkVersion flutter.compileSdkVersion
+ ndkVersion flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId "com.example.smart_insti"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
+ minSdkVersion flutter.minSdkVersion
+ targetSdkVersion flutter.targetSdkVersion
+ versionCode flutterVersionCode.toInteger()
+ versionName flutterVersionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig signingConfigs.debug
+ }
+ }
+}
+
+flutter {
+ source '../..'
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 00000000..6d680701
--- /dev/null
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..b1593b0f
--- /dev/null
+++ b/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/java/com/iotecksolutions/todoapp/MainActivity.java b/android/app/src/main/java/com/iotecksolutions/todoapp/MainActivity.java
new file mode 100644
index 00000000..1e184251
--- /dev/null
+++ b/android/app/src/main/java/com/iotecksolutions/todoapp/MainActivity.java
@@ -0,0 +1,7 @@
+package com.iotecksolutions.todoapp;
+
+import io.flutter.embedding.android.FlutterActivity;
+
+public class MainActivity extends FlutterActivity {
+
+}
diff --git a/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
new file mode 100644
index 00000000..539ab022
--- /dev/null
+++ b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
@@ -0,0 +1,19 @@
+package io.flutter.plugins;
+
+import androidx.annotation.Keep;
+import androidx.annotation.NonNull;
+import io.flutter.Log;
+
+import io.flutter.embedding.engine.FlutterEngine;
+
+/**
+ * Generated file. Do not edit.
+ * This file is generated by the Flutter tool based on the
+ * plugins that support the Android platform.
+ */
+@Keep
+public final class GeneratedPluginRegistrant {
+ private static final String TAG = "GeneratedPluginRegistrant";
+ public static void registerWith(@NonNull FlutterEngine flutterEngine) {
+ }
+}
diff --git a/android/app/src/main/kotlin/com/example/smart_insti/MainActivity.kt b/android/app/src/main/kotlin/com/example/smart_insti/MainActivity.kt
new file mode 100644
index 00000000..439ff0d1
--- /dev/null
+++ b/android/app/src/main/kotlin/com/example/smart_insti/MainActivity.kt
@@ -0,0 +1,6 @@
+package com.example.smart_insti
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity() {
+}
diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 00000000..1cb7aa2f
--- /dev/null
+++ b/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/ic_appicon.png b/android/app/src/main/res/drawable/ic_appicon.png
new file mode 100644
index 00000000..655cd0e0
Binary files /dev/null and b/android/app/src/main/res/drawable/ic_appicon.png differ
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 00000000..84037589
--- /dev/null
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..db77bb4b
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..17987b79
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..09d43914
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..d5f1c8d3
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..4d6372ee
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 00000000..360a1605
--- /dev/null
+++ b/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..5fac6796
--- /dev/null
+++ b/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 00000000..6d680701
--- /dev/null
+++ b/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 00000000..104a4864
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,31 @@
+buildscript {
+ ext.kotlin_version = '1.6.10'
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:7.1.2'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(':app')
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/android/gradle.properties b/android/gradle.properties
new file mode 100644
index 00000000..46c1f169
--- /dev/null
+++ b/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx1536M
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..13372aef
Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..2108ceb9
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
diff --git a/android/gradlew b/android/gradlew
new file mode 100644
index 00000000..9d82f789
--- /dev/null
+++ b/android/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/android/gradlew.bat b/android/gradlew.bat
new file mode 100644
index 00000000..aec99730
--- /dev/null
+++ b/android/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/android/local.properties b/android/local.properties
new file mode 100644
index 00000000..9c05e2dc
--- /dev/null
+++ b/android/local.properties
@@ -0,0 +1 @@
+flutter.sdk=F:\\flutter
\ No newline at end of file
diff --git a/android/settings.gradle b/android/settings.gradle
new file mode 100644
index 00000000..33f0745d
--- /dev/null
+++ b/android/settings.gradle
@@ -0,0 +1,11 @@
+include ':app'
+
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
+
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
+
+def flutterSdkPath = properties.getProperty("flutter.sdk")
+assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
diff --git a/android/smart_insti_android.iml b/android/smart_insti_android.iml
new file mode 100644
index 00000000..5e74ee6a
--- /dev/null
+++ b/android/smart_insti_android.iml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/art/architecture.png b/art/architecture.png
new file mode 100644
index 00000000..ad94e3bb
Binary files /dev/null and b/art/architecture.png differ
diff --git a/art/flow.png b/art/flow.png
new file mode 100644
index 00000000..f7293596
Binary files /dev/null and b/art/flow.png differ
diff --git a/assets/fonts/Product-Sans-Bold-Italic.ttf b/assets/fonts/Product-Sans-Bold-Italic.ttf
new file mode 100644
index 00000000..129d12df
Binary files /dev/null and b/assets/fonts/Product-Sans-Bold-Italic.ttf differ
diff --git a/assets/fonts/Product-Sans-Bold.ttf b/assets/fonts/Product-Sans-Bold.ttf
new file mode 100644
index 00000000..d847195c
Binary files /dev/null and b/assets/fonts/Product-Sans-Bold.ttf differ
diff --git a/assets/fonts/Product-Sans-Italic.ttf b/assets/fonts/Product-Sans-Italic.ttf
new file mode 100644
index 00000000..5fc56d4c
Binary files /dev/null and b/assets/fonts/Product-Sans-Italic.ttf differ
diff --git a/assets/fonts/Product-Sans-Regular.ttf b/assets/fonts/Product-Sans-Regular.ttf
new file mode 100644
index 00000000..c0442ee2
Binary files /dev/null and b/assets/fonts/Product-Sans-Regular.ttf differ
diff --git a/assets/icons/ic_appicon.png b/assets/icons/ic_appicon.png
new file mode 100644
index 00000000..655cd0e0
Binary files /dev/null and b/assets/icons/ic_appicon.png differ
diff --git a/assets/icons/ic_launcher.png b/assets/icons/ic_launcher.png
new file mode 100644
index 00000000..285962f4
Binary files /dev/null and b/assets/icons/ic_launcher.png differ
diff --git a/assets/images/img_login.jpg b/assets/images/img_login.jpg
new file mode 100644
index 00000000..5e8529f1
Binary files /dev/null and b/assets/images/img_login.jpg differ
diff --git a/assets/images/img_no_jobs.png b/assets/images/img_no_jobs.png
new file mode 100644
index 00000000..a5c716d8
Binary files /dev/null and b/assets/images/img_no_jobs.png differ
diff --git a/assets/lang/da.json b/assets/lang/da.json
new file mode 100644
index 00000000..064bb1a1
--- /dev/null
+++ b/assets/lang/da.json
@@ -0,0 +1,17 @@
+{
+ "login_start": "Below are list of strings for login da ",
+ "login_et_user_email": "Brugernavn",
+ "login_et_user_password": "Adgangskode",
+ "login_btn_forgot_password": "Glemt adgangskode?",
+ "login_btn_sign_in": "Log ind",
+ "login_error_fill_fields": "Udfyld venligst alle felterne",
+ "login_end": "------------------------------------------------------------------------------------",
+
+ "home_start": "Below are list of strings for home",
+ "home_tv_posts": "Indlæg",
+ "home_tv_error": "Fejl",
+ "home_tv_no_post_found": "Ingen indlæg fundet",
+ "home_tv_choose_language": "Vælg sprog",
+ "home_end": "-------------------------------------------------------------------------------------"
+
+}
diff --git a/assets/lang/en.json b/assets/lang/en.json
new file mode 100644
index 00000000..1be1f370
--- /dev/null
+++ b/assets/lang/en.json
@@ -0,0 +1,17 @@
+{
+ "login_start": "Below are list of strings for login",
+ "login_et_user_email": "Enter user email",
+ "login_et_user_password": "Enter password",
+ "login_btn_forgot_password": "Forgot Password?",
+ "login_btn_sign_in": "Sign In",
+ "login_error_fill_fields": "Please fill in all fields",
+ "login_end": "------------------------------------------------------------------------------------",
+
+ "home_start": "Below are list of strings for home",
+ "home_tv_posts": "Posts",
+ "home_tv_error": "Error",
+ "home_tv_no_post_found": "No posts found",
+ "home_tv_choose_language": "Choose Language",
+ "home_end": "-------------------------------------------------------------------------------------"
+
+}
diff --git a/assets/lang/es.json b/assets/lang/es.json
new file mode 100644
index 00000000..d4fc47f6
--- /dev/null
+++ b/assets/lang/es.json
@@ -0,0 +1,16 @@
+{
+ "login_start": "Below are list of strings for login es ",
+ "login_et_user_email": "Ingrese el correo electrónico del usuario",
+ "login_et_user_password": "Introducir la contraseña",
+ "login_btn_forgot_password": "¿Se te olvidó tu contraseña",
+ "login_btn_sign_in": "Registrarse",
+ "login_error_fill_fields": "Por favor complete todos los campos e",
+ "login_end": "------------------------------------------------------------------------------------",
+
+ "home_start": "Below are list of strings for home",
+ "home_tv_posts": "Publicaciones",
+ "home_tv_error": "Error",
+ "home_tv_no_post_found": "No se han encontrado publicaciones",
+ "home_tv_choose_language": "Elige lengua",
+ "home_end": "-------------------------------------------------------------------------------------"
+}
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 00000000..8d4492f9
--- /dev/null
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ App
+ CFBundleIdentifier
+ io.flutter.flutter.app
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ App
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ MinimumOSVersion
+ 9.0
+
+
diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig
new file mode 100644
index 00000000..e8efba11
--- /dev/null
+++ b/ios/Flutter/Debug.xcconfig
@@ -0,0 +1,2 @@
+#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
+#include "Generated.xcconfig"
diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig
new file mode 100644
index 00000000..399e9340
--- /dev/null
+++ b/ios/Flutter/Release.xcconfig
@@ -0,0 +1,2 @@
+#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
+#include "Generated.xcconfig"
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 00000000..c83b0051
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,539 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 50;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+ 8981BC204AA6763F48392668 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 887069A31D31C9BF9D217F54 /* libPods-Runner.a */; };
+ 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
+ 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
+ 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 4FA17A1567654C183BDA1E63 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
+ 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
+ 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
+ 86CC2D58A4D5E9C5BEA67555 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
+ 887069A31D31C9BF9D217F54 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
+ 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
+ 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ B5E67463C84E3E6657585186 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 97C146EB1CF9000F007C117D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8981BC204AA6763F48392668 /* libPods-Runner.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 6A50AD2F0B3F0D889EFA460A /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 887069A31D31C9BF9D217F54 /* libPods-Runner.a */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 9740EEB11CF90186004384FC /* Flutter */ = {
+ isa = PBXGroup;
+ children = (
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */,
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */,
+ );
+ name = Flutter;
+ sourceTree = "";
+ };
+ 97C146E51CF9000F007C117D = {
+ isa = PBXGroup;
+ children = (
+ 9740EEB11CF90186004384FC /* Flutter */,
+ 97C146F01CF9000F007C117D /* Runner */,
+ 97C146EF1CF9000F007C117D /* Products */,
+ C48FD86A9715636178099FE1 /* Pods */,
+ 6A50AD2F0B3F0D889EFA460A /* Frameworks */,
+ );
+ sourceTree = "";
+ };
+ 97C146EF1CF9000F007C117D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146EE1CF9000F007C117D /* Runner.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 97C146F01CF9000F007C117D /* Runner */ = {
+ isa = PBXGroup;
+ children = (
+ 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
+ 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
+ 97C146FA1CF9000F007C117D /* Main.storyboard */,
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */,
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+ 97C147021CF9000F007C117D /* Info.plist */,
+ 97C146F11CF9000F007C117D /* Supporting Files */,
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+ );
+ path = Runner;
+ sourceTree = "";
+ };
+ 97C146F11CF9000F007C117D /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146F21CF9000F007C117D /* main.m */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ C48FD86A9715636178099FE1 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ B5E67463C84E3E6657585186 /* Pods-Runner.debug.xcconfig */,
+ 4FA17A1567654C183BDA1E63 /* Pods-Runner.release.xcconfig */,
+ 86CC2D58A4D5E9C5BEA67555 /* Pods-Runner.profile.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 97C146ED1CF9000F007C117D /* Runner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+ buildPhases = (
+ 641FA095A70B88123015AA6E /* [CP] Check Pods Manifest.lock */,
+ 9740EEB61CF901F6004384FC /* Run Script */,
+ 97C146EA1CF9000F007C117D /* Sources */,
+ 97C146EB1CF9000F007C117D /* Frameworks */,
+ 97C146EC1CF9000F007C117D /* Resources */,
+ 9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Runner;
+ productName = Runner;
+ productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 97C146E61CF9000F007C117D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 1300;
+ ORGANIZATIONNAME = "The Chromium Authors";
+ TargetAttributes = {
+ 97C146ED1CF9000F007C117D = {
+ CreatedOnToolsVersion = 7.3.1;
+ };
+ };
+ };
+ buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 97C146E51CF9000F007C117D;
+ productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 97C146ED1CF9000F007C117D /* Runner */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 97C146EC1CF9000F007C117D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+ 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Thin Binary";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+ };
+ 641FA095A70B88123015AA6E /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 9740EEB61CF901F6004384FC /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 97C146EA1CF9000F007C117D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
+ 97C146F31CF9000F007C117D /* main.m in Sources */,
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C146FB1CF9000F007C117D /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C147001CF9000F007C117D /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 249021D3217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Profile;
+ };
+ 249021D4217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = S8QB4VV633;
+ ENABLE_BITCODE = NO;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.iotecksolutions.todoApp;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Profile;
+ };
+ 97C147031CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 97C147041CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 97C147061CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ ENABLE_BITCODE = NO;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.iotecksolutions.todoApp;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 97C147071CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ ENABLE_BITCODE = NO;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.iotecksolutions.todoApp;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147031CF9000F007C117D /* Debug */,
+ 97C147041CF9000F007C117D /* Release */,
+ 249021D3217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147061CF9000F007C117D /* Debug */,
+ 97C147071CF9000F007C117D /* Release */,
+ 249021D4217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 00000000..919434a6
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 00000000..f1560181
--- /dev/null
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 00000000..21a3cc14
--- /dev/null
+++ b/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/ios/Runner/AppDelegate.h b/ios/Runner/AppDelegate.h
new file mode 100644
index 00000000..36e21bbf
--- /dev/null
+++ b/ios/Runner/AppDelegate.h
@@ -0,0 +1,6 @@
+#import
+#import
+
+@interface AppDelegate : FlutterAppDelegate
+
+@end
diff --git a/ios/Runner/AppDelegate.m b/ios/Runner/AppDelegate.m
new file mode 100644
index 00000000..59a72e90
--- /dev/null
+++ b/ios/Runner/AppDelegate.m
@@ -0,0 +1,13 @@
+#include "AppDelegate.h"
+#include "GeneratedPluginRegistrant.h"
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application
+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ [GeneratedPluginRegistrant registerWithRegistry:self];
+ // Override point for customization after application launch.
+ return [super application:application didFinishLaunchingWithOptions:launchOptions];
+}
+
+@end
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 00000000..d36b1fab
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,122 @@
+{
+ "images" : [
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "83.5x83.5",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-83.5x83.5@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "1024x1024",
+ "idiom" : "ios-marketing",
+ "filename" : "Icon-App-1024x1024@1x.png",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 00000000..3d43d11e
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 00000000..28c6bf03
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 00000000..2ccbfd96
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 00000000..f091b6b0
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 00000000..4cde1211
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 00000000..d0ef06e7
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 00000000..dcdc2306
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 00000000..2ccbfd96
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 00000000..c8f9ed8f
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 00000000..a6d6b860
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 00000000..a6d6b860
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 00000000..75b2d164
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 00000000..c4df70d3
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 00000000..6a84f41e
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 00000000..d0e1f585
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 00000000..0bedcf2f
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 00000000..9da19eac
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 00000000..9da19eac
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 00000000..9da19eac
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 00000000..89c2725b
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+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.
\ No newline at end of file
diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 00000000..f2e259c7
--- /dev/null
+++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 00000000..f3c28516
--- /dev/null
+++ b/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
new file mode 100644
index 00000000..25f900c7
--- /dev/null
+++ b/ios/Runner/Info.plist
@@ -0,0 +1,50 @@
+
+
+
+
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ Boilerplate Project
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+
+
diff --git a/ios/Runner/main.m b/ios/Runner/main.m
new file mode 100644
index 00000000..dff6597e
--- /dev/null
+++ b/ios/Runner/main.m
@@ -0,0 +1,9 @@
+#import
+#import
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/lib/constants/app_theme.dart b/lib/constants/app_theme.dart
new file mode 100644
index 00000000..fec93925
--- /dev/null
+++ b/lib/constants/app_theme.dart
@@ -0,0 +1,112 @@
+/// Creating custom color palettes is part of creating a custom app. The idea is to create
+/// your class of custom colors, in this case `CompanyColors` and then create a `ThemeData`
+/// object with those colors you just defined.
+///
+/// Resource:
+/// A good resource would be this website: http://mcg.mbitson.com/
+/// You simply need to put in the colour you wish to use, and it will generate all shades
+/// for you. Your primary colour will be the `500` value.
+///
+/// Colour Creation:
+/// In order to create the custom colours you need to create a `Map` object
+/// which will have all the shade values. `const Color(0xFF...)` will be how you create
+/// the colours. The six character hex code is what follows. If you wanted the colour
+/// #114488 or #D39090 as primary colours in your theme, then you would have
+/// `const Color(0x114488)` and `const Color(0xD39090)`, respectively.
+///
+/// Usage:
+/// In order to use this newly created theme or even the colours in it, you would just
+/// `import` this file in your project, anywhere you needed it.
+/// `import 'path/to/theme.dart';`
+import 'package:flutter/material.dart';
+import 'package:google_fonts/google_fonts.dart';
+
+class AppThemeData {
+ static const _lightFillColor = Colors.black;
+ static const _darkFillColor = Colors.white;
+
+ static final Color _lightFocusColor = Colors.black.withOpacity(0.12);
+ static final Color _darkFocusColor = Colors.white.withOpacity(0.12);
+
+ static ThemeData lightThemeData =
+ themeData(lightColorScheme, _lightFocusColor);
+ static ThemeData darkThemeData = themeData(darkColorScheme, _darkFocusColor);
+
+ static ThemeData themeData(ColorScheme colorScheme, Color focusColor) {
+ return ThemeData(
+ colorScheme: colorScheme,
+ textTheme: _textTheme,
+ // Matches manifest.json colors and background color.
+ primaryColor: const Color(0xFF030303),
+ appBarTheme: AppBarTheme(
+ backgroundColor: colorScheme.background,
+ elevation: 0,
+ iconTheme: IconThemeData(color: colorScheme.primary),
+ ),
+ iconTheme: IconThemeData(color: colorScheme.onPrimary),
+ canvasColor: colorScheme.background,
+ scaffoldBackgroundColor: colorScheme.background,
+ highlightColor: Colors.transparent,
+ focusColor: focusColor,
+ snackBarTheme: SnackBarThemeData(
+ behavior: SnackBarBehavior.floating,
+ backgroundColor: Color.alphaBlend(
+ _lightFillColor.withOpacity(0.80),
+ _darkFillColor,
+ ),
+ contentTextStyle: _textTheme.subtitle1!.apply(color: _darkFillColor),
+ ),
+ );
+ }
+
+ static const ColorScheme lightColorScheme = ColorScheme(
+ primary: Color(0xFFd21e1d),
+ primaryContainer: Color(0xFF9e1718),
+ secondary: Color(0xFFEFF3F3),
+ secondaryContainer: Color(0xFFFAFBFB),
+ background: Color(0xFFE6EBEB),
+ surface: Color(0xFFFAFBFB),
+ onBackground: Colors.white,
+ error: _lightFillColor,
+ onError: _lightFillColor,
+ onPrimary: _lightFillColor,
+ onSecondary: Color(0xFF322942),
+ onSurface: Color(0xFF241E30),
+ brightness: Brightness.light,
+ );
+
+ static const ColorScheme darkColorScheme = ColorScheme(
+ primary: Color(0xFFFF8383),
+ primaryContainer: Color(0xFF1CDEC9),
+ secondary: Color(0xFF4D1F7C),
+ secondaryContainer: Color(0xFF451B6F),
+ background: Color(0xFF241E30),
+ surface: Color(0xFF1F1929),
+ onBackground: Color(0x0DFFFFFF),
+ // White with 0.05 opacity
+ error: _darkFillColor,
+ onError: _darkFillColor,
+ onPrimary: _darkFillColor,
+ onSecondary: _darkFillColor,
+ onSurface: _darkFillColor,
+ brightness: Brightness.dark,
+ );
+
+ static const _regular = FontWeight.w400;
+ static const _medium = FontWeight.w500;
+ static const _semiBold = FontWeight.w600;
+ static const _bold = FontWeight.w700;
+
+ static final TextTheme _textTheme = TextTheme(
+ headline4: GoogleFonts.montserrat(fontWeight: _bold, fontSize: 20.0),
+ caption: GoogleFonts.oswald(fontWeight: _semiBold, fontSize: 16.0),
+ headline5: GoogleFonts.oswald(fontWeight: _medium, fontSize: 16.0),
+ subtitle1: GoogleFonts.montserrat(fontWeight: _medium, fontSize: 16.0),
+ overline: GoogleFonts.montserrat(fontWeight: _medium, fontSize: 12.0),
+ bodyText1: GoogleFonts.montserrat(fontWeight: _regular, fontSize: 14.0),
+ subtitle2: GoogleFonts.montserrat(fontWeight: _medium, fontSize: 14.0),
+ bodyText2: GoogleFonts.montserrat(fontWeight: _regular, fontSize: 16.0),
+ headline6: GoogleFonts.montserrat(fontWeight: _bold, fontSize: 16.0),
+ button: GoogleFonts.montserrat(fontWeight: _semiBold, fontSize: 14.0),
+ );
+}
diff --git a/lib/constants/assets.dart b/lib/constants/assets.dart
new file mode 100644
index 00000000..4d8505c7
--- /dev/null
+++ b/lib/constants/assets.dart
@@ -0,0 +1,10 @@
+class Assets {
+ Assets._();
+
+ // splash screen assets
+ static const String appLogo = "assets/icons/ic_appicon.png";
+
+ // login screen assets
+ static const String carBackground = "assets/images/img_login.jpg";
+
+}
\ No newline at end of file
diff --git a/lib/constants/colors.dart b/lib/constants/colors.dart
new file mode 100644
index 00000000..9cecce17
--- /dev/null
+++ b/lib/constants/colors.dart
@@ -0,0 +1,18 @@
+import 'package:flutter/material.dart';
+
+class AppColors {
+ AppColors._(); // this basically makes it so you can't instantiate this class
+
+ static const Map orange = const {
+ 50: const Color(0xFFFCF2E7),
+ 100: const Color(0xFFF8DEC3),
+ 200: const Color(0xFFF3C89C),
+ 300: const Color(0xFFEEB274),
+ 400: const Color(0xFFEAA256),
+ 500: const Color(0xFFE69138),
+ 600: const Color(0xFFE38932),
+ 700: const Color(0xFFDF7E2B),
+ 800: const Color(0xFFDB7424),
+ 900: const Color(0xFFD56217)
+ };
+}
diff --git a/lib/constants/dimens.dart b/lib/constants/dimens.dart
new file mode 100644
index 00000000..20b774d9
--- /dev/null
+++ b/lib/constants/dimens.dart
@@ -0,0 +1,7 @@
+class Dimens {
+ Dimens._();
+
+ //for all screens
+ static const double horizontal_padding = 12.0;
+ static const double vertical_padding = 12.0;
+}
\ No newline at end of file
diff --git a/lib/constants/font_family.dart b/lib/constants/font_family.dart
new file mode 100644
index 00000000..69001996
--- /dev/null
+++ b/lib/constants/font_family.dart
@@ -0,0 +1,6 @@
+class FontFamily {
+ FontFamily._();
+
+ static String productSans = "ProductSans";
+ static String roboto = "Roboto";
+}
\ No newline at end of file
diff --git a/lib/constants/strings.dart b/lib/constants/strings.dart
new file mode 100644
index 00000000..04bd63b6
--- /dev/null
+++ b/lib/constants/strings.dart
@@ -0,0 +1,6 @@
+class Strings {
+ Strings._();
+
+ //General
+ static const String appName = "Boilerplate Project";
+}
diff --git a/lib/data/local/constants/db_constants.dart b/lib/data/local/constants/db_constants.dart
new file mode 100644
index 00000000..25ba1b03
--- /dev/null
+++ b/lib/data/local/constants/db_constants.dart
@@ -0,0 +1,12 @@
+class DBConstants {
+ DBConstants._();
+
+ // Store Name
+ static const String STORE_NAME = 'demo';
+
+ // DB Name
+ static const DB_NAME = 'demo.db';
+
+ // Fields
+ static const FIELD_ID = 'id';
+}
diff --git a/lib/data/local/datasources/post/post_datasource.dart b/lib/data/local/datasources/post/post_datasource.dart
new file mode 100644
index 00000000..8d1218a0
--- /dev/null
+++ b/lib/data/local/datasources/post/post_datasource.dart
@@ -0,0 +1,101 @@
+import 'package:boilerplate/data/local/constants/db_constants.dart';
+import 'package:boilerplate/models/post/post.dart';
+import 'package:boilerplate/models/post/post_list.dart';
+import 'package:sembast/sembast.dart';
+
+class PostDataSource {
+ // A Store with int keys and Map values.
+ // This Store acts like a persistent map, values of which are Flogs objects converted to Map
+ final _postsStore = intMapStoreFactory.store(DBConstants.STORE_NAME);
+
+ // Private getter to shorten the amount of code needed to get the
+ // singleton instance of an opened database.
+// Future get _db async => await AppDatabase.instance.database;
+
+ // database instance
+ final Database _db;
+
+ // Constructor
+ PostDataSource(this._db);
+
+ // DB functions:--------------------------------------------------------------
+ Future insert(Post post) async {
+ return await _postsStore.add(_db, post.toMap());
+ }
+
+ Future count() async {
+ return await _postsStore.count(_db);
+ }
+
+ Future> getAllSortedByFilter({List? filters}) async {
+ //creating finder
+ final finder = Finder(
+ filter: filters != null ? Filter.and(filters) : null,
+ sortOrders: [SortOrder(DBConstants.FIELD_ID)]);
+
+ final recordSnapshots = await _postsStore.find(
+ _db,
+ finder: finder,
+ );
+
+ // Making a List out of List
+ return recordSnapshots.map((snapshot) {
+ final post = Post.fromMap(snapshot.value);
+ // An ID is a key of a record from the database.
+ post.id = snapshot.key;
+ return post;
+ }).toList();
+ }
+
+ Future getPostsFromDb() async {
+
+ print('Loading from database');
+
+ // post list
+ var postsList;
+
+ // fetching data
+ final recordSnapshots = await _postsStore.find(
+ _db,
+ );
+
+ // Making a List out of List
+ if(recordSnapshots.length > 0) {
+ postsList = PostList(
+ posts: recordSnapshots.map((snapshot) {
+ final post = Post.fromMap(snapshot.value);
+ // An ID is a key of a record from the database.
+ post.id = snapshot.key;
+ return post;
+ }).toList());
+ }
+
+ return postsList;
+ }
+
+ Future update(Post post) async {
+ // For filtering by key (ID), RegEx, greater than, and many other criteria,
+ // we use a Finder.
+ final finder = Finder(filter: Filter.byKey(post.id));
+ return await _postsStore.update(
+ _db,
+ post.toMap(),
+ finder: finder,
+ );
+ }
+
+ Future delete(Post post) async {
+ final finder = Finder(filter: Filter.byKey(post.id));
+ return await _postsStore.delete(
+ _db,
+ finder: finder,
+ );
+ }
+
+ Future deleteAll() async {
+ await _postsStore.drop(
+ _db,
+ );
+ }
+
+}
diff --git a/lib/data/network/apis/posts/post_api.dart b/lib/data/network/apis/posts/post_api.dart
new file mode 100644
index 00000000..154e4ecd
--- /dev/null
+++ b/lib/data/network/apis/posts/post_api.dart
@@ -0,0 +1,38 @@
+import 'dart:async';
+
+import 'package:boilerplate/data/network/constants/endpoints.dart';
+import 'package:boilerplate/data/network/dio_client.dart';
+import 'package:boilerplate/data/network/rest_client.dart';
+import 'package:boilerplate/models/post/post_list.dart';
+
+class PostApi {
+ // dio instance
+ final DioClient _dioClient;
+
+ // rest-client instance
+ final RestClient _restClient;
+
+ // injecting dio instance
+ PostApi(this._dioClient, this._restClient);
+
+ /// Returns list of post in response
+ Future getPosts() async {
+ try {
+ final res = await _dioClient.get(Endpoints.getPosts);
+ return PostList.fromJson(res);
+ } catch (e) {
+ print(e.toString());
+ throw e;
+ }
+ }
+
+/// sample api call with default rest client
+// Future getPosts() {
+//
+// return _restClient
+// .get(Endpoints.getPosts)
+// .then((dynamic res) => PostsList.fromJson(res))
+// .catchError((error) => throw NetworkException(message: error));
+// }
+
+}
diff --git a/lib/data/network/constants/endpoints.dart b/lib/data/network/constants/endpoints.dart
new file mode 100644
index 00000000..160227aa
--- /dev/null
+++ b/lib/data/network/constants/endpoints.dart
@@ -0,0 +1,15 @@
+class Endpoints {
+ Endpoints._();
+
+ // base url
+ static const String baseUrl = "http://jsonplaceholder.typicode.com";
+
+ // receiveTimeout
+ static const int receiveTimeout = 15000;
+
+ // connectTimeout
+ static const int connectionTimeout = 30000;
+
+ // booking endpoints
+ static const String getPosts = baseUrl + "/posts";
+}
\ No newline at end of file
diff --git a/lib/data/network/dio_client.dart b/lib/data/network/dio_client.dart
new file mode 100644
index 00000000..3509fd1c
--- /dev/null
+++ b/lib/data/network/dio_client.dart
@@ -0,0 +1,108 @@
+import 'package:dio/dio.dart';
+
+class DioClient {
+ // dio instance
+ final Dio _dio;
+
+ // injecting dio instance
+ DioClient(this._dio);
+
+ // Get:-----------------------------------------------------------------------
+ Future get(
+ String uri, {
+ Map? queryParameters,
+ Options? options,
+ CancelToken? cancelToken,
+ ProgressCallback? onReceiveProgress,
+ }) async {
+ try {
+ final Response response = await _dio.get(
+ uri,
+ queryParameters: queryParameters,
+ options: options,
+ cancelToken: cancelToken,
+ onReceiveProgress: onReceiveProgress,
+ );
+ return response.data;
+ } catch (e) {
+ print(e.toString());
+ throw e;
+ }
+ }
+
+ // Post:----------------------------------------------------------------------
+ Future post(
+ String uri, {
+ data,
+ Map? queryParameters,
+ Options? options,
+ CancelToken? cancelToken,
+ ProgressCallback? onSendProgress,
+ ProgressCallback? onReceiveProgress,
+ }) async {
+ try {
+ final Response response = await _dio.post(
+ uri,
+ data: data,
+ queryParameters: queryParameters,
+ options: options,
+ cancelToken: cancelToken,
+ onSendProgress: onSendProgress,
+ onReceiveProgress: onReceiveProgress,
+ );
+ return response.data;
+ } catch (e) {
+ throw e;
+ }
+ }
+
+ // Put:-----------------------------------------------------------------------
+ Future put(
+ String uri, {
+ data,
+ Map? queryParameters,
+ Options? options,
+ CancelToken? cancelToken,
+ ProgressCallback? onSendProgress,
+ ProgressCallback? onReceiveProgress,
+ }) async {
+ try {
+ final Response response = await _dio.put(
+ uri,
+ data: data,
+ queryParameters: queryParameters,
+ options: options,
+ cancelToken: cancelToken,
+ onSendProgress: onSendProgress,
+ onReceiveProgress: onReceiveProgress,
+ );
+ return response.data;
+ } catch (e) {
+ throw e;
+ }
+ }
+
+ // Delete:--------------------------------------------------------------------
+ Future delete(
+ String uri, {
+ data,
+ Map? queryParameters,
+ Options? options,
+ CancelToken? cancelToken,
+ ProgressCallback? onSendProgress,
+ ProgressCallback? onReceiveProgress,
+ }) async {
+ try {
+ final Response response = await _dio.delete(
+ uri,
+ data: data,
+ queryParameters: queryParameters,
+ options: options,
+ cancelToken: cancelToken,
+ );
+ return response.data;
+ } catch (e) {
+ throw e;
+ }
+ }
+}
diff --git a/lib/data/network/exceptions/network_exceptions.dart b/lib/data/network/exceptions/network_exceptions.dart
new file mode 100644
index 00000000..8ba446d2
--- /dev/null
+++ b/lib/data/network/exceptions/network_exceptions.dart
@@ -0,0 +1,11 @@
+class NetworkException implements Exception {
+ String? message;
+ int? statusCode;
+
+ NetworkException({this.message, this.statusCode});
+}
+
+class AuthException extends NetworkException {
+ AuthException({message, statusCode})
+ : super(message: message, statusCode: statusCode);
+}
diff --git a/lib/data/network/rest_client.dart b/lib/data/network/rest_client.dart
new file mode 100644
index 00000000..b5fd6e57
--- /dev/null
+++ b/lib/data/network/rest_client.dart
@@ -0,0 +1,69 @@
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:boilerplate/data/network/constants/endpoints.dart';
+import 'package:http/http.dart' as http;
+
+import 'exceptions/network_exceptions.dart';
+
+class RestClient {
+ // instantiate json decoder for json serialization
+ final JsonDecoder _decoder = JsonDecoder();
+
+ // Get:-----------------------------------------------------------------------
+ Future get(String path) {
+ return http.get(Uri.https(Endpoints.baseUrl, path)).then(_createResponse);
+ }
+
+ // Post:----------------------------------------------------------------------
+ Future post(String path,
+ {Map? headers, body, encoding}) {
+ return http
+ .post(
+ Uri.https(Endpoints.baseUrl, path),
+ body: body,
+ headers: headers,
+ encoding: encoding,
+ )
+ .then(_createResponse);
+ }
+
+ // Put:----------------------------------------------------------------------
+ Future put(String path,
+ {Map? headers, body, encoding}) {
+ return http
+ .put(
+ Uri.https(Endpoints.baseUrl, path),
+ body: body,
+ headers: headers,
+ encoding: encoding,
+ )
+ .then(_createResponse);
+ }
+
+ // Delete:----------------------------------------------------------------------
+ Future delete(String path,
+ {Map? headers, body, encoding}) {
+ return http
+ .delete(
+ Uri.https(Endpoints.baseUrl, path),
+ body: body,
+ headers: headers,
+ encoding: encoding,
+ )
+ .then(_createResponse);
+ }
+
+ // Response:------------------------------------------------------------------
+ dynamic _createResponse(http.Response response) {
+ final String res = response.body;
+ final int statusCode = response.statusCode;
+
+ if (statusCode < 200 || statusCode > 400) {
+ throw NetworkException(
+ message: 'Error fetching data from server', statusCode: statusCode);
+ }
+
+ return _decoder.convert(res);
+ }
+}
diff --git a/lib/data/repository.dart b/lib/data/repository.dart
new file mode 100644
index 00000000..49b53580
--- /dev/null
+++ b/lib/data/repository.dart
@@ -0,0 +1,91 @@
+import 'dart:async';
+
+import 'package:boilerplate/data/local/datasources/post/post_datasource.dart';
+import 'package:boilerplate/data/sharedpref/shared_preference_helper.dart';
+import 'package:boilerplate/models/post/post.dart';
+import 'package:boilerplate/models/post/post_list.dart';
+import 'package:sembast/sembast.dart';
+
+import 'local/constants/db_constants.dart';
+import 'network/apis/posts/post_api.dart';
+
+class Repository {
+ // data source object
+ final PostDataSource _postDataSource;
+
+ // api objects
+ final PostApi _postApi;
+
+ // shared pref object
+ final SharedPreferenceHelper _sharedPrefsHelper;
+
+ // constructor
+ Repository(this._postApi, this._sharedPrefsHelper, this._postDataSource);
+
+ // Post: ---------------------------------------------------------------------
+ Future getPosts() async {
+ // check to see if posts are present in database, then fetch from database
+ // else make a network call to get all posts, store them into database for
+ // later use
+ return await _postApi.getPosts().then((postsList) {
+ postsList.posts?.forEach((post) {
+ _postDataSource.insert(post);
+ });
+
+ return postsList;
+ }).catchError((error) => throw error);
+ }
+
+ Future> findPostById(int id) {
+ //creating filter
+ List filters = [];
+
+ //check to see if dataLogsType is not null
+ Filter dataLogTypeFilter = Filter.equals(DBConstants.FIELD_ID, id);
+ filters.add(dataLogTypeFilter);
+
+ //making db call
+ return _postDataSource
+ .getAllSortedByFilter(filters: filters)
+ .then((posts) => posts)
+ .catchError((error) => throw error);
+ }
+
+ Future insert(Post post) => _postDataSource
+ .insert(post)
+ .then((id) => id)
+ .catchError((error) => throw error);
+
+ Future update(Post post) => _postDataSource
+ .update(post)
+ .then((id) => id)
+ .catchError((error) => throw error);
+
+ Future delete(Post post) => _postDataSource
+ .update(post)
+ .then((id) => id)
+ .catchError((error) => throw error);
+
+
+ // Login:---------------------------------------------------------------------
+ Future login(String email, String password) async {
+ return await Future.delayed(Duration(seconds: 2), ()=> true);
+ }
+
+ Future saveIsLoggedIn(bool value) =>
+ _sharedPrefsHelper.saveIsLoggedIn(value);
+
+ Future get isLoggedIn => _sharedPrefsHelper.isLoggedIn;
+
+ // Theme: --------------------------------------------------------------------
+ Future changeBrightnessToDark(bool value) =>
+ _sharedPrefsHelper.changeBrightnessToDark(value);
+
+ bool get isDarkMode => _sharedPrefsHelper.isDarkMode;
+
+ // Language: -----------------------------------------------------------------
+ Future changeLanguage(String value) =>
+ _sharedPrefsHelper.changeLanguage(value);
+
+ String? get currentLanguage => _sharedPrefsHelper.currentLanguage;
+}
\ No newline at end of file
diff --git a/lib/data/sharedpref/constants/preferences.dart b/lib/data/sharedpref/constants/preferences.dart
new file mode 100644
index 00000000..64fcc67b
--- /dev/null
+++ b/lib/data/sharedpref/constants/preferences.dart
@@ -0,0 +1,8 @@
+class Preferences {
+ Preferences._();
+
+ static const String is_logged_in = "isLoggedIn";
+ static const String auth_token = "authToken";
+ static const String is_dark_mode = "is_dark_mode";
+ static const String current_language = "current_language";
+}
\ No newline at end of file
diff --git a/lib/data/sharedpref/shared_preference_helper.dart b/lib/data/sharedpref/shared_preference_helper.dart
new file mode 100644
index 00000000..446a9ddd
--- /dev/null
+++ b/lib/data/sharedpref/shared_preference_helper.dart
@@ -0,0 +1,53 @@
+import 'dart:async';
+
+import 'package:shared_preferences/shared_preferences.dart';
+
+import 'constants/preferences.dart';
+
+class SharedPreferenceHelper {
+ // shared pref instance
+ final SharedPreferences _sharedPreference;
+
+ // constructor
+ SharedPreferenceHelper(this._sharedPreference);
+
+ // General Methods: ----------------------------------------------------------
+ Future get authToken async {
+ return _sharedPreference.getString(Preferences.auth_token);
+ }
+
+ Future saveAuthToken(String authToken) async {
+ return _sharedPreference.setString(Preferences.auth_token, authToken);
+ }
+
+ Future removeAuthToken() async {
+ return _sharedPreference.remove(Preferences.auth_token);
+ }
+
+ // Login:---------------------------------------------------------------------
+ Future get isLoggedIn async {
+ return _sharedPreference.getBool(Preferences.is_logged_in) ?? false;
+ }
+
+ Future saveIsLoggedIn(bool value) async {
+ return _sharedPreference.setBool(Preferences.is_logged_in, value);
+ }
+
+ // Theme:------------------------------------------------------
+ bool get isDarkMode {
+ return _sharedPreference.getBool(Preferences.is_dark_mode) ?? false;
+ }
+
+ Future changeBrightnessToDark(bool value) {
+ return _sharedPreference.setBool(Preferences.is_dark_mode, value);
+ }
+
+ // Language:---------------------------------------------------
+ String? get currentLanguage {
+ return _sharedPreference.getString(Preferences.current_language);
+ }
+
+ Future changeLanguage(String language) {
+ return _sharedPreference.setString(Preferences.current_language, language);
+ }
+}
\ No newline at end of file
diff --git a/lib/di/components/service_locator.dart b/lib/di/components/service_locator.dart
new file mode 100644
index 00000000..c081e79c
--- /dev/null
+++ b/lib/di/components/service_locator.dart
@@ -0,0 +1,56 @@
+
+import 'package:boilerplate/data/local/datasources/post/post_datasource.dart';
+import 'package:boilerplate/data/network/apis/posts/post_api.dart';
+import 'package:boilerplate/data/network/dio_client.dart';
+import 'package:boilerplate/data/network/rest_client.dart';
+import 'package:boilerplate/data/repository.dart';
+import 'package:boilerplate/data/sharedpref/shared_preference_helper.dart';
+import 'package:boilerplate/di/module/local_module.dart';
+import 'package:boilerplate/di/module/network_module.dart';
+import 'package:boilerplate/stores/error/error_store.dart';
+import 'package:boilerplate/stores/form/form_store.dart';
+import 'package:boilerplate/stores/language/language_store.dart';
+import 'package:boilerplate/stores/post/post_store.dart';
+import 'package:boilerplate/stores/theme/theme_store.dart';
+import 'package:boilerplate/stores/user/user_store.dart';
+import 'package:dio/dio.dart';
+import 'package:get_it/get_it.dart';
+import 'package:sembast/sembast.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+final getIt = GetIt.instance;
+
+Future setupLocator() async {
+ // factories:-----------------------------------------------------------------
+ getIt.registerFactory(() => ErrorStore());
+ getIt.registerFactory(() => FormStore());
+
+ // async singletons:----------------------------------------------------------
+ getIt.registerSingletonAsync(() => LocalModule.provideDatabase());
+ getIt.registerSingletonAsync(() => LocalModule.provideSharedPreferences());
+
+ // singletons:----------------------------------------------------------------
+ getIt.registerSingleton(SharedPreferenceHelper(await getIt.getAsync()));
+ getIt.registerSingleton(NetworkModule.provideDio(getIt()));
+ getIt.registerSingleton(DioClient(getIt()));
+ getIt.registerSingleton(RestClient());
+
+ // api's:---------------------------------------------------------------------
+ getIt.registerSingleton(PostApi(getIt(), getIt()));
+
+ // data sources
+ getIt.registerSingleton(PostDataSource(await getIt.getAsync()));
+
+ // repository:----------------------------------------------------------------
+ getIt.registerSingleton(Repository(
+ getIt(),
+ getIt(),
+ getIt(),
+ ));
+
+ // stores:--------------------------------------------------------------------
+ getIt.registerSingleton(LanguageStore(getIt()));
+ getIt.registerSingleton(PostStore(getIt()));
+ getIt.registerSingleton(ThemeStore(getIt()));
+ getIt.registerSingleton(UserStore(getIt()));
+}
diff --git a/lib/di/module/local_module.dart b/lib/di/module/local_module.dart
new file mode 100644
index 00000000..170884ae
--- /dev/null
+++ b/lib/di/module/local_module.dart
@@ -0,0 +1,48 @@
+import 'dart:async';
+
+import 'package:boilerplate/data/local/constants/db_constants.dart';
+import 'package:boilerplate/utils/encryption/xxtea.dart';
+import 'package:path/path.dart';
+import 'package:path_provider/path_provider.dart';
+import 'package:sembast/sembast.dart';
+import 'package:sembast/sembast_io.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+abstract class LocalModule {
+
+
+ /// A singleton preference provider.
+ ///
+ /// Calling it multiple times will return the same instance.
+ static Future provideSharedPreferences() {
+ return SharedPreferences.getInstance();
+ }
+
+ /// A singleton database provider.
+ ///
+ /// Calling it multiple times will return the same instance.
+ static Future provideDatabase() async {
+ // Key for encryption
+ var encryptionKey = "";
+
+ // Get a platform-specific directory where persistent app data can be stored
+ final appDocumentDir = await getApplicationDocumentsDirectory();
+
+ // Path with the form: /platform-specific-directory/demo.db
+ final dbPath = join(appDocumentDir.path, DBConstants.DB_NAME);
+
+ // Check to see if encryption is set, then provide codec
+ // else init normal db with path
+ var database;
+ if (encryptionKey.isNotEmpty) {
+ // Initialize the encryption codec with a user password
+ var codec = getXXTeaCodec(password: encryptionKey);
+ database = await databaseFactoryIo.openDatabase(dbPath, codec: codec);
+ } else {
+ database = await databaseFactoryIo.openDatabase(dbPath);
+ }
+
+ // Return database instance
+ return database;
+ }
+}
diff --git a/lib/di/module/network_module.dart b/lib/di/module/network_module.dart
new file mode 100644
index 00000000..f3fb079f
--- /dev/null
+++ b/lib/di/module/network_module.dart
@@ -0,0 +1,43 @@
+import 'package:boilerplate/data/network/constants/endpoints.dart';
+import 'package:boilerplate/data/sharedpref/shared_preference_helper.dart';
+import 'package:dio/dio.dart';
+
+abstract class NetworkModule {
+ /// A singleton dio provider.
+ ///
+ /// Calling it multiple times will return the same instance.
+ static Dio provideDio(SharedPreferenceHelper sharedPrefHelper) {
+ final dio = Dio();
+
+ dio
+ ..options.baseUrl = Endpoints.baseUrl
+ ..options.connectTimeout = Endpoints.connectionTimeout
+ ..options.receiveTimeout = Endpoints.receiveTimeout
+ ..options.headers = {'Content-Type': 'application/json; charset=utf-8'}
+ ..interceptors.add(LogInterceptor(
+ request: true,
+ responseBody: true,
+ requestBody: true,
+ requestHeader: true,
+ ))
+ ..interceptors.add(
+ InterceptorsWrapper(
+ onRequest: (RequestOptions options,
+ RequestInterceptorHandler handler) async {
+ // getting token
+ var token = await sharedPrefHelper.authToken;
+
+ if (token != null) {
+ options.headers.putIfAbsent('Authorization', () => token);
+ } else {
+ print('Auth token is null');
+ }
+
+ return handler.next(options);
+ },
+ ),
+ );
+
+ return dio;
+ }
+}
diff --git a/lib/main.dart b/lib/main.dart
new file mode 100644
index 00000000..ef4ae22f
--- /dev/null
+++ b/lib/main.dart
@@ -0,0 +1,115 @@
+import 'package:flutter/material.dart';
+
+void main() {
+ runApp(const MyApp());
+}
+
+class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+
+ // This widget is the root of your application.
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'Flutter Demo',
+ theme: ThemeData(
+ // This is the theme of your application.
+ //
+ // Try running your application with "flutter run". You'll see the
+ // application has a blue toolbar. Then, without quitting the app, try
+ // changing the primarySwatch below to Colors.green and then invoke
+ // "hot reload" (press "r" in the console where you ran "flutter run",
+ // or simply save your changes to "hot reload" in a Flutter IDE).
+ // Notice that the counter didn't reset back to zero; the application
+ // is not restarted.
+ primarySwatch: Colors.blue,
+ ),
+ home: const MyHomePage(title: 'Flutter Demo Home Page'),
+ );
+ }
+}
+
+class MyHomePage extends StatefulWidget {
+ const MyHomePage({super.key, required this.title});
+
+ // This widget is the home page of your application. It is stateful, meaning
+ // that it has a State object (defined below) that contains fields that affect
+ // how it looks.
+
+ // This class is the configuration for the state. It holds the values (in this
+ // case the title) provided by the parent (in this case the App widget) and
+ // used by the build method of the State. Fields in a Widget subclass are
+ // always marked "final".
+
+ final String title;
+
+ @override
+ State createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State {
+ int _counter = 0;
+
+ void _incrementCounter() {
+ setState(() {
+ // This call to setState tells the Flutter framework that something has
+ // changed in this State, which causes it to rerun the build method below
+ // so that the display can reflect the updated values. If we changed
+ // _counter without calling setState(), then the build method would not be
+ // called again, and so nothing would appear to happen.
+ _counter++;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ // This method is rerun every time setState is called, for instance as done
+ // by the _incrementCounter method above.
+ //
+ // The Flutter framework has been optimized to make rerunning build methods
+ // fast, so that you can just rebuild anything that needs updating rather
+ // than having to individually change instances of widgets.
+ return Scaffold(
+ appBar: AppBar(
+ // Here we take the value from the MyHomePage object that was created by
+ // the App.build method, and use it to set our appbar title.
+ title: Text(widget.title),
+ ),
+ body: Center(
+ // Center is a layout widget. It takes a single child and positions it
+ // in the middle of the parent.
+ child: Column(
+ // Column is also a layout widget. It takes a list of children and
+ // arranges them vertically. By default, it sizes itself to fit its
+ // children horizontally, and tries to be as tall as its parent.
+ //
+ // Invoke "debug painting" (press "p" in the console, choose the
+ // "Toggle Debug Paint" action from the Flutter Inspector in Android
+ // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
+ // to see the wireframe for each widget.
+ //
+ // Column has various properties to control how it sizes itself and
+ // how it positions its children. Here we use mainAxisAlignment to
+ // center the children vertically; the main axis here is the vertical
+ // axis because Columns are vertical (the cross axis would be
+ // horizontal).
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const Text(
+ 'You have pushed the button this many times:',
+ ),
+ Text(
+ '$_counter',
+ style: Theme.of(context).textTheme.headline4,
+ ),
+ ],
+ ),
+ ),
+ floatingActionButton: FloatingActionButton(
+ onPressed: _incrementCounter,
+ tooltip: 'Increment',
+ child: const Icon(Icons.add),
+ ), // This trailing comma makes auto-formatting nicer for build methods.
+ );
+ }
+}
diff --git a/lib/models/language/Language.dart b/lib/models/language/Language.dart
new file mode 100644
index 00000000..0c27ebaf
--- /dev/null
+++ b/lib/models/language/Language.dart
@@ -0,0 +1,15 @@
+class Language {
+ /// the country code (IT,AF..)
+ String? code;
+
+ /// the locale (en, es, da)
+ String? locale;
+
+ /// the full name of language (English, Danish..)
+ String? language;
+
+ /// map of keys used based on industry type (service worker, route etc)
+ Map? dictionary;
+
+ Language({this.code, this.locale, this.language, this.dictionary});
+}
diff --git a/lib/models/post/post.dart b/lib/models/post/post.dart
new file mode 100644
index 00000000..449b6c23
--- /dev/null
+++ b/lib/models/post/post.dart
@@ -0,0 +1,28 @@
+class Post {
+ int? userId;
+ int? id;
+ String? title;
+ String? body;
+
+ Post({
+ this.userId,
+ this.id,
+ this.title,
+ this.body,
+ });
+
+ factory Post.fromMap(Map json) => Post(
+ userId: json["userId"],
+ id: json["id"],
+ title: json["title"],
+ body: json["body"],
+ );
+
+ Map toMap() => {
+ "userId": userId,
+ "id": id,
+ "title": title,
+ "body": body,
+ };
+
+}
diff --git a/lib/models/post/post_list.dart b/lib/models/post/post_list.dart
new file mode 100644
index 00000000..e537a244
--- /dev/null
+++ b/lib/models/post/post_list.dart
@@ -0,0 +1,18 @@
+import 'package:boilerplate/models/post/post.dart';
+
+class PostList {
+ final List? posts;
+
+ PostList({
+ this.posts,
+ });
+
+ factory PostList.fromJson(List json) {
+ List posts = [];
+ posts = json.map((post) => Post.fromMap(post)).toList();
+
+ return PostList(
+ posts: posts,
+ );
+ }
+}
diff --git a/lib/stores/error/error_store.dart b/lib/stores/error/error_store.dart
new file mode 100644
index 00000000..e98922fe
--- /dev/null
+++ b/lib/stores/error/error_store.dart
@@ -0,0 +1,43 @@
+import 'package:mobx/mobx.dart';
+
+part 'error_store.g.dart';
+
+class ErrorStore = _ErrorStore with _$ErrorStore;
+
+abstract class _ErrorStore with Store {
+
+ // disposers
+ late List _disposers;
+
+ // constructor:---------------------------------------------------------------
+ _ErrorStore() {
+ _disposers = [
+ reaction((_) => errorMessage, reset, delay: 200),
+ ];
+ }
+
+ // store variables:-----------------------------------------------------------
+ @observable
+ String errorMessage = '';
+
+
+ // actions:-------------------------------------------------------------------
+ @action
+ void setErrorMessage(String message) {
+ this.errorMessage = message;
+ }
+
+ @action
+ void reset(String value) {
+ print('calling reset');
+ errorMessage = '';
+ }
+
+ // dispose:-------------------------------------------------------------------
+ @action
+ dispose() {
+ for (final d in _disposers) {
+ d();
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/stores/error/error_store.g.dart b/lib/stores/error/error_store.g.dart
new file mode 100644
index 00000000..5b1d960b
--- /dev/null
+++ b/lib/stores/error/error_store.g.dart
@@ -0,0 +1,43 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'error_store.dart';
+
+// **************************************************************************
+// StoreGenerator
+// **************************************************************************
+
+// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars
+
+mixin _$ErrorStore on _ErrorStore, Store {
+ final _$errorMessageAtom = Atom(name: '_ErrorStore.errorMessage');
+
+ @override
+ String get errorMessage {
+ _$errorMessageAtom.reportObserved();
+ return super.errorMessage;
+ }
+
+ @override
+ set errorMessage(String value) {
+ _$errorMessageAtom.context
+ .checkIfStateModificationsAreAllowed(_$errorMessageAtom);
+ super.errorMessage = value;
+ _$errorMessageAtom.reportChanged();
+ }
+
+ final _$showErrorAtom = Atom(name: '_ErrorStore.showError');
+
+ @override
+ bool get showError {
+ _$showErrorAtom.reportObserved();
+ return super.showError;
+ }
+
+ @override
+ set showError(bool value) {
+ _$showErrorAtom.context
+ .checkIfStateModificationsAreAllowed(_$showErrorAtom);
+ super.showError = value;
+ _$showErrorAtom.reportChanged();
+ }
+}
diff --git a/lib/stores/form/form_store.dart b/lib/stores/form/form_store.dart
new file mode 100644
index 00000000..6e2b6f4a
--- /dev/null
+++ b/lib/stores/form/form_store.dart
@@ -0,0 +1,177 @@
+import 'package:boilerplate/stores/error/error_store.dart';
+import 'package:mobx/mobx.dart';
+import 'package:validators/validators.dart';
+
+part 'form_store.g.dart';
+
+class FormStore = _FormStore with _$FormStore;
+
+abstract class _FormStore with Store {
+ // store for handling form errors
+ final FormErrorStore formErrorStore = FormErrorStore();
+
+ // store for handling error messages
+ final ErrorStore errorStore = ErrorStore();
+
+ _FormStore() {
+ _setupValidations();
+ }
+
+ // disposers:-----------------------------------------------------------------
+ late List _disposers;
+
+ void _setupValidations() {
+ _disposers = [
+ reaction((_) => userEmail, validateUserEmail),
+ reaction((_) => password, validatePassword),
+ reaction((_) => confirmPassword, validateConfirmPassword)
+ ];
+ }
+
+ // store variables:-----------------------------------------------------------
+ @observable
+ String userEmail = '';
+
+ @observable
+ String password = '';
+
+ @observable
+ String confirmPassword = '';
+
+ @observable
+ bool success = false;
+
+ @observable
+ bool loading = false;
+
+ @computed
+ bool get canLogin =>
+ !formErrorStore.hasErrorsInLogin && userEmail.isNotEmpty && password.isNotEmpty;
+
+ @computed
+ bool get canRegister =>
+ !formErrorStore.hasErrorsInRegister &&
+ userEmail.isNotEmpty &&
+ password.isNotEmpty &&
+ confirmPassword.isNotEmpty;
+
+ @computed
+ bool get canForgetPassword =>
+ !formErrorStore.hasErrorInForgotPassword && userEmail.isNotEmpty;
+
+ // actions:-------------------------------------------------------------------
+ @action
+ void setUserId(String value) {
+ userEmail = value;
+ }
+
+ @action
+ void setPassword(String value) {
+ password = value;
+ }
+
+ @action
+ void setConfirmPassword(String value) {
+ confirmPassword = value;
+ }
+
+ @action
+ void validateUserEmail(String value) {
+ if (value.isEmpty) {
+ formErrorStore.userEmail = "Email can't be empty";
+ } else if (!isEmail(value)) {
+ formErrorStore.userEmail = 'Please enter a valid email address';
+ } else {
+ formErrorStore.userEmail = null;
+ }
+ }
+
+ @action
+ void validatePassword(String value) {
+ if (value.isEmpty) {
+ formErrorStore.password = "Password can't be empty";
+ } else if (value.length < 6) {
+ formErrorStore.password = "Password must be at-least 6 characters long";
+ } else {
+ formErrorStore.password = null;
+ }
+ }
+
+ @action
+ void validateConfirmPassword(String value) {
+ if (value.isEmpty) {
+ formErrorStore.confirmPassword = "Confirm password can't be empty";
+ } else if (value != password) {
+ formErrorStore.confirmPassword = "Password doen't match";
+ } else {
+ formErrorStore.confirmPassword = null;
+ }
+ }
+
+ @action
+ Future register() async {
+ loading = true;
+ }
+
+ @action
+ Future login() async {
+ loading = true;
+
+ Future.delayed(Duration(milliseconds: 2000)).then((future) {
+ loading = false;
+ success = true;
+ }).catchError((e) {
+ loading = false;
+ success = false;
+ errorStore.errorMessage = e.toString().contains("ERROR_USER_NOT_FOUND")
+ ? "Username and password doesn't match"
+ : "Something went wrong, please check your internet connection and try again";
+ print(e);
+ });
+ }
+
+ @action
+ Future forgotPassword() async {
+ loading = true;
+ }
+
+ @action
+ Future logout() async {
+ loading = true;
+ }
+
+ // general methods:-----------------------------------------------------------
+ void dispose() {
+ for (final d in _disposers) {
+ d();
+ }
+ }
+
+ void validateAll() {
+ validatePassword(password);
+ validateUserEmail(userEmail);
+ }
+}
+
+class FormErrorStore = _FormErrorStore with _$FormErrorStore;
+
+abstract class _FormErrorStore with Store {
+ @observable
+ String? userEmail;
+
+ @observable
+ String? password;
+
+ @observable
+ String? confirmPassword;
+
+ @computed
+ bool get hasErrorsInLogin => userEmail != null || password != null;
+
+ @computed
+ bool get hasErrorsInRegister =>
+ userEmail != null || password != null || confirmPassword != null;
+
+ @computed
+ bool get hasErrorInForgotPassword => userEmail != null;
+}
diff --git a/lib/stores/form/form_store.g.dart b/lib/stores/form/form_store.g.dart
new file mode 100644
index 00000000..2e079822
--- /dev/null
+++ b/lib/stores/form/form_store.g.dart
@@ -0,0 +1,281 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'form_store.dart';
+
+// **************************************************************************
+// StoreGenerator
+// **************************************************************************
+
+// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars
+
+mixin _$FormStore on _FormStore, Store {
+ Computed _$canLoginComputed;
+
+ @override
+ bool get canLogin =>
+ (_$canLoginComputed ??= Computed(() => super.canLogin)).value;
+ Computed _$canRegisterComputed;
+
+ @override
+ bool get canRegister =>
+ (_$canRegisterComputed ??= Computed(() => super.canRegister)).value;
+ Computed _$canForgetPasswordComputed;
+
+ @override
+ bool get canForgetPassword => (_$canForgetPasswordComputed ??=
+ Computed(() => super.canForgetPassword))
+ .value;
+
+ final _$postsListAtom = Atom(name: '_FormStore.postsList');
+
+ @override
+ PostsList get postsList {
+ _$postsListAtom.reportObserved();
+ return super.postsList;
+ }
+
+ @override
+ set postsList(PostsList value) {
+ _$postsListAtom.context
+ .checkIfStateModificationsAreAllowed(_$postsListAtom);
+ super.postsList = value;
+ _$postsListAtom.reportChanged();
+ }
+
+ final _$userEmailAtom = Atom(name: '_FormStore.userEmail');
+
+ @override
+ String get userEmail {
+ _$userEmailAtom.reportObserved();
+ return super.userEmail;
+ }
+
+ @override
+ set userEmail(String value) {
+ _$userEmailAtom.context
+ .checkIfStateModificationsAreAllowed(_$userEmailAtom);
+ super.userEmail = value;
+ _$userEmailAtom.reportChanged();
+ }
+
+ final _$passwordAtom = Atom(name: '_FormStore.password');
+
+ @override
+ String get password {
+ _$passwordAtom.reportObserved();
+ return super.password;
+ }
+
+ @override
+ set password(String value) {
+ _$passwordAtom.context.checkIfStateModificationsAreAllowed(_$passwordAtom);
+ super.password = value;
+ _$passwordAtom.reportChanged();
+ }
+
+ final _$confirmPasswordAtom = Atom(name: '_FormStore.confirmPassword');
+
+ @override
+ String get confirmPassword {
+ _$confirmPasswordAtom.reportObserved();
+ return super.confirmPassword;
+ }
+
+ @override
+ set confirmPassword(String value) {
+ _$confirmPasswordAtom.context
+ .checkIfStateModificationsAreAllowed(_$confirmPasswordAtom);
+ super.confirmPassword = value;
+ _$confirmPasswordAtom.reportChanged();
+ }
+
+ final _$successAtom = Atom(name: '_FormStore.success');
+
+ @override
+ bool get success {
+ _$successAtom.reportObserved();
+ return super.success;
+ }
+
+ @override
+ set success(bool value) {
+ _$successAtom.context.checkIfStateModificationsAreAllowed(_$successAtom);
+ super.success = value;
+ _$successAtom.reportChanged();
+ }
+
+ final _$loadingAtom = Atom(name: '_FormStore.loading');
+
+ @override
+ bool get loading {
+ _$loadingAtom.reportObserved();
+ return super.loading;
+ }
+
+ @override
+ set loading(bool value) {
+ _$loadingAtom.context.checkIfStateModificationsAreAllowed(_$loadingAtom);
+ super.loading = value;
+ _$loadingAtom.reportChanged();
+ }
+
+ final _$registerAsyncAction = AsyncAction('register');
+
+ @override
+ Future register() {
+ return _$registerAsyncAction.run(() => super.register());
+ }
+
+ final _$loginAsyncAction = AsyncAction('login');
+
+ @override
+ Future login() {
+ return _$loginAsyncAction.run(() => super.login());
+ }
+
+ final _$forgotPasswordAsyncAction = AsyncAction('forgotPassword');
+
+ @override
+ Future forgotPassword() {
+ return _$forgotPasswordAsyncAction.run(() => super.forgotPassword());
+ }
+
+ final _$logoutAsyncAction = AsyncAction('logout');
+
+ @override
+ Future logout() {
+ return _$logoutAsyncAction.run(() => super.logout());
+ }
+
+ final _$_FormStoreActionController = ActionController(name: '_FormStore');
+
+ @override
+ void setUserId(String value) {
+ final _$actionInfo = _$_FormStoreActionController.startAction();
+ try {
+ return super.setUserId(value);
+ } finally {
+ _$_FormStoreActionController.endAction(_$actionInfo);
+ }
+ }
+
+ @override
+ void setPassword(String value) {
+ final _$actionInfo = _$_FormStoreActionController.startAction();
+ try {
+ return super.setPassword(value);
+ } finally {
+ _$_FormStoreActionController.endAction(_$actionInfo);
+ }
+ }
+
+ @override
+ void setConfirmPassword(String value) {
+ final _$actionInfo = _$_FormStoreActionController.startAction();
+ try {
+ return super.setConfirmPassword(value);
+ } finally {
+ _$_FormStoreActionController.endAction(_$actionInfo);
+ }
+ }
+
+ @override
+ void validateUserEmail(String value) {
+ final _$actionInfo = _$_FormStoreActionController.startAction();
+ try {
+ return super.validateUserEmail(value);
+ } finally {
+ _$_FormStoreActionController.endAction(_$actionInfo);
+ }
+ }
+
+ @override
+ void validatePassword(String value) {
+ final _$actionInfo = _$_FormStoreActionController.startAction();
+ try {
+ return super.validatePassword(value);
+ } finally {
+ _$_FormStoreActionController.endAction(_$actionInfo);
+ }
+ }
+
+ @override
+ void validateConfirmPassword(String value) {
+ final _$actionInfo = _$_FormStoreActionController.startAction();
+ try {
+ return super.validateConfirmPassword(value);
+ } finally {
+ _$_FormStoreActionController.endAction(_$actionInfo);
+ }
+ }
+}
+
+// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars
+
+mixin _$FormErrorStore on _FormErrorStore, Store {
+ Computed _$hasErrorsInLoginComputed;
+
+ @override
+ bool get hasErrorsInLogin => (_$hasErrorsInLoginComputed ??=
+ Computed(() => super.hasErrorsInLogin))
+ .value;
+ Computed _$hasErrorsInRegisterComputed;
+
+ @override
+ bool get hasErrorsInRegister => (_$hasErrorsInRegisterComputed ??=
+ Computed(() => super.hasErrorsInRegister))
+ .value;
+ Computed _$hasErrorInForgotPasswordComputed;
+
+ @override
+ bool get hasErrorInForgotPassword => (_$hasErrorInForgotPasswordComputed ??=
+ Computed(() => super.hasErrorInForgotPassword))
+ .value;
+
+ final _$userEmailAtom = Atom(name: '_FormErrorStore.userEmail');
+
+ @override
+ String get userEmail {
+ _$userEmailAtom.reportObserved();
+ return super.userEmail;
+ }
+
+ @override
+ set userEmail(String value) {
+ _$userEmailAtom.context
+ .checkIfStateModificationsAreAllowed(_$userEmailAtom);
+ super.userEmail = value;
+ _$userEmailAtom.reportChanged();
+ }
+
+ final _$passwordAtom = Atom(name: '_FormErrorStore.password');
+
+ @override
+ String get password {
+ _$passwordAtom.reportObserved();
+ return super.password;
+ }
+
+ @override
+ set password(String value) {
+ _$passwordAtom.context.checkIfStateModificationsAreAllowed(_$passwordAtom);
+ super.password = value;
+ _$passwordAtom.reportChanged();
+ }
+
+ final _$confirmPasswordAtom = Atom(name: '_FormErrorStore.confirmPassword');
+
+ @override
+ String get confirmPassword {
+ _$confirmPasswordAtom.reportObserved();
+ return super.confirmPassword;
+ }
+
+ @override
+ set confirmPassword(String value) {
+ _$confirmPasswordAtom.context
+ .checkIfStateModificationsAreAllowed(_$confirmPasswordAtom);
+ super.confirmPassword = value;
+ _$confirmPasswordAtom.reportChanged();
+ }
+}
diff --git a/lib/stores/language/language_store.dart b/lib/stores/language/language_store.dart
new file mode 100644
index 00000000..1bcc9d6d
--- /dev/null
+++ b/lib/stores/language/language_store.dart
@@ -0,0 +1,81 @@
+import 'package:boilerplate/data/repository.dart';
+import 'package:boilerplate/models/language/Language.dart';
+import 'package:boilerplate/stores/error/error_store.dart';
+import 'package:mobx/mobx.dart';
+
+part 'language_store.g.dart';
+
+class LanguageStore = _LanguageStore with _$LanguageStore;
+
+abstract class _LanguageStore with Store {
+ static const String TAG = "LanguageStore";
+
+ // repository instance
+ final Repository _repository;
+
+ // store for handling errors
+ final ErrorStore errorStore = ErrorStore();
+
+ // supported languages
+ List supportedLanguages = [
+ Language(code: 'US', locale: 'en', language: 'English'),
+ Language(code: 'DK', locale: 'da', language: 'Danish'),
+ Language(code: 'ES', locale: 'es', language: 'España'),
+ ];
+
+ // constructor:---------------------------------------------------------------
+ _LanguageStore(Repository repository)
+ : this._repository = repository {
+ init();
+ }
+
+ // store variables:-----------------------------------------------------------
+ @observable
+ String _locale = "en";
+
+ @computed
+ String get locale => _locale;
+
+ // actions:-------------------------------------------------------------------
+ @action
+ void changeLanguage(String value) {
+ _locale = value;
+ _repository.changeLanguage(value).then((_) {
+ // write additional logic here
+ });
+ }
+
+ @action
+ String getCode() {
+ var code;
+
+ if (_locale == 'en') {
+ code = "US";
+ } else if (_locale == 'da') {
+ code = "DK";
+ } else if (_locale == 'es') {
+ code = "ES";
+ }
+
+ return code;
+ }
+
+ @action
+ String? getLanguage() {
+ return supportedLanguages[supportedLanguages
+ .indexWhere((language) => language.locale == _locale)]
+ .language;
+ }
+
+ // general:-------------------------------------------------------------------
+ void init() async {
+ // getting current language from shared preference
+ if(_repository.currentLanguage != null) {
+ _locale = _repository.currentLanguage!;
+ }
+ }
+
+ // dispose:-------------------------------------------------------------------
+ @override
+ dispose() {}
+}
diff --git a/lib/stores/post/post_store.dart b/lib/stores/post/post_store.dart
new file mode 100644
index 00000000..463d846d
--- /dev/null
+++ b/lib/stores/post/post_store.dart
@@ -0,0 +1,50 @@
+import 'package:boilerplate/data/repository.dart';
+import 'package:boilerplate/models/post/post_list.dart';
+import 'package:boilerplate/stores/error/error_store.dart';
+import 'package:boilerplate/utils/dio/dio_error_util.dart';
+import 'package:mobx/mobx.dart';
+
+part 'post_store.g.dart';
+
+class PostStore = _PostStore with _$PostStore;
+
+abstract class _PostStore with Store {
+ // repository instance
+ late Repository _repository;
+
+ // store for handling errors
+ final ErrorStore errorStore = ErrorStore();
+
+ // constructor:---------------------------------------------------------------
+ _PostStore(Repository repository) : this._repository = repository;
+
+ // store variables:-----------------------------------------------------------
+ static ObservableFuture emptyPostResponse =
+ ObservableFuture.value(null);
+
+ @observable
+ ObservableFuture fetchPostsFuture =
+ ObservableFuture(emptyPostResponse);
+
+ @observable
+ PostList? postList;
+
+ @observable
+ bool success = false;
+
+ @computed
+ bool get loading => fetchPostsFuture.status == FutureStatus.pending;
+
+ // actions:-------------------------------------------------------------------
+ @action
+ Future getPosts() async {
+ final future = _repository.getPosts();
+ fetchPostsFuture = ObservableFuture(future);
+
+ future.then((postList) {
+ this.postList = postList;
+ }).catchError((error) {
+ errorStore.errorMessage = DioErrorUtil.handleError(error);
+ });
+ }
+}
diff --git a/lib/stores/post/post_store.g.dart b/lib/stores/post/post_store.g.dart
new file mode 100644
index 00000000..425891d2
--- /dev/null
+++ b/lib/stores/post/post_store.g.dart
@@ -0,0 +1,64 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'post_store.dart';
+
+// **************************************************************************
+// StoreGenerator
+// **************************************************************************
+
+// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars
+
+mixin _$PostStore on _PostStore, Store {
+ final _$postsListAtom = Atom(name: '_PostStore.postsList');
+
+ @override
+ PostsList get postsList {
+ _$postsListAtom.reportObserved();
+ return super.postsList;
+ }
+
+ @override
+ set postsList(PostsList value) {
+ _$postsListAtom.context
+ .checkIfStateModificationsAreAllowed(_$postsListAtom);
+ super.postsList = value;
+ _$postsListAtom.reportChanged();
+ }
+
+ final _$successAtom = Atom(name: '_PostStore.success');
+
+ @override
+ bool get success {
+ _$successAtom.reportObserved();
+ return super.success;
+ }
+
+ @override
+ set success(bool value) {
+ _$successAtom.context.checkIfStateModificationsAreAllowed(_$successAtom);
+ super.success = value;
+ _$successAtom.reportChanged();
+ }
+
+ final _$loadingAtom = Atom(name: '_PostStore.loading');
+
+ @override
+ bool get loading {
+ _$loadingAtom.reportObserved();
+ return super.loading;
+ }
+
+ @override
+ set loading(bool value) {
+ _$loadingAtom.context.checkIfStateModificationsAreAllowed(_$loadingAtom);
+ super.loading = value;
+ _$loadingAtom.reportChanged();
+ }
+
+ final _$getPostsAsyncAction = AsyncAction('getPosts');
+
+ @override
+ Future getPosts() {
+ return _$getPostsAsyncAction.run(() => super.getPosts());
+ }
+}
diff --git a/lib/stores/theme/theme_store.dart b/lib/stores/theme/theme_store.dart
new file mode 100644
index 00000000..0f908742
--- /dev/null
+++ b/lib/stores/theme/theme_store.dart
@@ -0,0 +1,53 @@
+import 'package:boilerplate/data/repository.dart';
+import 'package:boilerplate/stores/error/error_store.dart';
+import 'package:flutter/material.dart';
+import 'package:mobx/mobx.dart';
+
+part 'theme_store.g.dart';
+
+class ThemeStore = _ThemeStore with _$ThemeStore;
+
+abstract class _ThemeStore with Store {
+ final String TAG = "_ThemeStore";
+
+ // repository instance
+ final Repository _repository;
+
+ // store for handling errors
+ final ErrorStore errorStore = ErrorStore();
+
+ // store variables:-----------------------------------------------------------
+ @observable
+ bool _darkMode = false;
+
+
+ // getters:-------------------------------------------------------------------
+ bool get darkMode => _darkMode;
+
+ // constructor:---------------------------------------------------------------
+ _ThemeStore(Repository repository)
+ : this._repository = repository {
+ init();
+ }
+
+ // actions:-------------------------------------------------------------------
+ @action
+ Future changeBrightnessToDark(bool value) async {
+ _darkMode = value;
+ await _repository.changeBrightnessToDark(value);
+ }
+
+ // general methods:-----------------------------------------------------------
+ Future init() async {
+ _darkMode = _repository.isDarkMode;
+ }
+
+ bool isPlatformDark(BuildContext context) =>
+ MediaQuery.platformBrightnessOf(context) == Brightness.dark;
+
+ // dispose:-------------------------------------------------------------------
+ @override
+ dispose() {
+
+ }
+}
diff --git a/lib/stores/user/user_store.dart b/lib/stores/user/user_store.dart
new file mode 100644
index 00000000..cd419712
--- /dev/null
+++ b/lib/stores/user/user_store.dart
@@ -0,0 +1,92 @@
+import 'package:boilerplate/stores/error/error_store.dart';
+import 'package:mobx/mobx.dart';
+
+import '../../data/repository.dart';
+import '../form/form_store.dart';
+
+part 'user_store.g.dart';
+
+class UserStore = _UserStore with _$UserStore;
+
+abstract class _UserStore with Store {
+ // repository instance
+ final Repository _repository;
+
+ // store for handling form errors
+ final FormErrorStore formErrorStore = FormErrorStore();
+
+ // store for handling error messages
+ final ErrorStore errorStore = ErrorStore();
+
+ // bool to check if current user is logged in
+ bool isLoggedIn = false;
+
+ // constructor:---------------------------------------------------------------
+ _UserStore(Repository repository) : this._repository = repository {
+
+ // setting up disposers
+ _setupDisposers();
+
+ // checking if user is logged in
+ repository.isLoggedIn.then((value) {
+ this.isLoggedIn = value;
+ });
+ }
+
+ // disposers:-----------------------------------------------------------------
+ late List _disposers;
+
+ void _setupDisposers() {
+ _disposers = [
+ reaction((_) => success, (_) => success = false, delay: 200),
+ ];
+ }
+
+ // empty responses:-----------------------------------------------------------
+ static ObservableFuture emptyLoginResponse =
+ ObservableFuture.value(false);
+
+ // store variables:-----------------------------------------------------------
+ @observable
+ bool success = false;
+
+ @observable
+ ObservableFuture loginFuture = emptyLoginResponse;
+
+ @computed
+ bool get isLoading => loginFuture.status == FutureStatus.pending;
+
+ // actions:-------------------------------------------------------------------
+ @action
+ Future login(String email, String password) async {
+
+ final future = _repository.login(email, password);
+ loginFuture = ObservableFuture(future);
+ await future.then((value) async {
+ if (value) {
+ _repository.saveIsLoggedIn(true);
+ this.isLoggedIn = true;
+ this.success = true;
+ } else {
+ print('failed to login');
+ }
+ }).catchError((e) {
+ print(e);
+ this.isLoggedIn = false;
+ this.success = false;
+ throw e;
+ });
+ }
+
+ logout() {
+ this.isLoggedIn = false;
+ _repository.saveIsLoggedIn(false);
+ }
+
+ // general methods:-----------------------------------------------------------
+ void dispose() {
+ for (final d in _disposers) {
+ d();
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/ui/home/home.dart b/lib/ui/home/home.dart
new file mode 100644
index 00000000..1c5eb600
--- /dev/null
+++ b/lib/ui/home/home.dart
@@ -0,0 +1,249 @@
+import 'package:another_flushbar/flushbar_helper.dart';
+import 'package:boilerplate/data/sharedpref/constants/preferences.dart';
+import 'package:boilerplate/utils/routes/routes.dart';
+import 'package:boilerplate/stores/language/language_store.dart';
+import 'package:boilerplate/stores/post/post_store.dart';
+import 'package:boilerplate/stores/theme/theme_store.dart';
+import 'package:boilerplate/utils/locale/app_localization.dart';
+import 'package:boilerplate/widgets/progress_indicator_widget.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_mobx/flutter_mobx.dart';
+import 'package:material_dialog/material_dialog.dart';
+import 'package:provider/provider.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+class HomeScreen extends StatefulWidget {
+ @override
+ _HomeScreenState createState() => _HomeScreenState();
+}
+
+class _HomeScreenState extends State {
+ //stores:---------------------------------------------------------------------
+ late PostStore _postStore;
+ late ThemeStore _themeStore;
+ late LanguageStore _languageStore;
+
+ @override
+ void initState() {
+ super.initState();
+ }
+
+ @override
+ void didChangeDependencies() {
+ super.didChangeDependencies();
+
+ // initializing stores
+ _languageStore = Provider.of(context);
+ _themeStore = Provider.of(context);
+ _postStore = Provider.of(context);
+
+ // check to see if already called api
+ if (!_postStore.loading) {
+ _postStore.getPosts();
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: _buildAppBar(),
+ body: _buildBody(),
+ );
+ }
+
+ // app bar methods:-----------------------------------------------------------
+ PreferredSizeWidget _buildAppBar() {
+ return AppBar(
+ title: Text(AppLocalizations.of(context).translate('home_tv_posts')),
+ actions: _buildActions(context),
+ );
+ }
+
+ List _buildActions(BuildContext context) {
+ return [
+ _buildLanguageButton(),
+ _buildThemeButton(),
+ _buildLogoutButton(),
+ ];
+ }
+
+ Widget _buildThemeButton() {
+ return Observer(
+ builder: (context) {
+ return IconButton(
+ onPressed: () {
+ _themeStore.changeBrightnessToDark(!_themeStore.darkMode);
+ },
+ icon: Icon(
+ _themeStore.darkMode ? Icons.brightness_5 : Icons.brightness_3,
+ ),
+ );
+ },
+ );
+ }
+
+ Widget _buildLogoutButton() {
+ return IconButton(
+ onPressed: () {
+ SharedPreferences.getInstance().then((preference) {
+ preference.setBool(Preferences.is_logged_in, false);
+ Navigator.of(context).pushReplacementNamed(Routes.login);
+ });
+ },
+ icon: Icon(
+ Icons.power_settings_new,
+ ),
+ );
+ }
+
+ Widget _buildLanguageButton() {
+ return IconButton(
+ onPressed: () {
+ _buildLanguageDialog();
+ },
+ icon: Icon(
+ Icons.language,
+ ),
+ );
+ }
+
+ // body methods:--------------------------------------------------------------
+ Widget _buildBody() {
+ return Stack(
+ children: [
+ _handleErrorMessage(),
+ _buildMainContent(),
+ ],
+ );
+ }
+
+ Widget _buildMainContent() {
+ return Observer(
+ builder: (context) {
+ return _postStore.loading
+ ? CustomProgressIndicatorWidget()
+ : Material(child: _buildListView());
+ },
+ );
+ }
+
+ Widget _buildListView() {
+ return _postStore.postList != null
+ ? ListView.separated(
+ itemCount: _postStore.postList!.posts!.length,
+ separatorBuilder: (context, position) {
+ return Divider();
+ },
+ itemBuilder: (context, position) {
+ return _buildListItem(position);
+ },
+ )
+ : Center(
+ child: Text(
+ AppLocalizations.of(context).translate('home_tv_no_post_found'),
+ ),
+ );
+ }
+
+ Widget _buildListItem(int position) {
+ return ListTile(
+ dense: true,
+ leading: Icon(Icons.cloud_circle),
+ title: Text(
+ '${_postStore.postList?.posts?[position].title}',
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ softWrap: false,
+ style: Theme.of(context).textTheme.subtitle1,
+ ),
+ subtitle: Text(
+ '${_postStore.postList?.posts?[position].body}',
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ softWrap: false,
+ ),
+ );
+ }
+
+ Widget _handleErrorMessage() {
+ return Observer(
+ builder: (context) {
+ if (_postStore.errorStore.errorMessage.isNotEmpty) {
+ return _showErrorMessage(_postStore.errorStore.errorMessage);
+ }
+
+ return SizedBox.shrink();
+ },
+ );
+ }
+
+ // General Methods:-----------------------------------------------------------
+ _showErrorMessage(String message) {
+ Future.delayed(Duration(milliseconds: 0), () {
+ if (message.isNotEmpty) {
+ FlushbarHelper.createError(
+ message: message,
+ title: AppLocalizations.of(context).translate('home_tv_error'),
+ duration: Duration(seconds: 3),
+ )..show(context);
+ }
+ });
+
+ return SizedBox.shrink();
+ }
+
+_buildLanguageDialog() {
+ _showDialog(
+ context: context,
+ child: MaterialDialog(
+ borderRadius: 5.0,
+ enableFullWidth: true,
+ title: Text(
+ AppLocalizations.of(context).translate('home_tv_choose_language'),
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 16.0,
+ ),
+ ),
+ headerColor: Theme.of(context).primaryColor,
+ backgroundColor: Theme.of(context).scaffoldBackgroundColor,
+ closeButtonColor: Colors.white,
+ enableCloseButton: true,
+ enableBackButton: false,
+ onCloseButtonClicked: () {
+ Navigator.of(context).pop();
+ },
+ children: _languageStore.supportedLanguages
+ .map(
+ (object) => ListTile(
+ dense: true,
+ contentPadding: EdgeInsets.all(0.0),
+ title: Text(
+ object.language!,
+ style: TextStyle(
+ color: _languageStore.locale == object.locale
+ ? Theme.of(context).primaryColor
+ : _themeStore.darkMode ? Colors.white : Colors.black,
+ ),
+ ),
+ onTap: () {
+ Navigator.of(context).pop();
+ // change user language based on selected locale
+ _languageStore.changeLanguage(object.locale!);
+ },
+ ),
+ )
+ .toList(),
+ ),
+ );
+}
+
+ _showDialog({required BuildContext context, required Widget child}) {
+ showDialog(
+ context: context,
+ builder: (BuildContext context) => child,
+ ).then((T? value) {
+ // The value passed to Navigator.pop() or null.
+ });
+ }
+}
diff --git a/lib/ui/login/login.dart b/lib/ui/login/login.dart
new file mode 100644
index 00000000..22e37a1c
--- /dev/null
+++ b/lib/ui/login/login.dart
@@ -0,0 +1,244 @@
+import 'package:another_flushbar/flushbar_helper.dart';
+import 'package:boilerplate/constants/assets.dart';
+import 'package:boilerplate/data/sharedpref/constants/preferences.dart';
+import 'package:boilerplate/utils/routes/routes.dart';
+import 'package:boilerplate/stores/form/form_store.dart';
+import 'package:boilerplate/stores/theme/theme_store.dart';
+import 'package:boilerplate/utils/device/device_utils.dart';
+import 'package:boilerplate/utils/locale/app_localization.dart';
+import 'package:boilerplate/widgets/app_icon_widget.dart';
+import 'package:boilerplate/widgets/empty_app_bar_widget.dart';
+import 'package:boilerplate/widgets/progress_indicator_widget.dart';
+import 'package:boilerplate/widgets/rounded_button_widget.dart';
+import 'package:boilerplate/widgets/textfield_widget.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_mobx/flutter_mobx.dart';
+import 'package:provider/provider.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+class LoginScreen extends StatefulWidget {
+ @override
+ _LoginScreenState createState() => _LoginScreenState();
+}
+
+class _LoginScreenState extends State {
+ //text controllers:-----------------------------------------------------------
+ TextEditingController _userEmailController = TextEditingController();
+ TextEditingController _passwordController = TextEditingController();
+
+ //stores:---------------------------------------------------------------------
+ late ThemeStore _themeStore;
+
+ //focus node:-----------------------------------------------------------------
+ late FocusNode _passwordFocusNode;
+
+ //stores:---------------------------------------------------------------------
+ final _store = FormStore();
+
+ @override
+ void initState() {
+ super.initState();
+ _passwordFocusNode = FocusNode();
+ }
+
+ @override
+ void didChangeDependencies() {
+ super.didChangeDependencies();
+ _themeStore = Provider.of(context);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ primary: true,
+ appBar: EmptyAppBar(),
+ body: _buildBody(),
+ );
+ }
+
+ // body methods:--------------------------------------------------------------
+ Widget _buildBody() {
+ return Material(
+ child: Stack(
+ children: [
+ MediaQuery.of(context).orientation == Orientation.landscape
+ ? Row(
+ children: [
+ Expanded(
+ flex: 1,
+ child: _buildLeftSide(),
+ ),
+ Expanded(
+ flex: 1,
+ child: _buildRightSide(),
+ ),
+ ],
+ )
+ : Center(child: _buildRightSide()),
+ Observer(
+ builder: (context) {
+ return _store.success
+ ? navigate(context)
+ : _showErrorMessage(_store.errorStore.errorMessage);
+ },
+ ),
+ Observer(
+ builder: (context) {
+ return Visibility(
+ visible: _store.loading,
+ child: CustomProgressIndicatorWidget(),
+ );
+ },
+ )
+ ],
+ ),
+ );
+ }
+
+ Widget _buildLeftSide() {
+ return SizedBox.expand(
+ child: Image.asset(
+ Assets.carBackground,
+ fit: BoxFit.cover,
+ ),
+ );
+ }
+
+ Widget _buildRightSide() {
+ return SingleChildScrollView(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 24.0),
+ child: Column(
+ mainAxisSize: MainAxisSize.max,
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ AppIconWidget(image: 'assets/icons/ic_appicon.png'),
+ SizedBox(height: 24.0),
+ _buildUserIdField(),
+ _buildPasswordField(),
+ _buildForgotPasswordButton(),
+ _buildSignInButton()
+ ],
+ ),
+ ),
+ );
+ }
+
+ Widget _buildUserIdField() {
+ return Observer(
+ builder: (context) {
+ return TextFieldWidget(
+ hint: AppLocalizations.of(context).translate('login_et_user_email'),
+ inputType: TextInputType.emailAddress,
+ icon: Icons.person,
+ iconColor: _themeStore.darkMode ? Colors.white70 : Colors.black54,
+ textController: _userEmailController,
+ inputAction: TextInputAction.next,
+ autoFocus: false,
+ onChanged: (value) {
+ _store.setUserId(_userEmailController.text);
+ },
+ onFieldSubmitted: (value) {
+ FocusScope.of(context).requestFocus(_passwordFocusNode);
+ },
+ errorText: _store.formErrorStore.userEmail,
+ );
+ },
+ );
+ }
+
+ Widget _buildPasswordField() {
+ return Observer(
+ builder: (context) {
+ return TextFieldWidget(
+ hint:
+ AppLocalizations.of(context).translate('login_et_user_password'),
+ isObscure: true,
+ padding: EdgeInsets.only(top: 16.0),
+ icon: Icons.lock,
+ iconColor: _themeStore.darkMode ? Colors.white70 : Colors.black54,
+ textController: _passwordController,
+ focusNode: _passwordFocusNode,
+ errorText: _store.formErrorStore.password,
+ onChanged: (value) {
+ _store.setPassword(_passwordController.text);
+ },
+ );
+ },
+ );
+ }
+
+ Widget _buildForgotPasswordButton() {
+ return Align(
+ alignment: FractionalOffset.centerRight,
+ child: FlatButton(
+ padding: EdgeInsets.all(0.0),
+ child: Text(
+ AppLocalizations.of(context).translate('login_btn_forgot_password'),
+ style: Theme.of(context)
+ .textTheme
+ .caption
+ ?.copyWith(color: Colors.orangeAccent),
+ ),
+ onPressed: () {},
+ ),
+ );
+ }
+
+ Widget _buildSignInButton() {
+ return RoundedButtonWidget(
+ buttonText: AppLocalizations.of(context).translate('login_btn_sign_in'),
+ buttonColor: Colors.orangeAccent,
+ textColor: Colors.white,
+ onPressed: () async {
+ if (_store.canLogin) {
+ DeviceUtils.hideKeyboard(context);
+ _store.login();
+ } else {
+ _showErrorMessage('Please fill in all fields');
+ }
+ },
+ );
+ }
+
+ Widget navigate(BuildContext context) {
+ SharedPreferences.getInstance().then((prefs) {
+ prefs.setBool(Preferences.is_logged_in, true);
+ });
+
+ Future.delayed(Duration(milliseconds: 0), () {
+ Navigator.of(context).pushNamedAndRemoveUntil(
+ Routes.home, (Route route) => false);
+ });
+
+ return Container();
+ }
+
+ // General Methods:-----------------------------------------------------------
+ _showErrorMessage(String message) {
+ if (message.isNotEmpty) {
+ Future.delayed(Duration(milliseconds: 0), () {
+ if (message.isNotEmpty) {
+ FlushbarHelper.createError(
+ message: message,
+ title: AppLocalizations.of(context).translate('home_tv_error'),
+ duration: Duration(seconds: 3),
+ )..show(context);
+ }
+ });
+ }
+
+ return SizedBox.shrink();
+ }
+
+ // dispose:-------------------------------------------------------------------
+ @override
+ void dispose() {
+ // Clean up the controller when the Widget is removed from the Widget tree
+ _userEmailController.dispose();
+ _passwordController.dispose();
+ _passwordFocusNode.dispose();
+ super.dispose();
+ }
+}
diff --git a/lib/ui/my_app.dart b/lib/ui/my_app.dart
new file mode 100644
index 00000000..b9d4f25b
--- /dev/null
+++ b/lib/ui/my_app.dart
@@ -0,0 +1,65 @@
+import 'package:boilerplate/constants/app_theme.dart';
+import 'package:boilerplate/constants/strings.dart';
+import 'package:boilerplate/data/repository.dart';
+import 'package:boilerplate/di/components/service_locator.dart';
+import 'package:boilerplate/stores/language/language_store.dart';
+import 'package:boilerplate/stores/post/post_store.dart';
+import 'package:boilerplate/stores/theme/theme_store.dart';
+import 'package:boilerplate/stores/user/user_store.dart';
+import 'package:boilerplate/ui/home/home.dart';
+import 'package:boilerplate/ui/login/login.dart';
+import 'package:boilerplate/utils/locale/app_localization.dart';
+import 'package:boilerplate/utils/routes/routes.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_localizations/flutter_localizations.dart';
+import 'package:flutter_mobx/flutter_mobx.dart';
+import 'package:provider/provider.dart';
+
+class MyApp extends StatelessWidget {
+ // This widget is the root of your application.
+ // Create your store as a final variable in a base Widget. This works better
+ // with Hot Reload than creating it directly in the `build` function.
+ final ThemeStore _themeStore = ThemeStore(getIt());
+ final PostStore _postStore = PostStore(getIt());
+ final LanguageStore _languageStore = LanguageStore(getIt());
+ final UserStore _userStore = UserStore(getIt());
+
+ @override
+ Widget build(BuildContext context) {
+ return MultiProvider(
+ providers: [
+ Provider(create: (_) => _themeStore),
+ Provider(create: (_) => _postStore),
+ Provider(create: (_) => _languageStore),
+ ],
+ child: Observer(
+ name: 'global-observer',
+ builder: (context) {
+ return MaterialApp(
+ debugShowCheckedModeBanner: false,
+ title: Strings.appName,
+ theme: _themeStore.darkMode
+ ? AppThemeData.darkThemeData
+ : AppThemeData.lightThemeData,
+ routes: Routes.routes,
+ locale: Locale(_languageStore.locale),
+ supportedLocales: _languageStore.supportedLanguages
+ .map((language) => Locale(language.locale!, language.code))
+ .toList(),
+ localizationsDelegates: [
+ // A class which loads the translations from JSON files
+ AppLocalizations.delegate,
+ // Built-in localization of basic text for Material widgets
+ GlobalMaterialLocalizations.delegate,
+ // Built-in localization for text direction LTR/RTL
+ GlobalWidgetsLocalizations.delegate,
+ // Built-in localization of basic text for Cupertino widgets
+ GlobalCupertinoLocalizations.delegate,
+ ],
+ home: _userStore.isLoggedIn ? HomeScreen() : LoginScreen(),
+ );
+ },
+ ),
+ );
+ }
+}
diff --git a/lib/ui/splash/splash.dart b/lib/ui/splash/splash.dart
new file mode 100644
index 00000000..4679e14b
--- /dev/null
+++ b/lib/ui/splash/splash.dart
@@ -0,0 +1,44 @@
+import 'dart:async';
+
+import 'package:boilerplate/constants/assets.dart';
+import 'package:boilerplate/data/sharedpref/constants/preferences.dart';
+import 'package:boilerplate/utils/routes/routes.dart';
+import 'package:boilerplate/widgets/app_icon_widget.dart';
+import 'package:flutter/material.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+class SplashScreen extends StatefulWidget {
+ @override
+ State createState() => _SplashScreenState();
+}
+
+class _SplashScreenState extends State {
+ @override
+ void initState() {
+ super.initState();
+ startTimer();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+
+ return Material(
+ child: Center(child: AppIconWidget(image: Assets.appLogo)),
+ );
+ }
+
+ startTimer() {
+ var _duration = Duration(milliseconds: 2000);
+ return Timer(_duration, navigate);
+ }
+
+ navigate() async {
+ SharedPreferences preferences = await SharedPreferences.getInstance();
+
+ if (preferences.getBool(Preferences.is_logged_in) ?? false) {
+ Navigator.of(context).pushReplacementNamed(Routes.home);
+ } else {
+ Navigator.of(context).pushReplacementNamed(Routes.login);
+ }
+ }
+}
diff --git a/lib/utils/device/device_utils.dart b/lib/utils/device/device_utils.dart
new file mode 100644
index 00000000..d3a58d1e
--- /dev/null
+++ b/lib/utils/device/device_utils.dart
@@ -0,0 +1,38 @@
+//
+import 'package:flutter/material.dart';
+
+/// Helper class for device related operations.
+///
+class DeviceUtils {
+
+ ///
+ /// hides the keyboard if its already open
+ ///
+ static hideKeyboard(BuildContext context) {
+ FocusScope.of(context).unfocus();
+ }
+
+ ///
+ /// accepts a double [scale] and returns scaled sized based on the screen
+ /// orientation
+ ///
+ static double getScaledSize(BuildContext context, double scale) =>
+ scale *
+ (MediaQuery.of(context).orientation == Orientation.portrait
+ ? MediaQuery.of(context).size.width
+ : MediaQuery.of(context).size.height);
+
+ ///
+ /// accepts a double [scale] and returns scaled sized based on the screen
+ /// width
+ ///
+ static double getScaledWidth(BuildContext context, double scale) =>
+ scale * MediaQuery.of(context).size.width;
+
+ ///
+ /// accepts a double [scale] and returns scaled sized based on the screen
+ /// height
+ ///
+ static double getScaledHeight(BuildContext context, double scale) =>
+ scale * MediaQuery.of(context).size.height;
+}
\ No newline at end of file
diff --git a/lib/utils/dio/dio_error_util.dart b/lib/utils/dio/dio_error_util.dart
new file mode 100644
index 00000000..fbd08812
--- /dev/null
+++ b/lib/utils/dio/dio_error_util.dart
@@ -0,0 +1,35 @@
+import 'package:dio/dio.dart';
+
+class DioErrorUtil {
+ // general methods:------------------------------------------------------------
+ static String handleError(DioError error) {
+ String errorDescription = "";
+ if (error is DioError) {
+ switch (error.type) {
+ case DioErrorType.cancel:
+ errorDescription = "Request to API server was cancelled";
+ break;
+ case DioErrorType.connectTimeout:
+ errorDescription = "Connection timeout with API server";
+ break;
+ case DioErrorType.other:
+ errorDescription =
+ "Connection to API server failed due to internet connection";
+ break;
+ case DioErrorType.receiveTimeout:
+ errorDescription = "Receive timeout in connection with API server";
+ break;
+ case DioErrorType.response:
+ errorDescription =
+ "Received invalid status code: ${error.response?.statusCode}";
+ break;
+ case DioErrorType.sendTimeout:
+ errorDescription = "Send timeout in connection with API server";
+ break;
+ }
+ } else {
+ errorDescription = "Unexpected error occured";
+ }
+ return errorDescription;
+ }
+}
\ No newline at end of file
diff --git a/lib/utils/encryption/xxtea.dart b/lib/utils/encryption/xxtea.dart
new file mode 100644
index 00000000..184e5858
--- /dev/null
+++ b/lib/utils/encryption/xxtea.dart
@@ -0,0 +1,63 @@
+import 'dart:convert';
+
+import 'package:sembast/sembast.dart';
+import 'package:xxtea/xxtea.dart';
+
+class _XXTeaEncoder extends Converter