diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 93549e1..1b41817 100755 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.5.12+4\\\\","dependencies":[]}],"android":[{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.5.12+4\\\\","dependencies":[]}],"macos":[{"name":"shared_preferences_macos","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_macos-0.0.1+11\\\\","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_linux-0.0.1+2\\\\","dependencies":[]},{"name":"shared_preferences_linux","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_linux-0.0.2+4\\\\","dependencies":["path_provider_linux"]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_windows-0.0.4+3\\\\","dependencies":[]},{"name":"shared_preferences_windows","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_windows-0.0.1+3\\\\","dependencies":["path_provider_windows"]}],"web":[{"name":"shared_preferences_web","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_web-0.1.2+7\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_linux","shared_preferences_macos","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_macos","dependencies":[]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2020-12-27 13:03:34.505515","version":"1.22.5"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\device_info-2.0.1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-2.0.5\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"android":[{"name":"device_info","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\device_info-2.0.1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-2.0.5\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_macos-2.0.0\\\\","dependencies":[]},{"name":"shared_preferences_macos","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_macos-2.0.0\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.0+3\\\\","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_linux-2.0.0\\\\","dependencies":[]},{"name":"shared_preferences_linux","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_linux-2.0.0\\\\","dependencies":["path_provider_linux"]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_windows-2.0.1\\\\","dependencies":[]},{"name":"shared_preferences_windows","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_windows-2.0.0\\\\","dependencies":["path_provider_windows"]}],"web":[{"name":"shared_preferences_web","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_web-2.0.0\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"device_info","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_linux","shared_preferences_macos","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_macos","dependencies":[]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"sqflite","dependencies":[]}],"date_created":"2021-05-30 12:59:36.529653","version":"2.2.0"} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9d532b1..0fa6b67 100755 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,8 @@ app.*.symbols # Obfuscation related app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/.metadata b/.metadata index 107fcb7..54ec0a8 100755 --- a/.metadata +++ b/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: 8874f21e79d7ec66d0457c7ab338348e31b17f1d + revision: b22742018b3edf16c6cadd7b76d9db5e7f9064b5 channel: stable project_type: app diff --git a/README.md b/README.md index 2fd5f49..ac17718 100755 --- a/README.md +++ b/README.md @@ -1,31 +1,16 @@ -# Odoo Mobile Framework With Flutter -Odoo Mobile framework with flutter +# odoo_common_code_latest -This Project Supports **Odoo 10.0, 11.0, 12.0 Community and Enterprise Edition**. It may not work properly against older versions of Odoo. +A new Flutter project. -# Supported Platforms - -> Android - -> iOS - -# MIT License +## Getting Started -Copyright (c) 2019 Mustafa Lokhandwala +This project is a starting point for a Flutter application. -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: +A few resources to get you started if this is your first Flutter project: -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. +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/app/build.gradle b/android/app/build.gradle index b5e4a96..e6a398a 100755 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,21 +26,17 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 29 + compileSdkVersion 30 sourceSets { main.java.srcDirs += 'src/main/kotlin' } - lintOptions { - disable 'InvalidPackage' - } - defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.mtfa.odoo_json_rpc_flutter" - minSdkVersion 16 - targetSdkVersion 29 + applicationId "com.mtfa.odooclient" + minSdkVersion 21 + targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 219d082..0984306 100755 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="com.mtfa.odooclient"> diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 04876e1..f0e5a0c 100755 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,41 +1,34 @@ - + package="com.mtfa.odooclient"> + + android:icon="@mipmap/ic_launcher" + android:label="Odoo Mobile"> + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme" /> + android:name="io.flutter.embedding.android.SplashScreenDrawable" + android:resource="@drawable/launch_background" /> - - + + + + + + + + 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 0000000..449a9f9 --- /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 index 1f83a33..d74aa35 100755 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -1,7 +1,7 @@ - - diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index 219d082..e7a5201 100755 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="com.mtfa.odooclient.odoo_common_code_latest"> diff --git a/android/build.gradle b/android/build.gradle index 3100ad2..9b6ed06 100755 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:4.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -21,8 +21,6 @@ allprojects { rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { project.evaluationDependsOn(':app') } diff --git a/android/gradle.properties b/android/gradle.properties index a673820..94adc3a 100755 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,3 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true -android.enableR8=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 296b146..bc6a58a 100755 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/assets/fonts/Roboto-Black.ttf b/assets/fonts/Roboto-Black.ttf new file mode 100644 index 0000000..2d45238 Binary files /dev/null and b/assets/fonts/Roboto-Black.ttf differ diff --git a/assets/fonts/Roboto-BlackItalic.ttf b/assets/fonts/Roboto-BlackItalic.ttf new file mode 100644 index 0000000..29a4359 Binary files /dev/null and b/assets/fonts/Roboto-BlackItalic.ttf differ diff --git a/assets/fonts/Roboto-Bold.ttf b/assets/fonts/Roboto-Bold.ttf new file mode 100644 index 0000000..d998cf5 Binary files /dev/null and b/assets/fonts/Roboto-Bold.ttf differ diff --git a/assets/fonts/Roboto-BoldItalic.ttf b/assets/fonts/Roboto-BoldItalic.ttf new file mode 100644 index 0000000..b4e2210 Binary files /dev/null and b/assets/fonts/Roboto-BoldItalic.ttf differ diff --git a/assets/fonts/Roboto-Italic.ttf b/assets/fonts/Roboto-Italic.ttf new file mode 100644 index 0000000..5b390ff Binary files /dev/null and b/assets/fonts/Roboto-Italic.ttf differ diff --git a/assets/fonts/Roboto-Light.ttf b/assets/fonts/Roboto-Light.ttf new file mode 100644 index 0000000..3526798 Binary files /dev/null and b/assets/fonts/Roboto-Light.ttf differ diff --git a/assets/fonts/Roboto-LightItalic.ttf b/assets/fonts/Roboto-LightItalic.ttf new file mode 100644 index 0000000..46e9bf7 Binary files /dev/null and b/assets/fonts/Roboto-LightItalic.ttf differ diff --git a/assets/fonts/Roboto-Medium.ttf b/assets/fonts/Roboto-Medium.ttf new file mode 100644 index 0000000..f714a51 Binary files /dev/null and b/assets/fonts/Roboto-Medium.ttf differ diff --git a/assets/fonts/Roboto-MediumItalic.ttf b/assets/fonts/Roboto-MediumItalic.ttf new file mode 100644 index 0000000..5dc6a2d Binary files /dev/null and b/assets/fonts/Roboto-MediumItalic.ttf differ diff --git a/assets/fonts/Roboto-Regular.ttf b/assets/fonts/Roboto-Regular.ttf new file mode 100644 index 0000000..2b6392f Binary files /dev/null and b/assets/fonts/Roboto-Regular.ttf differ diff --git a/assets/fonts/Roboto-Thin.ttf b/assets/fonts/Roboto-Thin.ttf new file mode 100644 index 0000000..4e797cf Binary files /dev/null and b/assets/fonts/Roboto-Thin.ttf differ diff --git a/assets/fonts/Roboto-ThinItalic.ttf b/assets/fonts/Roboto-ThinItalic.ttf new file mode 100644 index 0000000..eea836f Binary files /dev/null and b/assets/fonts/Roboto-ThinItalic.ttf differ diff --git a/assets/images/2.0x/back_arrow.png b/assets/images/2.0x/back_arrow.png new file mode 100644 index 0000000..b8c2aa3 Binary files /dev/null and b/assets/images/2.0x/back_arrow.png differ diff --git a/assets/images/3.0x/back_arrow.png b/assets/images/3.0x/back_arrow.png new file mode 100644 index 0000000..f55d79c Binary files /dev/null and b/assets/images/3.0x/back_arrow.png differ diff --git a/assets/images/back_arrow.png b/assets/images/back_arrow.png new file mode 100644 index 0000000..146f544 Binary files /dev/null and b/assets/images/back_arrow.png differ diff --git a/ios/.gitignore b/ios/.gitignore index e96ef60..151026b 100644 --- a/ios/.gitignore +++ b/ios/.gitignore @@ -18,6 +18,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index f2872cf..9367d48 100755 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 9.0 + 8.0 diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh index be9b4c0..43067cc 100755 --- a/ios/Flutter/flutter_export_environment.sh +++ b/ios/Flutter/flutter_export_environment.sh @@ -1,12 +1,11 @@ #!/bin/sh # This is a generated file; do not edit or check into version control. export "FLUTTER_ROOT=C:\src\flutter" -export "FLUTTER_APPLICATION_PATH=E:\Work\Flutter\Odoo-JsonRpc-with-Flutter" +export "FLUTTER_APPLICATION_PATH=F:\Work\Flutter Work\odoo_common_code_latest" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" export "FLUTTER_TARGET=lib\main.dart" export "FLUTTER_BUILD_DIR=build" export "SYMROOT=${SOURCE_ROOT}/../build\ios" -export "OTHER_LDFLAGS=$(inherited) -framework Flutter" -export "FLUTTER_FRAMEWORK_DIR=C:\src\flutter\bin\cache\artifacts\engine\ios" export "FLUTTER_BUILD_NAME=1.0.0" export "FLUTTER_BUILD_NUMBER=1" export "DART_OBFUSCATION=false" diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8141bb4..8122145 100755 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -289,17 +289,9 @@ CLANG_ENABLE_MODULES = YES; 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.mtfa.odooJsonRpcFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.mtfa.odooclient.odooCommonCodeLatest; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -421,17 +413,9 @@ CLANG_ENABLE_MODULES = YES; 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.mtfa.odooJsonRpcFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.mtfa.odooclient.odooCommonCodeLatest; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -448,17 +432,9 @@ CLANG_ENABLE_MODULES = YES; 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.mtfa.odooJsonRpcFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.mtfa.odooclient.odooCommonCodeLatest; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a1..919434a 100755 --- a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index a5de35c..10b11c0 100755 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -11,7 +11,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - odoo_json_rpc_flutter + odoo_common_code_latest CFBundlePackageType APPL CFBundleShortVersionString diff --git a/lib/app/data/pojo/partners.dart b/lib/app/data/pojo/partners.dart deleted file mode 100755 index 94790cf..0000000 --- a/lib/app/data/pojo/partners.dart +++ /dev/null @@ -1,16 +0,0 @@ -class Partner { - int id; - String name; - String imageUrl; - String email; - String phone; - String address; - - Partner( - {this.id, - this.name, - this.imageUrl, - this.email, - this.phone, - this.address}); -} diff --git a/lib/app/data/pojo/user.dart b/lib/app/data/pojo/user.dart deleted file mode 100755 index 4547c3d..0000000 --- a/lib/app/data/pojo/user.dart +++ /dev/null @@ -1,117 +0,0 @@ -class User { - Result result; - - User({this.result}); - - User.fromJson(Map json) { - result = - json['result'] != null ? new Result.fromJson(json['result']) : null; - } - - Map toJson() { - final Map data = new Map(); - if (this.result != null) { - data['result'] = this.result.toJson(); - } - return data; - } -} - -class Result { - String sessionId; - int uid; - bool isAdmin; - UserContext userContext; - String db; - String serverVersion; - String name; - String username; - String partnerDisplayName; - int companyId; - int partnerId; - bool userCompanies; - String webBaseUrl; - bool odoobotInitialized; - - Result({ - this.sessionId, - this.uid, - this.isAdmin, - this.userContext, - this.db, - this.serverVersion, - this.name, - this.username, - this.partnerDisplayName, - this.companyId, - this.partnerId, - this.userCompanies, - this.webBaseUrl, - this.odoobotInitialized, - }); - - Result.fromJson(Map json) { - sessionId = json['session_id']; - uid = json['uid']; - isAdmin = json['is_admin']; - userContext = json['user_context'] != null - ? new UserContext.fromJson(json['user_context']) - : null; - db = json['db'] is! bool ? json['db'] : "N/A"; - serverVersion = - json['server_version'] is! bool ? json['server_version'] : "N/A"; - name = json['name'] is! bool ? json['name'] : "N/A"; - username = json['username'] is! bool ? json['username'] : "N/A"; - partnerDisplayName = json['partner_display_name'] is! bool - ? json['partner_display_name'] - : "N/A"; - companyId = json['company_id']; - partnerId = json['partner_id']; - userCompanies = json['user_companies']; - webBaseUrl = json['web.base.url'] is! bool ? json['web.base.url'] : "N/A"; - odoobotInitialized = json['odoobot_initialized']; - } - - Map toJson() { - final Map data = new Map(); - data['session_id'] = this.sessionId; - data['uid'] = this.uid; - data['is_admin'] = this.isAdmin; - if (this.userContext != null) { - data['user_context'] = this.userContext.toJson(); - } - data['db'] = this.db; - data['server_version'] = this.serverVersion; - data['name'] = this.name; - data['username'] = this.username; - data['partner_display_name'] = this.partnerDisplayName; - data['company_id'] = this.companyId; - data['partner_id'] = this.partnerId; - data['user_companies'] = this.userCompanies; - data['web.base.url'] = this.webBaseUrl; - data['odoobot_initialized'] = this.odoobotInitialized; - return data; - } -} - -class UserContext { - String lang; - String tz; - int uid; - - UserContext({this.lang, this.tz, this.uid}); - - UserContext.fromJson(Map json) { - lang = json['lang'] is! bool ? json['lang'] : "N/A"; - tz = json['tz'] is! bool ? json['tz'] : "N/A"; - uid = json['uid']; - } - - Map toJson() { - final Map data = new Map(); - data['lang'] = this.lang; - data['tz'] = this.tz; - data['uid'] = this.uid; - return data; - } -} diff --git a/lib/app/data/services/globals.dart b/lib/app/data/services/globals.dart deleted file mode 100755 index 616da34..0000000 --- a/lib/app/data/services/globals.dart +++ /dev/null @@ -1,6 +0,0 @@ -class Globals { - String loginPrefName = "loginPrefs"; - String url; - - Globals({this.url}); -} diff --git a/lib/app/data/services/odoo_api.dart b/lib/app/data/services/odoo_api.dart deleted file mode 100755 index 8049f98..0000000 --- a/lib/app/data/services/odoo_api.dart +++ /dev/null @@ -1,246 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:odoo_json_rpc_flutter/app/utility/constant.dart'; - -import 'package:uuid/uuid.dart'; -import 'odoo_response.dart'; -import 'odoo_version.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -class Odoo { - Odoo({String url}) { - _serverURL = url; - } - - http.Client _client = http.Client(); - String _serverURL; - Map _headers = {}; - OdooVersion version = new OdooVersion(); - String _sessionId; - int _uid; - - String createPath(String path) { - return _serverURL + path; - } - - setSessionId(String session_id) { - _sessionId = session_id; - } - - initOdoo() async { - SharedPreferences preferences = await SharedPreferences.getInstance(); - if (preferences.getString("UserPrefs") != null) { - var jsonPrefs = jsonDecode(preferences.getString("UserPrefs")); - _serverURL = jsonPrefs['url']; - authenticate( - jsonPrefs['username'], jsonPrefs['password'], jsonPrefs['db']); - } - } - - Future getSessionInfo() async { - var url = createPath("/web/session/get_session_info"); - return await callRequest(url, createPayload({})); - } - - Future destroy() async { - var url = createPath("/web/session/destroy"); - SharedPreferences prefs = await SharedPreferences.getInstance(); - final res = await callRequest(url, createPayload({})); - prefs.remove("session"); - return res; - } - - // Authenticate user - Future authenticate( - String username, String password, String database) async { - var url = createPath("/web/session/authenticate"); - var params = { - "db": database, - "login": username, - "password": password, - "context": {} - }; - final response = await callDbRequest(url, createPayload(params)); - return response; - } - - Future read(String model, List ids, List fields, - {dynamic kwargs, Map context}) async { - return await callKW(model, "read", [ids, fields], - kwargs: kwargs, context: context); - } - - Future searchRead( - String model, List domain, List fields, - {int offset = 0, int limit = 0, String order = ""}) async { - var url = createPath("/web/dataset/search_read"); - var params = { - "context": getContext(), - "domain": domain, - "fields": fields, - "limit": limit, - "model": model, - "offset": offset, - "sort": order - }; - return await callRequest(url, createPayload(params)); - } - - // Call any model method with arguments - Future callKW(String model, String method, List args, - {dynamic kwargs, Map context}) async { - kwargs = kwargs == null ? {} : kwargs; - context = context == null ? {} : context; - var url = createPath("/web/dataset/call_kw/" + model + "/" + method); - var params = { - "model": model, - "method": method, - "args": args, - "kwargs": kwargs, - "context": context - }; - return await callRequest(url, createPayload(params)); - } - - // Create new record for model - Future create(String model, Map values) async { - return await callKW(model, "create", [values]); - } - - // Write record with ids and values - Future write(String model, List ids, Map values) async { - return await callKW(model, "write", [ids, values]); - } - - // Remove record from system - Future unlink(String model, List ids) async { - return await callKW(model, "unlink", [ids]); - } - - // Call json controller - Future callController(String path, Map params) async { - return await callRequest(createPath(path), createPayload(params)); - } - - String getSessionId() { - return _sessionId; - } - - // connect to odoo and set version and databases - Future connect() async { - OdooVersion odooVersion = await getVersionInfo(); - return odooVersion; - } - - // get version of odoo - Future getVersionInfo() async { - var url = createPath("/web/webclient/version_info"); - final response = await callRequest(url, createPayload({})); - version = OdooVersion().parse(response); - return version; - } - - Future getDatabases() async { - var serverVersionNumber = await getVersionInfo(); - - if (serverVersionNumber.getMajorVersion() == null) { - version = await getVersionInfo(); - } - String url = getServerURL(); - var params = {}; - if (serverVersionNumber != null) { - if (serverVersionNumber.getMajorVersion() == 9) { - url = createPath("/jsonrpc"); - params["method"] = "list"; - params["service"] = "db"; - params["args"] = []; - } else if (serverVersionNumber.getMajorVersion() >= 10) { - url = createPath("/web/database/list"); - params["context"] = {}; - } else { - url = createPath("/web/database/get_list"); - params["context"] = {}; - } - } - final response = await callDbRequest(url, createPayload(params)); - return response; - } - - String getServerURL() { - return _serverURL; - } - - Map createPayload(Map params) { - return { - "id": new Uuid().v1(), - "jsonrpc": "2.0", - "method": "call", - "params": params, - }; - } - - Map getContext() { - return {"lang": "en_US", "tz": "Europe/Brussels", "uid": _uid}; - } - - Future callRequest(String url, Map payload) async { - var body = json.encode(payload); - SharedPreferences prefs = await SharedPreferences.getInstance(); - _headers["Content-type"] = "application/json; charset=UTF-8"; - _headers["Cookie"] = prefs.getString("session"); - print("------------------------------------------->>>"); - print("REQUEST: ${url}"); - print("------------------------------------------->>>"); - final response = await _client.post(url, body: body, headers: _headers); - _updateCookies(response); - print("<<<<============================================"); - print("RESPONSE: ${response.body}"); - print("<<<<============================================"); - return new OdooResponse(json.decode(response.body), response.statusCode); - } - - Future callDbRequest(String url, Map payload) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - var body = json.encode(payload); - _headers["Content-type"] = "application/json; charset=UTF-8"; - _headers["Cookie"] = prefs.getString("session"); - print("------------------------------------------->>>>"); - print("REQUEST: $url"); - print("------------------------------------------->>>>"); - final response = await _client.post(url, body: body, headers: _headers); - _updateCookies(response); - print("<<<<============================================"); - print("RESPONSE: ${response.body}"); - print("<<<<============================================"); - return response; - } - - _updateCookies(http.Response response) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - String rawCookie = response.headers['set-cookie']; - if (rawCookie != null) { - _headers['Cookie'] = rawCookie; - prefs.setString(Constants.SESSION, rawCookie); - } - } - - Future check() { - var url = createPath("/web/session/check"); - final res = callDbRequest(url, createPayload({})); - return res; - } - - Future hasRight(String model, List right) { - var url = createPath("/web/dataset/call_kw"); - var params = { - "model": model, - "method": "has_group", - "args": right, - "kwargs": {}, - "context": getContext() - }; - final res = callRequest(url, createPayload(params)); - return res; - } -} diff --git a/lib/app/data/services/utils.dart b/lib/app/data/services/utils.dart deleted file mode 100755 index d2d3068..0000000 --- a/lib/app/data/services/utils.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'package:flutter/material.dart'; -import 'dart:io'; - -class Utils { - Utils({this.context}); - - final BuildContext context; - bool _isNet = false; - - showMessage(String title, String message) { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext ctxt) { - return AlertDialog( - title: Text( - title, - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 22, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - ), - content: Text( - message, - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 18, - color: Colors.black, - ), - ), - actions: [ - FlatButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text( - "Ok", - style: TextStyle( - fontFamily: "Montserrat", - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ); - }, - ); - } - - Future isConnected() async { - try { - final result = await InternetAddress.lookup('google.com'); - if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) { - print('connected'); - return true; - } - } on SocketException catch (_) { - print('not connected'); - return false; - } - return false; - } - - bool isInNetwork() { - isConnected().then((bool val) { - _isNet = val; - }); - return _isNet; - } -} diff --git a/lib/app/pages/home.dart b/lib/app/pages/home.dart deleted file mode 100755 index 9c04c49..0000000 --- a/lib/app/pages/home.dart +++ /dev/null @@ -1,164 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:odoo_json_rpc_flutter/app/data/pojo/partners.dart'; -import 'package:odoo_json_rpc_flutter/app/data/services/odoo_response.dart'; -import 'package:odoo_json_rpc_flutter/app/pages/partner_details.dart'; -import 'package:odoo_json_rpc_flutter/app/utility/strings.dart'; -import 'package:odoo_json_rpc_flutter/base.dart'; - -import 'profile.dart'; -import 'settings.dart'; - -class Home extends StatefulWidget { - @override - _HomeState createState() => _HomeState(); -} - -class _HomeState extends Base { - //Odoo _odoo; - List _partners = []; - - _getPartners() async { - isConnected().then((isInternet) { - if (isInternet) { - showLoading(); - odoo.searchRead( - Strings.res_partner, [], ['email', 'name', 'phone']).then( - (OdooResponse res) { - if (!res.hasError()) { - setState(() { - hideLoading(); - String session = getSession(); - session = session.split(",")[0].split(";")[0]; - for (var i in res.getRecords()) { - _partners.add( - new Partner( - id: i["id"], - email: i["email"] is! bool ? i["email"] : "N/A", - name: i["name"], - phone: i["phone"] is! bool ? i["phone"] : "N/A", - imageUrl: getURL() + - "/web/image?model=res.partner&field=image&" + - session + - "&id=" + - i["id"].toString(), - ), - ); - } - }); - } else { - print(res.getError()); - showMessage("Warning", res.getErrorMessage()); - } - }, - ); - } - }); - } - - @override - void initState() { - super.initState(); - - getOdooInstance().then((odoo) { - _getPartners(); - }); - } - - @override - Widget build(BuildContext context) { - final emptyView = Container( - alignment: Alignment.center, - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Icon( - Icons.person_outline, - color: Colors.grey.shade300, - size: 100, - ), - Padding( - padding: EdgeInsets.all(1.0), - child: Text( - Strings.no_orders, - style: TextStyle( - color: Colors.grey.shade500, - fontSize: 20, - ), - ), - ) - ], - ), - ), - ); - - return Scaffold( - key: scaffoldKey, - appBar: AppBar( - title: Text("Home"), - actions: [ - IconButton( - icon: Icon( - Icons.settings, - color: Colors.white, - ), - onPressed: () { - push(Settings()); - }, - ), - IconButton( - icon: Icon( - Icons.person, - color: Colors.white, - ), - onPressed: () { - push(ProfilePage()); - }, - ), - ], - ), - body: _partners.length > 0 - ? ListView.builder( - itemCount: _partners.length, - physics: const AlwaysScrollableScrollPhysics(), - itemBuilder: (context, i) => InkWell( - onTap: () { - push(PartnerDetails(data: _partners[i])); - }, - child: Column( - children: [ - Divider( - height: 10.0, - ), - ListTile( - leading: CircleAvatar( - foregroundColor: Theme.of(context).primaryColor, - backgroundColor: Colors.grey, - backgroundImage: NetworkImage(_partners[i].imageUrl), - ), - title: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - _partners[i].name, - style: TextStyle(fontWeight: FontWeight.bold), - ), - ], - ), - subtitle: Container( - padding: const EdgeInsets.only(top: 5.0), - child: Text( - _partners[i].email, - style: TextStyle(color: Colors.grey, fontSize: 15.0), - ), - ), - ) - ], - ), - ), - ) - : emptyView, - ); - } -} diff --git a/lib/app/pages/login.dart b/lib/app/pages/login.dart deleted file mode 100755 index 1b323e9..0000000 --- a/lib/app/pages/login.dart +++ /dev/null @@ -1,347 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:odoo_json_rpc_flutter/app/data/pojo/user.dart'; -import 'package:odoo_json_rpc_flutter/app/data/services/odoo_api.dart'; -import 'package:odoo_json_rpc_flutter/app/pages/home.dart'; -import 'package:odoo_json_rpc_flutter/app/pages/settings.dart'; -import 'package:odoo_json_rpc_flutter/base.dart'; - -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; - -class Login extends StatefulWidget { - @override - _LoginState createState() => _LoginState(); -} - -class _LoginState extends Base { - String odooURL; - String _selectedProtocol = "http"; - String _selectedDb; - String _email; - String _pass; - List _dbList = []; - List dynamicList = []; - bool isCorrectURL = false; - bool isDBFilter = false; - TextEditingController _urlCtrler = new TextEditingController(); - TextEditingController _emailCtrler = new TextEditingController(); - TextEditingController _passCtrler = new TextEditingController(); - - _checkFirstTime() { - if (getURL() != null) { - odooURL = getURL(); - _checkURL(); - } - } - - _login() { - if (isValid()) { - isConnected().then((isInternet) { - if (isInternet) { - showLoading(); - odoo.authenticate(_email, _pass, _selectedDb).then( - (http.Response auth) { - if (auth.body != null) { - User user = User.fromJson(jsonDecode(auth.body)); - if (user != null && user.result != null) { - print(auth.body.toString()); - hideLoadingSuccess("Logged in successfully"); - saveUser(json.encode(user)); - saveOdooUrl(odooURL); - pushReplacement(Home()); - } else { - showMessage("Authentication Failed", - "Please Enter Valid Email or Password"); - } - } else { - showMessage("Authentication Failed", - "Please Enter Valid Email or Password"); - } - }, - ); - } - }); - } - } - - _checkURL() { - isConnected().then((isInternet) { - if (isInternet) { - showLoading(); - // Init Odoo URL when URL is not saved - odoo = new Odoo(url: odooURL); - odoo.getDatabases().then((http.Response res) { - setState( - () { - hideLoadingSuccess("Odoo Server Connected"); - isCorrectURL = true; - dynamicList = json.decode(res.body)['result'] as List; - saveOdooUrl(odooURL); - dynamicList.forEach((db) => _dbList.add(db)); - _selectedDb = _dbList[0]; - if (_dbList.length == 1) { - isDBFilter = true; - } else { - isDBFilter = false; - } - }, - ); - }).catchError( - (e) { - showMessage("Warning", "Invalid URL"); - }, - ); - } - }); - } - - @override - void initState() { - super.initState(); - - getOdooInstance().then((odoo) { - _checkFirstTime(); - }); - } - - bool isValid() { - _email = _emailCtrler.text; - _pass = _passCtrler.text; - if (_email.length > 0 && _pass.length > 0) { - return true; - } else { - showSnackBar("Please enter valid email and password"); - return false; - } - } - - @override - Widget build(BuildContext context) { - final checkButton = Container( - padding: EdgeInsets.symmetric(vertical: 16.0), - width: MediaQuery.of(context).size.width, - child: RaisedButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - onPressed: !isCorrectURL - ? () { - if (_urlCtrler.text.length == 0) { - showSnackBar("Please enter valid URL"); - return; - } - odooURL = _selectedProtocol + "://" + _urlCtrler.text; - _checkURL(); - } - : null, - padding: EdgeInsets.all(12), - color: Colors.indigo.shade400, - child: Text( - 'Connect Odoo Server', - style: TextStyle( - fontFamily: "Montserrat", - fontWeight: FontWeight.bold, - fontSize: 18, - color: Colors.white, - ), - ), - ), - ); - - final protocol = Container( - width: MediaQuery.of(context).size.width, - decoration: new BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - border: - Border.all(color: Color.fromRGBO(112, 112, 112, 3.0), width: 1.0), - ), - child: Padding( - padding: EdgeInsets.only(left: 20.0), - child: DropdownButton( - isExpanded: true, - value: _selectedProtocol, - onChanged: (String newValue) { - setState( - () { - _selectedProtocol = newValue; - }, - ); - }, - underline: SizedBox(height: 0.0), - items: ['http', 'https'].map>( - (String value) { - return DropdownMenuItem( - value: value, - child: Text( - value, - style: TextStyle( - fontSize: 18, - fontFamily: "Montserrat", - ), - ), - ); - }, - ).toList(), - ), //DropDownButton - ), - ); - - final dbs = isDBFilter - ? SizedBox(height: 0.0) - : Container( - width: MediaQuery.of(context).size.width, - decoration: new BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - border: Border.all( - color: Color.fromRGBO(112, 112, 112, 3.0), width: 1.0)), - child: Padding( - padding: EdgeInsets.only(left: 20.0), - child: DropdownButton( - value: _selectedDb, - onChanged: (String newValue) { - setState(() { - _selectedDb = newValue; - }); - }, - isExpanded: true, - underline: SizedBox(height: 0.0), - hint: Text( - "Select Database", - style: TextStyle( - fontFamily: "Montserrat", - ), - ), - items: _dbList.map( - (db) { - return DropdownMenuItem( - child: Text( - db, - style: - TextStyle(fontFamily: "Montserrat", fontSize: 18), - ), - value: db, - ); - }, - ).toList(), - ), - ), - ); - - final odooUrl = TextField( - autofocus: false, - controller: _urlCtrler, - decoration: InputDecoration( - labelText: "Odoo Server URL", - contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0), - border: OutlineInputBorder(borderRadius: BorderRadius.circular(10.0)), - ), - ); - - final email = TextField( - keyboardType: TextInputType.emailAddress, - controller: _emailCtrler, - decoration: InputDecoration( - labelText: "E-mail", - contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0), - border: OutlineInputBorder(borderRadius: BorderRadius.circular(10.0)), - ), - ); - - final password = TextField( - controller: _passCtrler, - obscureText: true, - decoration: InputDecoration( - labelText: "Password", - contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0), - border: OutlineInputBorder(borderRadius: BorderRadius.circular(10.0)), - ), - ); - - final loginButton = Container( - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.symmetric(vertical: 16.0), - child: RaisedButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - onPressed: () { - _login(); - }, - padding: EdgeInsets.all(12), - color: Colors.indigo.shade400, - child: Text( - 'Log In', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - color: Colors.white, - ), - ), - ), - ); - - final checkURLWidget = Container( - child: Column( - mainAxisSize: MainAxisSize.max, - children: [ - SizedBox(height: 48.0), - protocol, - SizedBox(height: 8.0), - odooUrl, - SizedBox(height: 8.0), - checkButton, - SizedBox(height: 8.0), - ], - ), - ); - - final loginWidget = Container( - child: Column( - children: [ - dbs, - SizedBox(height: 8.0), - email, - SizedBox(height: 8.0), - password, - SizedBox(height: 24.0), - loginButton - ], - ), - ); - - return Scaffold( - key: scaffoldKey, - appBar: AppBar( - title: Text( - "Login", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - ), - ), - ), - body: Container( - height: MediaQuery.of(context).size.height, - width: MediaQuery.of(context).size.width, - child: ListView( - padding: EdgeInsets.all(10.0), - children: [ - getURL() == null ? checkURLWidget : SizedBox(height: 0.0), - loginWidget, - ], - ), - ), - floatingActionButton: isLoggedIn() - ? FloatingActionButton( - child: Icon(Icons.settings), - onPressed: () { - pushReplacement(Settings()); - }, - ) - : SizedBox(height: 0.0), - ); - } -} diff --git a/lib/app/pages/partner_details.dart b/lib/app/pages/partner_details.dart deleted file mode 100755 index c631dc8..0000000 --- a/lib/app/pages/partner_details.dart +++ /dev/null @@ -1,402 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:odoo_json_rpc_flutter/app/data/pojo/partners.dart'; -import 'package:odoo_json_rpc_flutter/app/data/services/odoo_response.dart'; -import 'package:odoo_json_rpc_flutter/app/utility/strings.dart'; -import 'package:odoo_json_rpc_flutter/base.dart'; - -class PartnerDetails extends StatefulWidget { - PartnerDetails({this.data}); - - final data; - - @override - _PartnerDetailsState createState() => _PartnerDetailsState(); -} - -class _PartnerDetailsState extends Base { - var refreshkey = GlobalKey(); - String name = ""; - String image_URL = ""; - String email = ""; - var phone = ""; - var mobile = ""; - var street = ""; - var street2 = ""; - var city = ""; - var state_id = ""; - var zip = ""; - var title = ""; - var website = ""; - var jobposition = ""; - var country = ""; - Partner _partner; - - @override - void initState() { - super.initState(); - - _partner = widget.data; - - getOdooInstance().then((odoo) { - _getProfileData(); - }); - } - - _getProfileData() async { - isConnected().then((isInternet) { - if (isInternet) { - odoo.searchRead(Strings.res_partner, [ - ["id", "=", _partner.id] - ], []).then( - (OdooResponse res) { - if (!res.hasError()) { - setState(() { - String session = getSession(); - session = session.split(",")[0].split(";")[0]; - final result = res.getResult()['records'][0]; - name = result["name"]; - email = result["email"]; - phone = result['phone'] is! bool ? result['phone'] : "N/A"; - print("----------phone-------------$phone"); - mobile = result['mobile'] is! bool ? result['mobile'] : "N/A"; - print("----------mobile-------------$mobile"); - street = result['street'] is! bool ? result['street'] : ""; - street2 = result['street2'] is! bool ? result['street2'] : ""; - city = result['city'] is! bool ? result['city'] : ""; - state_id = - result['state_id'] is! bool ? result['state_id'][1] : ""; - zip = result['zip'] is! bool ? result['zip'] : ""; - title = result['title'] is! bool ? result['title'][1] : "N/A"; - website = - result['website'] is! bool ? result['website'] : "N/A"; - jobposition = - result['function'] is! bool ? result['function'] : "N/A"; - country = result["country_id"] is! bool - ? result["country_id"][1] - : "N/A"; - - image_URL = getURL() + - "/web/image?model=res.partner&field=image&" + - session + - "&id=" + - _partner.id.toString(); - }); - } - }, - ); - } - }); - } - - @override - Widget build(BuildContext context) { - final upper_header = Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(top: 50), - ), - new Container( - height: 120, - width: 120, - decoration: BoxDecoration( - border: Border.all(color: Colors.white, width: 1.0), - borderRadius: BorderRadius.circular(70.0), - ), - padding: EdgeInsets.all(8.0), - child: Container( - height: 110, - width: 110, - decoration: BoxDecoration( - border: Border.all( - color: Colors.white, - width: 1.0, - ), - borderRadius: BorderRadius.circular(50.0), - ), - child: CircleAvatar( - backgroundImage: NetworkImage( - image_URL != null - ? image_URL - : "https://image.flaticon.com/icons/png/512/1144/1144760.png", - ), - ), - ), - ), - Padding(padding: EdgeInsets.only(top: 5.0, bottom: 5.0)), - Text( - name, - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 16, - color: Colors.white, - ), - ), - Padding(padding: EdgeInsets.only(top: 2.0, bottom: 2.0)), - Text( - email, - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 14, - color: Colors.white, - ), - ), - Padding(padding: EdgeInsets.only(top: 8.0, bottom: 35.0)), - ], - ), - ); - - final lower = Container( - child: ListView( - children: [ - Container( - height: 75, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - color: Colors.grey.shade100, - child: Row( - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Image( - image: AssetImage("assets/worker.png"), - height: 30.0, - width: 30.0, - ), - Padding(padding: EdgeInsets.only(left: 10.0)), - Text( - jobposition != null ? jobposition : "", - style: TextStyle( - fontSize: 19.0, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - ), - InkWell( - onTap: () {}, - child: Container( - height: 75, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - color: Colors.grey.shade100, - child: Row( - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Image( - image: AssetImage("assets/mister.png"), - height: 30.0, - width: 30.0, - ), - Padding(padding: EdgeInsets.only(left: 10.0)), - Text( - title != null ? title : "", - style: TextStyle( - fontSize: 19.0, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - ), - ), - InkWell( - child: Container( - height: 75, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - color: Colors.grey.shade100, - child: Row( - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Image( - image: AssetImage("assets/web.png"), - height: 30.0, - width: 30.0, - ), - Padding(padding: EdgeInsets.only(left: 10.0)), - Text( - website != null ? website : "", - style: TextStyle( - fontSize: 19.0, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - ), - ), - InkWell( - child: Container( - height: 75, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - color: Colors.grey.shade100, - child: Row( - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Image( - image: AssetImage("assets/mobile.png"), - height: 30.0, - width: 30.0, - ), - Padding(padding: EdgeInsets.only(left: 10.0)), - Text( - mobile != null ? mobile : "", - style: TextStyle( - fontSize: 19.0, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - ), - ), - InkWell( - child: Container( - height: 75, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - color: Colors.grey.shade100, - child: Row( - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Image( - image: AssetImage("assets/call.png"), - height: 30.0, - width: 30.0, - ), - Padding(padding: EdgeInsets.only(left: 10.0)), - Text( - phone != null ? phone : "", - style: TextStyle( - fontSize: 19.0, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - ), - ), - InkWell( - child: Container( - height: 163, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - color: Colors.grey.shade100, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Image( - image: AssetImage("assets/user_location.png"), - height: 30.0, - width: 30.0, - ), - Padding(padding: EdgeInsets.only(left: 10.0)), - Container( - padding: - EdgeInsets.only(left: 10.0, bottom: 9.0, top: 9.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - street, - style: TextStyle( - fontSize: 19.0, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - ), - ), - Text( - city, - style: TextStyle( - fontSize: 19.0, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - ), - ), - Text( - state_id, - style: TextStyle( - fontSize: 19.0, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - ), - ), - Text( - zip, - style: TextStyle( - fontSize: 19.0, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - ], - ), - ), - ), - ), - ], - ), - ); - - return Scaffold( - key: scaffoldKey, - body: NestedScrollView( - headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { - return [ - SliverAppBar( - expandedHeight: 260.0, - floating: false, - pinned: false, - flexibleSpace: FlexibleSpaceBar( - background: upper_header, - ), - ), - ]; - }, - body: lower, - ), - ); - } -} diff --git a/lib/app/pages/profile.dart b/lib/app/pages/profile.dart deleted file mode 100755 index ba45021..0000000 --- a/lib/app/pages/profile.dart +++ /dev/null @@ -1,395 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:odoo_json_rpc_flutter/app/data/services/odoo_response.dart'; -import 'package:odoo_json_rpc_flutter/app/utility/constant.dart'; -import 'package:odoo_json_rpc_flutter/app/utility/strings.dart'; -import 'package:odoo_json_rpc_flutter/base.dart'; - -import 'login.dart'; - -class ProfilePage extends StatefulWidget { - @override - _ProfilePageState createState() => _ProfilePageState(); -} - -class _ProfilePageState extends Base { - String name = ""; - String image_URL = ""; - String email = ""; - var phone = ""; - var mobile = ""; - var street = ""; - var street2 = ""; - var city = ""; - var state_id = ""; - var zip = ""; - var title = ""; - var website = ""; - var jobposition = ""; - - _getUserData() async { - isConnected().then((isInternet) { - if (isInternet) { - odoo.searchRead(Strings.res_users, [ - ["id", "=", getUID()] - ], []).then( - (OdooResponse res) { - if (!res.hasError()) { - setState(() { - String session = getSession(); - session = session.split(",")[0].split(";")[0]; - final result = res.getResult()['records'][0]; - name = result['name'] is! bool ? result['name'] : ""; - image_URL = getURL() + - "/web/image?model=res.users&field=image&" + - session + - "&id=" + - getUID().toString(); - email = result['email'] is! bool ? result['email'] : ""; - }); - } else { - showMessage("Warning", res.getErrorMessage()); - } - }, - ); - } - }); - } - - _clearPrefs() async { - odoo.destroy(); - preferences.remove(Constants.USER_PREF); - preferences.remove(Constants.SESSION); - pushAndRemoveUntil(Login()); - } - - _getProfileData() async { - isConnected().then((isInternet) { - if (isInternet) { - odoo.searchRead("res.partner", [ - ["id", "=", user.result.partnerId] //model - ], []).then( - (OdooResponse res) { - if (!res.hasError()) { - setState(() { - final result = res.getResult()['records'][0]; - phone = result['phone'] is! bool ? result['phone'] : "N/A"; - mobile = result['mobile'] is! bool ? result['mobile'] : "N/A"; - street = result['street'] is! bool ? result['street'] : ""; - street2 = result['street2'] is! bool ? result['street2'] : ""; - city = result['city'] is! bool ? result['city'] : ""; - state_id = - result['state_id'] is! bool ? result['state_id'][1] : ""; - zip = result['zip'] is! bool ? result['zip'] : ""; - title = result['title'] is! bool ? result['title'][1] : "N/A"; - website = - result['website'] is! bool ? result['website'] : "N/A"; - jobposition = - result['function'] is! bool ? result['function'] : "N/A"; - }); - } - }, - ); - } - }); - } - - @override - void initState() { - super.initState(); - - getOdooInstance().then((odoo) { - _getUserData(); - _getProfileData(); - }); - } - - @override - Widget build(BuildContext context) { - final upper_header = Container( - color: Colors.indigo, - child: Align( - alignment: Alignment.center, - child: Padding( - padding: EdgeInsets.all(15.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - new Container( - width: 150.0, - height: 150.0, - padding: EdgeInsets.all(10.0), - margin: EdgeInsets.all(25.0), - decoration: new BoxDecoration( - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - blurRadius: 25.0, - color: Colors.orange, - ) - ], - image: new DecorationImage( - fit: BoxFit.fill, - image: new NetworkImage( - image_URL != null - ? image_URL - : "https://i1.wp.com/www.molddrsusa.com/wp-content/uploads/2015/11/profile-empty.png.250x250_q85_crop.jpg?ssl=1", - ), - ), - ), - ), - Padding( - padding: EdgeInsets.all(5.0), - child: Text( - name, - style: TextStyle( - fontSize: 25.0, - fontWeight: FontWeight.bold, - fontFamily: "Montserrat", - color: Colors.white, - ), - ), - ), - Padding( - padding: EdgeInsets.all(5.0), - child: Text( - email, - style: TextStyle( - fontSize: 14.0, - fontFamily: "Montserrat", - color: Colors.white, - ), - ), - ), - ], - ), - ), - ), - ); - - final lower = Container( - child: ListView( - children: [ - Container( - height: 75, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Icon(Icons.person_pin), - Padding(padding: EdgeInsets.only(left: 10.0)), - Text( - jobposition, - style: TextStyle( - fontSize: 16.0, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - Divider(), - Container( - height: 75, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Row( - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Icon(Icons.title, color: Colors.black), - Padding(padding: EdgeInsets.only(left: 10.0)), - Text( - title, - style: TextStyle( - fontSize: 16.0, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - Divider(), - Container( - height: 75, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Row( - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Icon(Icons.web_asset, color: Colors.black), - Padding(padding: EdgeInsets.only(left: 10.0)), - Text( - website, - style: TextStyle( - fontSize: 16.0, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - Divider(), - Container( - height: 75, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Row( - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Icon(Icons.phone_android, color: Colors.black), - Padding(padding: EdgeInsets.only(left: 10.0)), - Text( - mobile, - style: TextStyle( - fontSize: 16.0, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - Divider(), - Container( - height: 75, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Row( - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Icon(Icons.phone, color: Colors.black), - Padding(padding: EdgeInsets.only(left: 10.0)), - Text( - phone, - style: TextStyle( - fontSize: 16.0, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - Divider(), - Container( - height: 120, - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding(padding: EdgeInsets.only(right: 10.0)), - Icon(Icons.location_city), - Padding(padding: EdgeInsets.only(left: 10.0)), - Container( - padding: EdgeInsets.only(left: 10.0, bottom: 9.0, top: 9.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - street, - style: TextStyle( - fontSize: 16.0, - fontFamily: "Montserrat", - ), - ), - Text( - city, - style: TextStyle( - fontSize: 16.0, - fontFamily: "Montserrat", - ), - ), - Text( - state_id, - style: TextStyle( - fontSize: 16.0, - fontFamily: "Montserrat", - ), - ), - Text( - zip, - style: TextStyle( - fontSize: 16.0, - fontFamily: "Montserrat", - ), - ), - ], - ), - ), - ], - ), - ), - Divider() - ], - ), - ); - - return Scaffold( - key: scaffoldKey, - appBar: AppBar( - title: Text("Profile"), - actions: [ - IconButton( - icon: Icon(Icons.exit_to_app), - onPressed: () { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext ctxt) { - return AlertDialog( - title: Text( - "Logged Out", - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 22, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - ), - content: Text( - "Are you sure you want to logged out?", - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 18, - color: Colors.black, - ), - ), - actions: [ - FlatButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text( - "Cancel", - style: TextStyle( - fontFamily: "Montserrat", - fontWeight: FontWeight.bold, - ), - ), - ), - FlatButton( - onPressed: () { - _clearPrefs(); - }, - child: Text( - "Logout", - style: TextStyle( - fontFamily: "Montserrat", - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ); - }, - ); - }) - ], - ), - body: Column( - children: [upper_header, Expanded(child: lower)], - ), - ); - } -} diff --git a/lib/app/pages/settings.dart b/lib/app/pages/settings.dart deleted file mode 100755 index 3ae0807..0000000 --- a/lib/app/pages/settings.dart +++ /dev/null @@ -1,191 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; -import 'package:odoo_json_rpc_flutter/app/data/services/odoo_api.dart'; -import 'package:odoo_json_rpc_flutter/app/utility/constant.dart'; -import 'package:odoo_json_rpc_flutter/app/utility/strings.dart'; -import 'package:odoo_json_rpc_flutter/base.dart'; - -import 'login.dart'; - -class Settings extends StatefulWidget { - @override - _SettingsState createState() => _SettingsState(); -} - -class _SettingsState extends Base { - TextEditingController _urlCtrler = new TextEditingController(); - String odooURL = ""; - - @override - void initState() { - super.initState(); - getOdooInstance().then((odoo) { - _checkFirstTime(); - }); - } - - _checkFirstTime() async { - if (getURL() != null) { - setState(() { - _urlCtrler.text = odooURL = getURL(); - }); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - key: scaffoldKey, - appBar: AppBar( - title: Text("Settings"), - ), - body: ListView( - children: [ - Padding( - padding: EdgeInsets.all(15.0), - child: TextField( - textAlign: TextAlign.left, - controller: _urlCtrler, - decoration: InputDecoration( - labelText: "Odoo Server URL", - labelStyle: TextStyle( - color: Colors.black, - ), - border: OutlineInputBorder(), - focusedBorder: OutlineInputBorder(), - ), - ), - ), - Padding( - padding: EdgeInsets.all(15.0), - child: MaterialButton( - child: Text( - "Save Settings", - style: TextStyle( - color: Colors.white, - ), - ), - color: Colors.indigo.shade400, - onPressed: () { - _saveURL(_urlCtrler.text); - }, - ), - ) - ], - ), - ); - } - - _saveURL(String url) async { - if (!url.toLowerCase().contains("http://") && - !url.toLowerCase().contains("https://")) { - url = "http://" + url; - } - if (url.length > 0 && url != " ") { - isConnected().then((isInternet) { - if (isInternet) { - odoo = new Odoo(url: url); - odoo.getDatabases().then((http.Response res) { - saveOdooUrl(url); - _showLogoutMessage(Strings.loginAgainMessage); - }).catchError((error) { - _showMessage(Strings.invalidUrlMessage); - }); - } - }); - } else { - _showMessage("Please enter valid URL"); - } - } - - _showMessage(String message) { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext ctxt) { - return AlertDialog( - title: Text( - "Warning", - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 22, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - ), - content: Text( - message, - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 18, - color: Colors.black, - ), - ), - actions: [ - FlatButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text( - "Ok", - style: TextStyle( - fontFamily: "Montserrat", - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ); - }, - ); - } - - _showLogoutMessage(String message) { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext ctxt) { - return AlertDialog( - title: Text( - "Warning", - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 22, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - ), - content: Text( - message, - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 18, - color: Colors.black, - ), - ), - actions: [ - FlatButton( - onPressed: () { - _clearPrefs(); - }, - child: Text( - "Logout", - style: TextStyle( - fontFamily: "Montserrat", - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ); - }, - ); - } - - _clearPrefs() async { - odoo.destroy(); - preferences.remove(Constants.USER_PREF); - preferences.remove(Constants.SESSION); - pushAndRemoveUntil(Login()); - } -} diff --git a/lib/app/utility/constant.dart b/lib/app/utility/constant.dart deleted file mode 100755 index f87b156..0000000 --- a/lib/app/utility/constant.dart +++ /dev/null @@ -1,8 +0,0 @@ -class Constants { - static const String UID = "uid"; - static const String SESSION_ID = "session_id"; - static const String USER_PREF = "UserPrefs"; - static const String ODOO_URL = "odooUrl"; - static const String SESSION = "session"; - static const String PERSON_ID = "person_id"; -} \ No newline at end of file diff --git a/lib/app/utility/strings.dart b/lib/app/utility/strings.dart deleted file mode 100755 index 5615b8a..0000000 --- a/lib/app/utility/strings.dart +++ /dev/null @@ -1,16 +0,0 @@ -class Strings { - static const String app_title = "Odoo Mobile"; - - static const String internetMessage = "No Internet Connection!"; - static const String loginAgainMessage = "Setting Saved! Please Login!"; - static const String invalidUrlMessage = "Can't connect to the server! Please enter valid URL"; - static const String no_orders = "No Orders"; - - // Route Name - static const String route_home = "/home"; - static const String route_login = "/login"; - - // Model name - static const String res_partner = "res.partner"; - static const String res_users = "res.users"; -} \ No newline at end of file diff --git a/lib/base.dart b/lib/base.dart deleted file mode 100755 index 0634d5f..0000000 --- a/lib/base.dart +++ /dev/null @@ -1,238 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:loading/indicator/ball_pulse_indicator.dart'; -import 'package:loading/loading.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import 'app/data/pojo/user.dart'; -import 'app/data/services/odoo_api.dart'; -import 'app/utility/constant.dart'; -import 'app/utility/strings.dart'; - -abstract class Base extends State { - Odoo odoo; - SharedPreferences preferences; - User user; - GlobalKey scaffoldKey = new GlobalKey(); - - /* - * Create Odoo Object with URL, SessionID and UserID. - * If SessionId or UserId is not present then pass only OdooURL. - * Initialize SharedPreferences at once here and use it in anywhere you want to use. - * Initialize User Data as User model and use it anywhere - */ - Future getOdooInstance() async { - preferences = await SharedPreferences.getInstance(); - String userPref = preferences.getString(Constants.USER_PREF); // User Data - String odooUrl = getURL(); // Get OdooURL from SharedPreferences - if (userPref != null) { - Map map = json.decode(userPref); - user = User.fromJson(map); - } - odoo = new Odoo(url: odooUrl); - - return odoo; - } - - int getUID() { - if (user != null) { - return user.result.uid; - } - } - - bool isLoggedIn() { - return user != null; - } - - String getURL() { - if (preferences != null) { - return preferences.getString(Constants.ODOO_URL); - } - } - - String getSession() { - if (preferences != null) { - return preferences.getString(Constants.SESSION); - } - } - - User getUser() { - return user; - } - - saveUser(String userData) { - if (preferences != null) - preferences.setString(Constants.USER_PREF, userData); - } - - saveOdooUrl(String url) { - if (preferences != null) preferences.setString(Constants.ODOO_URL, url); - } - - // This method is about push to new widget and replace current widget - pushReplacement(StatefulWidget screenName) { - Navigator.of(context) - .pushReplacement(MaterialPageRoute(builder: (context) => screenName)); - } - - // This method is about push to new widget but don't replace current widget - push(StatefulWidget screenName) { - Navigator.push(context, - MaterialPageRoute(builder: (BuildContext context) => screenName)); - } - - // This method is about push to new widget and remove all previous widget - pushAndRemoveUntil(StatefulWidget screenName) { - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute(builder: (BuildContext context) => screenName), - (_) => false); - } - - // Show loading with optional message params - showLoading({String msg}) { - return Container( - color: Colors.lightBlue, - child: Center( - child: Loading( - indicator: BallPulseIndicator(), - size: 100.0, - color: Colors.pink, - ), - ), - ); - - // if (msg != null) { - // EasyLoading.show(status: msg); - // } else { - // EasyLoading.show(); - // } - } - - hideLoadingSuccess(String msg) { - // EasyLoading.showSuccess(msg, duration: Duration(seconds: 2)); - // EasyLoading.dismiss(); - } - - hideLoadingError(String msg) { - // EasyLoading.showError(msg, duration: Duration(seconds: 2)); - // EasyLoading.dismiss(); - } - - hideLoading() { - // EasyLoading.dismiss(); - } - - /* - * Show Snackbar with Global scaffold key - * scaffoldKey is defined globally as snackbar do not find context of Scaffold widget - * hideLoading is hide the loader when snackbar message is showing to UI - */ - showSnackBar(String msg) { - scaffoldKey.currentState.showSnackBar(new SnackBar(content: Text(msg))); - hideLoading(); - } - - showMessage(String title, String message) { - hideLoading(); - if (Platform.isAndroid) { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext ctxt) { - return AlertDialog( - title: Text( - title, - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 22, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - ), - content: Text( - message, - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 18, - color: Colors.black, - ), - ), - actions: [ - FlatButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text( - "Ok", - style: TextStyle( - fontFamily: "Montserrat", - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ); - }, - ); - } - if (Platform.isIOS) { - showCupertinoDialog( - context: context, - builder: (BuildContext ctxt) { - return CupertinoAlertDialog( - title: Text( - title, - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 22, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - ), - content: Text( - message, - style: TextStyle( - fontFamily: "Montserrat", - fontSize: 18, - color: Colors.black, - ), - ), - actions: [ - FlatButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text( - "Ok", - style: TextStyle( - fontFamily: "Montserrat", - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ); - }, - ); - } - } - - // Check Internet Connection Async method with Snackbar message. - Future isConnected() async { - try { - final result = await InternetAddress.lookup('google.com'); - if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) { - return true; - } - } on SocketException catch (_) { - showSnackBar(Strings.internetMessage); - return false; - } - showSnackBar(Strings.internetMessage); - return false; - } -} diff --git a/lib/common/api_factory/api.dart b/lib/common/api_factory/api.dart new file mode 100644 index 0000000..cd5e360 --- /dev/null +++ b/lib/common/api_factory/api.dart @@ -0,0 +1,441 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; +import 'package:odoo_common_code_latest/common/api_factory/api_end_points.dart'; +import 'package:odoo_common_code_latest/common/api_factory/base_response.dart'; +import 'package:odoo_common_code_latest/common/api_factory/dio_factory.dart'; +import 'package:uuid/uuid.dart'; +import 'package:odoo_common_code_latest/common/config/prefs/pref_utils.dart'; +import 'package:odoo_common_code_latest/common/utils/utils.dart'; +import 'package:odoo_common_code_latest/common/widgets/log.dart'; +import 'package:odoo_common_code_latest/src/authentication/models/user_model.dart'; +import 'package:odoo_common_code_latest/common/api_factory/models/version_info_response.dart'; +import 'package:odoo_common_code_latest/common/config/config.dart'; + +enum ApiEnvironment { UAT, Dev, Prod } + +extension APIEnvi on ApiEnvironment { + String get endpoint { + switch (this) { + case ApiEnvironment.UAT: + return Config.OdooUATURL; + case ApiEnvironment.Dev: + return Config.OdooDevURL; + case ApiEnvironment.Prod: + return Config.OdooProdURL; + } + } +} + +enum HttpMethod { delete, get, patch, post, put } + +extension HttpMethods on HttpMethod { + String get value { + switch (this) { + case HttpMethod.delete: + return 'DELETE'; + case HttpMethod.get: + return 'GET'; + case HttpMethod.patch: + return 'PATCH'; + case HttpMethod.post: + return 'POST'; + case HttpMethod.put: + return 'PUT'; + } + } +} + +class Api { + Api._(); + + static final catchError = _catchError; + + static void _catchError(e, stackTrace, OnError onError) { + if (!kReleaseMode) { + print(e); + } + if (e is DioError) { + if (e.type == DioErrorType.connectTimeout || + e.type == DioErrorType.sendTimeout || + e.type == DioErrorType.receiveTimeout || + e.type == DioErrorType.other) { + onError('Server unreachable', {}); + } else if (e.type == DioErrorType.response) { + final response = e.response; + if (response != null) { + final data = response.data; + if (data != null && data is Map) { + showSessionDialog(); + onError('Failed to get response: ${e.message}', data); + return; + } + } + onError('Failed to get response: ${e.message}', {}); + } else { + onError('Request cancelled', {}); + } + } else { + onError(e?.toString() ?? 'Unknown error occurred', {}); + } + } + + //General Post Request + static Future request( + {required HttpMethod method, + required String path, + required Map params, + required OnResponse onResponse, + required OnError onError}) async { + Response response; + switch (method) { + case HttpMethod.post: + response = await DioFactory.dio! + .post( + path, + data: params, + ) + .catchError((e, stackTrace) => _catchError(e, stackTrace, onError)); + break; + case HttpMethod.delete: + response = await DioFactory.dio! + .delete( + path, + data: params, + ) + .catchError((e, stackTrace) => _catchError(e, stackTrace, onError)); + break; + case HttpMethod.get: + response = await DioFactory.dio! + .get( + path, + ) + .catchError((e, stackTrace) => _catchError(e, stackTrace, onError)); + break; + case HttpMethod.patch: + response = await DioFactory.dio! + .patch( + path, + data: params, + ) + .catchError((e, stackTrace) => _catchError(e, stackTrace, onError)); + break; + case HttpMethod.put: + response = await DioFactory.dio! + .put( + path, + data: params, + ) + .catchError((e, stackTrace) => _catchError(e, stackTrace, onError)); + break; + } + + if (response.data["success"] == 0) { + onError(response.data["error"][0], {}); + } else { + onResponse(response.data["result"]); + } + + if (path == ApiEndPoints.authenticate) { + _updateCookies(response.headers); + } + } + + static _updateCookies(Headers headers) async { + Log("Inside Update Cookie"); + String? rawCookie = headers.value("set-cookie"); + Log(rawCookie); + if (rawCookie != null) { + DioFactory.initialiseHeaders(rawCookie); + PrefUtils.setToken(rawCookie); + } + } + + static getSessionInfo({ + required OnResponse onResponse, + required OnError onError, + }) { + request( + method: HttpMethod.post, + path: ApiEndPoints.getSessionInfo, + params: createPayload({}), + onResponse: (response) { + onResponse(response); + }, + onError: (error, data) { + onError(error, {}); + }, + ); + } + + static destroy({ + required OnResponse onResponse, + required OnError onError, + }) { + request( + method: HttpMethod.post, + path: ApiEndPoints.destroy, + params: createPayload({}), + onResponse: (response) { + onResponse(response); + }, + onError: (error, data) { + onError(error, {}); + }, + ); + } + + // Authenticate user + static authenticate({ + required String username, + required String password, + required String database, + required OnResponse onResponse, + required OnError onError, + }) { + var params = { + "db": database, + "login": username, + "password": password, + "context": {} + }; + + request( + method: HttpMethod.post, + path: ApiEndPoints.authenticate, + params: createPayload(params), + onResponse: (response) { + onResponse(UserModel.fromJson(response)); + }, + onError: (error, data) { + onError(error, {}); + }, + ); + } + + static read({ + required String model, + required List ids, + required List fields, + dynamic kwargs, + required OnResponse onResponse, + required OnError onError, + }) async { + callKW( + model: model, + method: "read", + args: [ids, fields], + kwargs: kwargs ?? null, + onResponse: onResponse, + onError: onError); + } + + static searchRead({ + required String model, + required List domain, + required List fields, + int offset = 0, + int limit = 0, + String order = "", + required OnResponse onResponse, + required OnError onError, + }) async { + var params = { + "context": getContext(), + "domain": domain, + "fields": fields, + "limit": limit, + "model": model, + "offset": offset, + "sort": order + }; + request( + method: HttpMethod.post, + path: ApiEndPoints.searchRead, + params: createPayload(params), + onResponse: (response) { + onResponse(response); + }, + onError: (error, data) { + onError(error, {}); + }, + ); + } + + // Call any model method with arguments + static callKW({ + required String model, + required String method, + required List args, + dynamic kwargs, + required OnResponse onResponse, + required OnError onError, + }) async { + var params = { + "model": model, + "method": method, + "args": args, + "kwargs": kwargs ?? {}, + "context": getContext(), + }; + request( + method: HttpMethod.post, + path: ApiEndPoints.getCallKWEndPoint(model, method), + params: createPayload(params), + onResponse: (response) { + onResponse(response); + }, + onError: (error, data) { + onError(error, {}); + }, + ); + } + + // Create new record for model + static create({ + required String model, + required Map values, + dynamic kwargs, + required OnResponse onResponse, + required OnError onError, + }) { + callKW( + model: model, + method: "create", + args: [values], + kwargs: kwargs ?? null, + onResponse: onResponse, + onError: onError); + } + + // Write record with ids and values + static write({ + required String model, + required List ids, + required Map values, + required OnResponse onResponse, + required OnError onError, + }) { + callKW( + model: model, + method: "write", + args: [ids, values], + onResponse: onResponse, + onError: onError); + } + + // Remove record from system + static unlink({ + required String model, + required List ids, + dynamic kwargs, + required OnResponse onResponse, + required OnError onError, + }) async { + callKW( + model: model, + method: "unlink", + args: [ids], + kwargs: kwargs ?? null, + onResponse: onResponse, + onError: onError); + } + + // Call json controller + static callController({ + required String path, + required Map params, + required OnResponse onResponse, + required OnError onError, + }) async { + request( + method: HttpMethod.post, + path: path, + params: createPayload(params), + onResponse: (response) { + onResponse(response); + }, + onError: (error, data) { + onError(error, {}); + }, + ); + } + + // get version of odoo + static getVersionInfo({ + required OnResponse onResponse, + required OnError onError, + }) { + request( + method: HttpMethod.post, + path: ApiEndPoints.getVersionInfo, + params: createPayload({}), + onResponse: (response) { + onResponse(VersionInfoResponse.fromJson(response)); + }, + onError: (error, data) { + onError(error, {}); + }, + ); + } + + static getDatabases({ + required int serverVersionNumber, + required OnResponse onResponse, + required OnError onError, + }) async { + var params = {}; + var endPoint = ""; + if (serverVersionNumber == 9) { + params["method"] = "list"; + params["service"] = "db"; + params["args"] = []; + endPoint = ApiEndPoints.getDb9; + } else if (serverVersionNumber >= 10) { + endPoint = ApiEndPoints.getDb10; + params["context"] = {}; + } else { + endPoint = ApiEndPoints.getDb; + params["context"] = {}; + } + request( + method: HttpMethod.post, + path: endPoint, + params: createPayload(params), + onResponse: (response) { + onResponse(response); + }, + onError: (error, data) { + onError(error, {}); + }, + ); + } + + static hasRight({ + required String model, + required List right, + dynamic kwargs, + required OnResponse onResponse, + required OnError onError, + }) { + callKW( + model: model, + method: "has_group", + args: right, + kwargs: kwargs ?? null, + onResponse: onResponse, + onError: onError); + } + + static Map createPayload(Map params) { + return { + "id": new Uuid().v1(), + "jsonrpc": "2.0", + "method": "call", + "params": params, + }; + } + + static Map getContext() { + return {"lang": "en_US", "tz": "Europe/Brussels", "uid": Uuid().v1()}; + } +} diff --git a/lib/common/api_factory/api_end_points.dart b/lib/common/api_factory/api_end_points.dart new file mode 100644 index 0000000..fc3dca4 --- /dev/null +++ b/lib/common/api_factory/api_end_points.dart @@ -0,0 +1,17 @@ +class ApiEndPoints { + ApiEndPoints._(); + + static const String getSessionInfo = "web/session/get_session_info"; + static const String destroy = "web/session/destroy"; + static const String authenticate = "web/session/authenticate"; + static const String searchRead = "web/dataset/search_read"; + static const String callKw = "web/dataset/call_kw/"; + static const String getVersionInfo = "web/webclient/version_info"; + static const String getDb9 = "jsonrpc"; + static const String getDb10 = "web/database/list"; + static const String getDb = "web/database/get_list"; + + static String getCallKWEndPoint(String model, String method) { + return '$callKw/$model/$method'; + } +} diff --git a/lib/common/api_factory/base_response.dart b/lib/common/api_factory/base_response.dart new file mode 100644 index 0000000..8d89852 --- /dev/null +++ b/lib/common/api_factory/base_response.dart @@ -0,0 +1,30 @@ +class BaseResponse { + dynamic result; + List? error; + int? success; + + BaseResponse({this.result, this.error, this.success}); + + factory BaseResponse.fromJson(Map json) { + return BaseResponse( + result: json['result'] != null ? json['result'] : null, + error: json['error'] != null + ? (json['error'] as List).map((i) => i).toList() + : null, + success: json['success'], + ); + } + + Map toJson() { + final Map result = new Map(); + result['success'] = this.success; + if (this.result != null) { + result['result'] = this.result.toJson(); + } + + if (this.error != null) { + result['error'] = this.error!.map((v) => v).toList(); + } + return result; + } +} diff --git a/lib/common/api_factory/dio_factory.dart b/lib/common/api_factory/dio_factory.dart new file mode 100644 index 0000000..dde9339 --- /dev/null +++ b/lib/common/api_factory/dio_factory.dart @@ -0,0 +1,97 @@ +import 'dart:developer' show log; +import 'dart:io'; +import 'package:device_info/device_info.dart'; +import 'package:dio/adapter.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; +import 'package:odoo_common_code_latest/common/api_factory/api.dart'; +import 'package:odoo_common_code_latest/common/config/config.dart'; + +typedef void OnError(String error, Map data); +typedef void OnResponse(T response); + +class DioFactory { + static final _singleton = DioFactory._instance(); + + static Dio? get dio => _singleton._dio; + static var _deviceName = 'Generic Device'; + static var _authorization = ''; + + static Future computeDeviceInfo() async { + if (Platform.isAndroid || Platform.isIOS) { + DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); + if (Platform.isAndroid) { + AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; + _deviceName = '${androidInfo.brand} ${androidInfo.model}'; + } else { + IosDeviceInfo iosInfo = await deviceInfo.iosInfo; + _deviceName = iosInfo.utsname.machine; + } + } else if (Platform.isFuchsia) { + _deviceName = 'Generic Fuchsia Device'; + } else if (Platform.isLinux) { + _deviceName = 'Generic Linux Device'; + } else if (Platform.isMacOS) { + _deviceName = 'Generic Macintosh Device'; + } else if (Platform.isWindows) { + _deviceName = 'Generic Windows Device'; + } + + return true; + } + + static void initialiseHeaders(String token) { + _authorization = token; + _singleton._dio!.options.headers[HttpHeaders.cookieHeader] = _authorization; + } + + static void initFCMToken(String token) { + var _token = token; + _singleton._dio!.options.headers["device_id"] = _token; + } + + Dio? _dio; + + DioFactory._instance() { + _dio = Dio( + BaseOptions( + baseUrl: ApiEnvironment.Dev.endpoint, + headers: { + HttpHeaders.userAgentHeader: _deviceName, + HttpHeaders.authorizationHeader: _authorization, + 'Keep-Alive': Config.timeout, + }, + connectTimeout: Config.timeout, + receiveTimeout: Config.timeout, + sendTimeout: Config.timeout, + contentType: Headers.jsonContentType, + ), + ); + if (!kReleaseMode) { + _dio!.interceptors.add(LogInterceptor( + request: Config.logNetworkRequest, + requestHeader: Config.logNetworkRequestHeader, + requestBody: Config.logNetworkRequestBody, + responseHeader: Config.logNetworkResponseHeader, + responseBody: Config.logNetworkResponseBody, + error: Config.logNetworkError, + logPrint: (Object object) { + log(object.toString(), name: 'dio'); + }, + )); + } + if (Config.selfSignedCert) { + final httpClientAdapter = + _dio!.httpClientAdapter as DefaultHttpClientAdapter; + httpClientAdapter.onHttpClientCreate = _onHttpClientCreate; + } + } + + dynamic _onHttpClientCreate(HttpClient client) { + client.badCertificateCallback = _badCertificateCallback; + } + + bool _badCertificateCallback(X509Certificate cert, String host, int port) { + return true; + } +} diff --git a/lib/common/api_factory/models/base_list.dart b/lib/common/api_factory/models/base_list.dart new file mode 100644 index 0000000..d397ca7 --- /dev/null +++ b/lib/common/api_factory/models/base_list.dart @@ -0,0 +1,22 @@ +class BaseListModel { + int? id; + String? name; + bool isSelected = false; + + BaseListModel({this.id, this.name, this.isSelected = false}); + + factory BaseListModel.fromJson(Map json) { + return BaseListModel( + id: json['id'], + name: json['name'], + isSelected: false, + ); + } + + Map toJson() { + final Map data = new Map(); + data['id'] = this.id; + data['name'] = this.name; + return data; + } +} diff --git a/lib/common/api_factory/models/version_info_response.dart b/lib/common/api_factory/models/version_info_response.dart new file mode 100644 index 0000000..93d2877 --- /dev/null +++ b/lib/common/api_factory/models/version_info_response.dart @@ -0,0 +1,37 @@ +import 'dart:convert'; + +VersionInfoResponse welcomeFromJson(String str) => + VersionInfoResponse.fromJson(json.decode(str)); + +String welcomeToJson(VersionInfoResponse data) => json.encode(data.toJson()); + +class VersionInfoResponse { + VersionInfoResponse({ + this.serverVersion, + this.serverVersionInfo, + this.serverSerie, + this.protocolVersion, + }); + + String? serverVersion; + List? serverVersionInfo; + String? serverSerie; + int? protocolVersion; + + factory VersionInfoResponse.fromJson(Map json) => + VersionInfoResponse( + serverVersion: json["server_version"] ?? '', + serverVersionInfo: + List.from(json["server_version_info"].map((x) => x)), + serverSerie: json["server_serie"] ?? '', + protocolVersion: json["protocol_version"] ?? 0, + ); + + Map toJson() => { + "server_version": serverVersion, + "server_version_info": + List.from(serverVersionInfo!.map((x) => x)), + "server_serie": serverSerie, + "protocol_version": protocolVersion, + }; +} diff --git a/lib/common/api_factory/modules/authentication_module.dart b/lib/common/api_factory/modules/authentication_module.dart new file mode 100644 index 0000000..5cd9e22 --- /dev/null +++ b/lib/common/api_factory/modules/authentication_module.dart @@ -0,0 +1,49 @@ +import 'dart:convert'; +import 'package:get/get.dart'; +import 'package:odoo_common_code_latest/common/api_factory/api.dart'; +import 'package:odoo_common_code_latest/common/config/config.dart'; +import 'package:odoo_common_code_latest/common/config/prefs/pref_utils.dart'; +import 'package:odoo_common_code_latest/common/utils/utils.dart'; +import 'package:odoo_common_code_latest/common/widgets/log.dart'; +import 'package:odoo_common_code_latest/src/authentication/controllers/signin_controller.dart'; +import 'package:odoo_common_code_latest/src/authentication/models/user_model.dart'; +import 'package:odoo_common_code_latest/src/home/view/home.dart'; + +getVersionInfoAPI() { + Api.getVersionInfo( + onResponse: (response) { + Api.getDatabases( + serverVersionNumber: response.serverVersionInfo![0], + onResponse: (response) { + Log(response); + Config.DB = response[0]; + }, + onError: (error, data) { + handleApiError(error); + }, + ); + }, + onError: (error, data) { + handleApiError(error); + }, + ); +} + +authenticationAPI(String email, String pass) { + showLoading(); + Api.authenticate( + username: email, + password: pass, + database: Config.DB, + onResponse: (UserModel response) { + hideLoading(); + currentUser.value = response; + PrefUtils.setIsLoggedIn(true); + PrefUtils.setUser(jsonEncode(response)); + Get.offAll(() => Home()); + }, + onError: (error, data) { + handleApiError(error); + }, + ); +} diff --git a/lib/common/api_factory/modules/home_api_module.dart b/lib/common/api_factory/modules/home_api_module.dart new file mode 100644 index 0000000..61d276b --- /dev/null +++ b/lib/common/api_factory/modules/home_api_module.dart @@ -0,0 +1,18 @@ +import 'package:odoo_common_code_latest/common/api_factory/api.dart'; +import 'package:odoo_common_code_latest/common/api_factory/dio_factory.dart'; +import 'package:odoo_common_code_latest/common/utils/utils.dart'; +import 'package:odoo_common_code_latest/src/home/model/res_partner_model.dart'; + +resPartnerApi({required OnResponse onResponse}) { + Api.searchRead( + model: "res.partner", + domain: [], + fields: ["name", "email", "image_512"], + onResponse: (response) { + onResponse(ResPartnerModel.fromJson(response)); + }, + onError: (error, data) { + handleApiError(error); + }, + ); +} diff --git a/lib/app/data/services/odoo_response.dart b/lib/common/api_factory/odoo_response.dart old mode 100755 new mode 100644 similarity index 97% rename from lib/app/data/services/odoo_response.dart rename to lib/common/api_factory/odoo_response.dart index 8f89f21..d5eda35 --- a/lib/app/data/services/odoo_response.dart +++ b/lib/common/api_factory/odoo_response.dart @@ -18,7 +18,7 @@ class OdooResponse { if (hasError()) { return _result['error']['data']['message']; } - return null; + return ""; } int getStatusCode() { diff --git a/lib/app/data/services/odoo_version.dart b/lib/common/api_factory/odoo_version.dart old mode 100755 new mode 100644 similarity index 51% rename from lib/app/data/services/odoo_version.dart rename to lib/common/api_factory/odoo_version.dart index b97d146..039ace7 --- a/lib/app/data/services/odoo_version.dart +++ b/lib/common/api_factory/odoo_version.dart @@ -1,8 +1,8 @@ -import 'odoo_response.dart'; +import 'package:odoo_common_code_latest/common/api_factory/odoo_response.dart'; class OdooVersion { - var _version, _server_serie, _protocol_version; - var _major, _minor, _micro, _release_level, _serial; + var _version, _serverSerie, _protocolVersion; + var _major, _minor, _micro, _releaseLevel, _serial; bool _isEnterprise = false; String getVersionInfo() { @@ -10,11 +10,11 @@ class OdooVersion { } int getServerSerie() { - return _server_serie; + return _serverSerie; } int getProtocolVersion() { - return _protocol_version; + return _protocolVersion; } dynamic getMajorVersion() { @@ -30,7 +30,7 @@ class OdooVersion { } String getReleaseLevel() { - return _release_level; + return _releaseLevel; } String getSerial() { @@ -44,24 +44,24 @@ class OdooVersion { OdooVersion parse(OdooResponse response) { Map result = response.getResult(); _version = result['server_version']; - _server_serie = result['server_serie']; - _protocol_version = result['protocol_version']; - List version_info = result['server_version_info']; - if (version_info.length == 6) { - _isEnterprise = version_info.last == "e"; + _serverSerie = result['server_serie']; + _protocolVersion = result['protocol_version']; + List versionInfo = result['server_version_info']; + if (versionInfo.length == 6) { + _isEnterprise = versionInfo.last == "e"; } - _major = version_info[0]; - _minor = version_info[1]; - _micro = version_info[2]; - _release_level = version_info[3]; - _serial = version_info[4]; + _major = versionInfo[0]; + _minor = versionInfo[1]; + _micro = versionInfo[2]; + _releaseLevel = versionInfo[3]; + _serial = versionInfo[4]; return this; } @override String toString() { if (_version != null) { - return "${_version} (${_isEnterprise ? 'Enterprise' : 'Community'})"; + return "$_version (${_isEnterprise ? 'Enterprise' : 'Community'})"; } return "Not Connected: Please call connect() or getVersionInfo() with callback."; } diff --git a/lib/common/app.dart b/lib/common/app.dart new file mode 100644 index 0000000..25f5a2d --- /dev/null +++ b/lib/common/app.dart @@ -0,0 +1,67 @@ +import 'dart:developer'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:get/get.dart'; +import 'package:odoo_common_code_latest/common/api_factory/dio_factory.dart'; +import 'package:odoo_common_code_latest/common/config/app_colors.dart'; +import 'package:odoo_common_code_latest/common/config/app_fonts.dart'; +import 'package:odoo_common_code_latest/common/config/config.dart'; +import 'package:odoo_common_code_latest/common/config/localization/translations.dart'; +import 'package:odoo_common_code_latest/src/authentication/views/signin.dart'; +import 'package:odoo_common_code_latest/src/home/view/home.dart'; + +class App extends StatefulWidget { + final bool isLoggedIn; + + App(this.isLoggedIn); + + @override + State createState() { + return _AppState(); + } +} + +class _AppState extends State { + var _initStateFlag = false; + + @override + void initState() { + super.initState(); + if (!kReleaseMode) { + log('initState', name: '_AppState::initState'); + } + _initStateFlag = true; + } + + @override + void didChangeDependencies() async { + super.didChangeDependencies(); + if (_initStateFlag) { + _initStateFlag = false; + await DioFactory.computeDeviceInfo(); + } + } + + @override + Widget build(BuildContext context) { + return GetMaterialApp( + translations: AppTranslations(), + locale: Get.deviceLocale, + fallbackLocale: Locale('en', 'US'), + theme: ThemeData( + brightness: Brightness.light, + primarySwatch: AppColors.orangeThemeColor, + fontFamily: AppFont.Roboto_Regular, + ), + debugShowCheckedModeBanner: false, + title: 'Odoo Inventory', + localizationsDelegates: [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: Config.supportedLocales, + home: widget.isLoggedIn ? Home() : SignIn(), + ); + } +} diff --git a/lib/common/config/app_colors.dart b/lib/common/config/app_colors.dart new file mode 100644 index 0000000..79cef63 --- /dev/null +++ b/lib/common/config/app_colors.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; + +class AppColors { + AppColors._(); + + static Color black = HexColor("#212121"); + static const homeBlack = Color(0xFF323643); + static const subTitle = Color(0xFF707070); + static const hintColor = Color(0xFFbabbbf); + static const blue = Color(0xFF3277D8); + static Color grey = HexColor("#757575"); + static Color lightGrey = HexColor("#9E9E9E"); + static Color greenColor = HexColor("#1BC500"); + static Color blueBgColor = HexColor("#2C5BDC"); + static Color textFieldBackgroundColor = HexColor("#FAFAFA"); + static Color backgroundColor = HexColor("#F5F5F5"); + static Color blueDotColor = HexColor("#2081FF"); + static Color greyDotColor = HexColor("#E0E0E0"); + static Color blueButtonColor = HexColor("#2081FF"); + static Color orange = HexColor("#F57C51"); + static Color dropDownArrowColor = HexColor("#424242"); + + static Color homeProposalSentBg = HexColor("#FFF3DA"); + static Color homeCandidateLikeBg = HexColor("#DDEEFF"); + static Color blueTextColor = HexColor("#2C5BDC"); + static Color borderColor = HexColor("#EEEEEE"); + static Color borderColorSingleLine = HexColor("#E0E0E0"); + + static Color iconColor = HexColor("#2E3A59"); + static Color progressBackColor = HexColor("#D5FCDA"); + static Color longTermBackColor = HexColor("#FFF3DA"); + static Color badgeColor = HexColor("#FF7C70"); + + static Color statusAccept = HexColor("#189A75"); + static Color statusNotAccept = HexColor("#DB5251"); + static Color statusAcceptBg = HexColor("#D4FCD9"); + static Color statusNotAcceptBg = HexColor("#FFEEE2"); + + static MaterialColor orangeThemeColor = const MaterialColor( + 0xFFF57C51, + const { + 50: const Color(0xFFF57C51), + 100: const Color(0xFFF57C51), + 200: const Color(0xFFF57C51), + 300: const Color(0xFFF57C51), + 400: const Color(0xFFF57C51), + 500: const Color(0xFFF57C51), + 600: const Color(0xFFF57C51), + 700: const Color(0xFFF57C51), + 800: const Color(0xFFF57C51), + 900: const Color(0xFFF57C51), + }, + ); +} + +class HexColor extends Color { + static int _getColorFromHex(String hexColor) { + hexColor = hexColor.toUpperCase().replaceAll("#", ""); + if (hexColor.length == 6) { + hexColor = "FF" + hexColor; + } + return int.parse(hexColor, radix: 16); + } + + HexColor(final String hexColor) : super(_getColorFromHex(hexColor)); +} diff --git a/lib/common/config/app_fonts.dart b/lib/common/config/app_fonts.dart new file mode 100644 index 0000000..c961261 --- /dev/null +++ b/lib/common/config/app_fonts.dart @@ -0,0 +1,149 @@ +import 'package:flutter/material.dart'; +import 'package:odoo_common_code_latest/common/config/app_colors.dart'; + +class AppFont { + AppFont._(); + + static const Roboto_Black = 'RobotoBlack'; + static const Roboto_BlackItalic = 'RobotoBlackItalic'; + static const Roboto_Bold = 'RobotoBold'; + static const Roboto_BoldItalic = 'RobotoBoldItalic'; + static const Roboto_Italic = 'RobotoItalic'; + static const Roboto_Light = 'RobotoLight'; + static const Roboto_LightItalic = 'RobotoLightItalic'; + static const Roboto_Medium = 'RobotoMedium'; + static const Roboto_MediumItalic = 'RobotoMediumItalic'; + static const Roboto_Regular = 'RobotoRegular'; + static const Roboto_Thin = 'RobotoThin'; + static const Roboto_ThinItalic = 'RobotoThinItalic'; + + static TextStyle Title_H2_Medium({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Medium, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.w500, + fontSize: size ?? 60, + ); + } + + static TextStyle Title_H3_Medium({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Medium, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.w500, + fontSize: size ?? 48, + ); + } + + static TextStyle Title_H4_Medium({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Medium, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.w500, + fontSize: size ?? 30, + ); + } + + static TextStyle Title_H4_Regular({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Light, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.w500, + fontSize: size ?? 30, + ); + } + + static TextStyle Title_H5_Medium({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Medium, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.w500, + fontSize: size ?? 24, + ); + } + + static TextStyle Title_H6_Medium({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Medium, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.w500, + fontSize: size ?? 20, + ); + } + + static TextStyle SubTitle1_Medium({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Medium, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.w500, + fontSize: size ?? 17, + ); + } + + static TextStyle SubTitle2_Medium({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Medium, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.w500, + fontSize: size ?? 15, + ); + } + + static TextStyle Body1_Regular({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Regular, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.normal, + fontSize: size ?? 17, + ); + } + + static TextStyle Body2_Regular({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Regular, + // fontStyle: FontStyle.normal, + // fontWeight: FontWeight.normal, + fontSize: size ?? 15, + ); + } + + static TextStyle Caption1_Body({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Regular, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.normal, + fontSize: size ?? 13, + ); + } + + static TextStyle Caption2_Title({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Medium, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.normal, + fontSize: size ?? 12, + ); + } + + static TextStyle Caption2_Body({Color? color, double? size}) { + return TextStyle( + color: color ?? AppColors.black, + fontFamily: Roboto_Regular, + //fontStyle: FontStyle.normal, + //fontWeight: FontWeight.normal, + fontSize: size ?? 12, + ); + } +} diff --git a/lib/common/config/app_images.dart b/lib/common/config/app_images.dart new file mode 100644 index 0000000..5562245 --- /dev/null +++ b/lib/common/config/app_images.dart @@ -0,0 +1,7 @@ +class AppImages { + AppImages._(); + + static const String basePath = "assets/images"; + + static const String ic_back = "$basePath/ic_back.png"; +} diff --git a/lib/common/config/config.dart b/lib/common/config/config.dart new file mode 100644 index 0000000..3432df9 --- /dev/null +++ b/lib/common/config/config.dart @@ -0,0 +1,33 @@ +import 'package:flutter/widgets.dart'; + +class Config { + Config._(); + + ///Odoo URLs + static const String OdooDevURL = "https://7983981-14-0-all.runbot36.odoo.com/"; + static const String OdooProdURL = "https://7983981-14-0-all.runbot36.odoo.com/"; + static const String OdooUATURL = "https://7983981-14-0-all.runbot36.odoo.com/"; + + /// SelfSignedCert: + static const selfSignedCert = false; + + /// API Config + static const timeout = 60000; + static const logNetworkRequest = true; + static const logNetworkRequestHeader = true; + static const logNetworkRequestBody = true; + static const logNetworkResponseHeader = false; + static const logNetworkResponseBody = true; + static const logNetworkError = true; + + /// Localization Config + static const supportedLocales = [Locale('en', ''), Locale('pt', '')]; + + /// Common Const + static const actionLocale = 'locale'; + static const int SIGNUP = 0; + static const int SIGNIN = 1; + static const String CURRENCY_SYMBOL = "€"; + static String FCM_TOKEN = ""; + static String DB = ""; +} diff --git a/lib/common/config/dependencies.dart b/lib/common/config/dependencies.dart new file mode 100644 index 0000000..74e7be2 --- /dev/null +++ b/lib/common/config/dependencies.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; +import 'package:odoo_common_code_latest/src/authentication/controllers/signin_controller.dart'; + +class Dependencies { + Dependencies._(); + + static void injectDependencies() { + Get.put(SignInController()); + } +} diff --git a/lib/common/config/extentions.dart b/lib/common/config/extentions.dart new file mode 100644 index 0000000..178c030 --- /dev/null +++ b/lib/common/config/extentions.dart @@ -0,0 +1,114 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +extension MyString on String { + String get first => this[0]; + + String get last => this[this.length - 1]; + + String get capitalize => "${this[0].toUpperCase()}${this.substring(1)}"; + + String get trimMobile => this.replaceAll(" ", ""); + + String get setDefaultVal => + (this.trim() == "") ? "..." : this; + + String get setPerc => this.trim() == "" ? "" : '$this%'; + + String get setNAVal => this.trim() == "" ? "N/A" : this; + + bool get isNullOrEmpty => (this.trim() == "") ? true : false; + + String get setChatId => (this.trim() == "") ? this : 'c$this'; + + int? get toInt => this.trim() == "" ? null : int.parse(this); + + Image image({color: Color}) { + return Image.asset( + this, + color: color, + ); + } + + CachedNetworkImage cachedImage( + {double? height, double? width, BoxFit? fit, String? placeholder}) => + CachedNetworkImage( + fit: fit ?? BoxFit.fill, + height: height ?? 20.0, + width: width ?? 20.0, + imageUrl: this, + progressIndicatorBuilder: (context, url, downloadProgress) => + CircularProgressIndicator(value: downloadProgress.progress), + errorWidget: (context, url, error) => placeholder != null + ? Image.asset(placeholder, fit: BoxFit.fill) + : Icon(Icons.error), + ); + + String setKVal() { + return '$this k'; + } + + String withCompany(String company) { + if (!this.isNullOrEmpty && !company.isNullOrEmpty) { + return this + ' at ' + company; + } else if (!this.isNullOrEmpty) { + return this; + } else if (!company.isNullOrEmpty) { + return company; + } else { + return this.setDefaultVal; + } + } +} + +extension MyInt on int { + bool get boolType => this == 0 ? false : true; + + String get setDigit => NumberFormat.compactCurrency( + decimalDigits: 0, + symbol: + '', // if you want to add currency symbol then pass that in this else leave it empty. + ).format(this ?? 0); + + String get setMonths => (this != null) + ? this.toString() + ' months' + : this.toString().setDefaultVal; + + String setFormatted(int val) { + return NumberFormat.currency(symbol: "", decimalDigits: 0).format(val); + } + + String setKVal() { + var val = this ?? 0; + return '$val\k'; + } + + String setPayscale() { + var val = this ?? 0; + return '${setFormatted(this)}/pm'; + } +} + +extension MyDateTime on DateTime { + String get getAgeInYears { + int ageInteger = 0; + + if (this != null) { + DateTime today = DateTime.now(); + today = DateTime(today.year, today.month, today.day); + DateTime dob = DateTime(this.year, this.month, this.day); + + ageInteger = today.year - dob.year; + + if (today.month == dob.month) { + if (today.day < dob.day) { + ageInteger = ageInteger - 1; + } + } else if (today.month < dob.month) { + ageInteger = ageInteger - 1; + } + } + return ageInteger.toString() + ' yr'; + } +} diff --git a/lib/common/config/localization/en.dart b/lib/common/config/localization/en.dart new file mode 100644 index 0000000..7a3a0a4 --- /dev/null +++ b/lib/common/config/localization/en.dart @@ -0,0 +1,14 @@ +import 'package:odoo_common_code_latest/common/config/localization/localize.dart'; + +class EN { + static Map Lang() { + return { + Localize.cancel: "Cancel", + Localize.done: "Done", + Localize.home: "Home", + Localize.password: "Password", + Localize.signin: "Sign In", + Localize.email: "Email", + }; + } +} diff --git a/lib/common/config/localization/localize.dart b/lib/common/config/localization/localize.dart new file mode 100644 index 0000000..bc7a1cf --- /dev/null +++ b/lib/common/config/localization/localize.dart @@ -0,0 +1,10 @@ +class Localize { + Localize._(); + + static String cancel = "cancel"; + static String done = "done"; + static String home = "home"; + static String password = "password"; + static String signin = "signin"; + static String email = "email"; +} diff --git a/lib/common/config/localization/translations.dart b/lib/common/config/localization/translations.dart new file mode 100644 index 0000000..f77dd28 --- /dev/null +++ b/lib/common/config/localization/translations.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; +import 'en.dart'; + +class AppTranslations extends Translations { + @override + // TODO: implement keys + Map> get keys => { + 'en': EN.Lang(), + }; +} diff --git a/lib/common/config/prefs/pref_keys.dart b/lib/common/config/prefs/pref_keys.dart new file mode 100644 index 0000000..8fe82d8 --- /dev/null +++ b/lib/common/config/prefs/pref_keys.dart @@ -0,0 +1,7 @@ +class PrefKeys { + PrefKeys._(); + + static const String user = "user"; + static const String token = "token"; + static const String isLoggedIn = "isLoggedIn"; +} diff --git a/lib/common/config/prefs/pref_utils.dart b/lib/common/config/prefs/pref_utils.dart new file mode 100644 index 0000000..8721841 --- /dev/null +++ b/lib/common/config/prefs/pref_utils.dart @@ -0,0 +1,45 @@ +import 'dart:convert'; +import 'package:odoo_common_code_latest/common/config/prefs/pref_keys.dart'; +import 'package:odoo_common_code_latest/src/authentication/models/user_model.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class PrefUtils { + PrefUtils(); + + static setToken(String token) async { + SharedPreferences preferences = await SharedPreferences.getInstance(); + await preferences.setString(PrefKeys.token, token); + } + + static Future getToken() async { + SharedPreferences preferences = await SharedPreferences.getInstance(); + return preferences.getString(PrefKeys.token) ?? ""; + } + + static setIsLoggedIn(bool isLoggedIn) async { + SharedPreferences preferences = await SharedPreferences.getInstance(); + await preferences.setBool(PrefKeys.isLoggedIn, isLoggedIn); + } + + static Future getIsLoggedIn() async { + SharedPreferences preferences = await SharedPreferences.getInstance(); + return preferences.getBool(PrefKeys.isLoggedIn) ?? false; + } + + static setUser(String userData) async { + SharedPreferences preferences = await SharedPreferences.getInstance(); + return preferences.setString(PrefKeys.user, userData); + } + + static Future getUser() async { + SharedPreferences preferences = await SharedPreferences.getInstance(); + Map user = + jsonDecode(preferences.getString(PrefKeys.user) ?? "{}"); + return UserModel.fromJson(user); + } + + static clearPrefs() async { + SharedPreferences preferences = await SharedPreferences.getInstance(); + await preferences.clear(); + } +} diff --git a/lib/common/utils/utils.dart b/lib/common/utils/utils.dart new file mode 100644 index 0000000..1a389dd --- /dev/null +++ b/lib/common/utils/utils.dart @@ -0,0 +1,287 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:odoo_common_code_latest/common/api_factory/models/base_list.dart'; +import 'package:odoo_common_code_latest/common/config/app_colors.dart'; +import 'package:odoo_common_code_latest/common/config/app_fonts.dart'; +import 'package:odoo_common_code_latest/common/config/app_images.dart'; +import 'package:odoo_common_code_latest/common/config/localization/localize.dart'; +import 'package:odoo_common_code_latest/common/config/prefs/pref_utils.dart'; +import 'package:odoo_common_code_latest/common/widgets/log.dart'; + +Future ackAlert( + BuildContext context, + String title, + String content, + VoidCallback onPressed, +) { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text(title), + titleTextStyle: TextStyle( + fontFamily: AppFont.Roboto_Regular, + fontSize: 21, + color: Colors.black, + fontWeight: FontWeight.bold, + ), + content: Text(content), + contentTextStyle: TextStyle( + fontFamily: AppFont.Roboto_Regular, + fontSize: 17, + color: Colors.black, + fontWeight: FontWeight.w500, + ), + actions: [ + TextButton( + child: Text( + Localize.done.tr, + style: TextStyle( + fontFamily: AppFont.Roboto_Regular, + fontSize: 17, + color: AppColors.blue, + fontWeight: FontWeight.bold, + ), + ), + onPressed: onPressed, + ), + ], + ); + }, + ); +} + +showLoading() { + Get.dialog( + Center( + child: SizedBox( + child: FittedBox(child: CircularProgressIndicator()), + height: 50.0, + width: 50.0, + ), + ), + barrierDismissible: false, + ); +} + +hideLoading() { + Get.back(); +} + +void showSnackBar( + {title, + message, + SnackPosition? snackPosition, + Color? backgroundColor, + Duration? duration}) { + Get.showSnackbar( + GetBar( + title: title, + message: message, + duration: duration ?? Duration(seconds: 2), + snackPosition: snackPosition ?? SnackPosition.BOTTOM, + backgroundColor: backgroundColor ?? Colors.black87, + ), + ); +} + +handleApiError(errorMessage) { + showSnackBar(backgroundColor: Colors.redAccent, message: errorMessage); +} + +showWarning(message) { + showSnackBar(backgroundColor: Colors.blueAccent, message: message); +} + +bool validatePassword(String password) { + return RegExp( + r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!@#\$&*~?]).{8,}$') + .hasMatch(password); +} + +bool validateEmail(String email) { + return RegExp( + r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") + .hasMatch(email); +} + +bool validURL(String url) { + return Uri.parse(url).isAbsolute; +} + +typedef OnItemsSelected(BaseListModel data); +typedef OnMultiItemSelected(List data); +typedef OnFilterSelected(String salary); + +//MARK - Open single select bottomsheet - +//----------------------------------- +showCustomBottomSheet({ + @required List? list, + @required String? title, + @required OnItemsSelected? onItemsSelected, + bool isMultiSelect = false, +}) { + Get.bottomSheet( + BottomSheet( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(30.0), + topLeft: Radius.circular(30.0), + ), + ), + onClosing: () { + Log("on Close bottom sheet"); + }, + builder: (context) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topRight: Radius.circular(30.0), + topLeft: Radius.circular(30.0), + ), + ), + padding: EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 40, + height: 4, + color: AppColors.greyDotColor, + ), + SizedBox( + height: 25, + ), + Row( + children: [ + InkWell( + onTap: () { + Get.back(); + }, + child: Image.asset(AppImages.ic_back), + ), + SizedBox( + width: 25, + ), + Text( + title ?? "", + style: AppFont.Title_H6_Medium(), + ), + isMultiSelect + ? Expanded( + child: Align( + alignment: Alignment.centerRight, + child: SizedBox( + height: 41, + width: 75, + child: MaterialButton( + elevation: 0.0, + color: AppColors.blueButtonColor, + onPressed: () { + var isSelectedItems = + list!.where((e) => e.isSelected).toList(); + if (isSelectedItems.length == 0) { + // showWarning(Localize.selectAnyItem.tr); + } else { + Get.back(result: isSelectedItems); + } + }, + child: Text( + Localize.done.tr, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.normal, + fontSize: 17, + ), + ), + textColor: AppColors.black, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ), + ) + : SizedBox(), + ], + ), + SizedBox( + height: 30, + ), + Expanded( + child: Container( + height: MediaQuery.of(context).size.height / 2 - 170, + child: ListView.builder( + shrinkWrap: true, + physics: ScrollPhysics(), + itemCount: list!.length, + itemBuilder: (context, index) { + return Container( + height: 50, + child: InkWell( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + list[index].name!, + style: AppFont.Body1_Regular(), + ), + list[index].isSelected + ? Icon(Icons.done) + : SizedBox() + ], + ), + onTap: () { + if (isMultiSelect) { + list[index].isSelected = !list[index].isSelected; + } else { + list[index].isSelected = !list[index].isSelected; + Get.back(result: list[index]); + } + }, + ), + ); + }, + ), + ), + ) + ], + ), + ); + }, + ), + ).then((value) { + FocusManager.instance.primaryFocus!.unfocus(); + onItemsSelected!(value); + Log(value); + }); +} + +showSessionDialog() { + Get.dialog( + AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + title: Text( + "Session Time out", + style: AppFont.Title_H4_Medium(), + ), + content: Text( + "Sorry! your session is expired, Please login again", + style: AppFont.Body2_Regular(), + ), + actions: [ + TextButton( + onPressed: () async { + PrefUtils.clearPrefs(); + }, + child: Text( + Localize.signin.tr, + style: AppFont.Body2_Regular(), + ), + ), + ], + ), + ); +} diff --git a/lib/common/widgets/custom_button.dart b/lib/common/widgets/custom_button.dart new file mode 100644 index 0000000..905b8d0 --- /dev/null +++ b/lib/common/widgets/custom_button.dart @@ -0,0 +1,26 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class CustomButton extends StatelessWidget { + var onPress; + Widget child; + var color; + + CustomButton({this.onPress, required this.child, this.color}); + + @override + Widget build(BuildContext context) { + return MaterialButton( + height: 56.0, + onPressed: onPress, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + textColor: Colors.white, + child: child, + color: color ?? Theme.of(context).accentColor, + ); + } +} diff --git a/lib/common/widgets/custom_drawer.dart b/lib/common/widgets/custom_drawer.dart new file mode 100644 index 0000000..9e0ec15 --- /dev/null +++ b/lib/common/widgets/custom_drawer.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +class CustomDrawer extends StatelessWidget { + CustomDrawer(); + + @override + Widget build(BuildContext context) { + return Drawer( + child: ListView( + children: [ + UserAccountsDrawerHeader( + currentAccountPicture: CircleAvatar( + radius: 30.0, + backgroundColor: Colors.transparent, + backgroundImage: NetworkImage( + "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5a/John_Doe%2C_born_John_Nommensen_Duchac.jpg/1200px-John_Doe%2C_born_John_Nommensen_Duchac.jpg", + ), + ), + accountName: Text("Mustafa Lokhandwala"), + accountEmail: Text("mustafa.mscit15@gmail.com"), + ), + ListTile( + leading: Icon(Icons.account_circle), + title: Text("Edit Profile"), + onTap: () {}, + ), + ], + ), + ); + } +} diff --git a/lib/common/widgets/date_picker.dart b/lib/common/widgets/date_picker.dart new file mode 100644 index 0000000..ca26499 --- /dev/null +++ b/lib/common/widgets/date_picker.dart @@ -0,0 +1,135 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:odoo_common_code_latest/common/config/localization/localize.dart'; + +typedef void OnDateChange(DateTime dateTime); +typedef void OnTimeChange(TimeOfDay dateTime); + +class DatePicker { + DatePicker(); + + var selectedDate = DateTime.now(); + OnDateChange? onDateChange; + var datePickerMode; + + show(BuildContext context, + {minimumDate, + maximumDate, + onDateChange, + onTimeChange, + selectedDate, + datePickerMode}) async { + final ThemeData theme = Theme.of(context); + switch (theme.platform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + return _buildMaterialDatePicker(context, onDateChange, onTimeChange, + minimumDate, maximumDate, selectedDate, datePickerMode); + case TargetPlatform.iOS: + case TargetPlatform.macOS: + return _buildCupertinoDatePicker(context, onDateChange, minimumDate, + maximumDate, selectedDate, datePickerMode); + } + } + + /// This builds material date picker in Android + _buildMaterialDatePicker( + BuildContext context, + OnDateChange onDateChange, + OnTimeChange onTimeChange, + DateTime? minimumDate, + DateTime? maximumDate, + DateTime? selectedDate, + var datePickerMode) async { + DateTime? picked = await showDatePicker( + context: context, + initialDate: selectedDate ?? this.selectedDate, + firstDate: minimumDate ?? DateTime(2000), + lastDate: maximumDate ?? DateTime(2050), + builder: (context, child) { + return Theme( + data: ThemeData.light(), + child: child ?? Container(), + ); + }, + ); + if (picked != null) { + this.selectedDate = picked; + if (datePickerMode == true) { + onDateChange(picked); + _buildTimePicker(context, onTimeChange); + } else { + onDateChange(picked); + } + } + } + + _buildTimePicker(BuildContext context, OnTimeChange onTimeChange) async { + final TimeOfDay picked = + await showTimePicker(context: context, initialTime: TimeOfDay.now()) ?? + TimeOfDay.now(); + onTimeChange(picked); + } + + /// This builds cupertion date picker in iOS + _buildCupertinoDatePicker( + BuildContext context, + OnDateChange onDateChange, + DateTime? minimumDate, + DateTime? maximumDate, + DateTime? selectedDate, + var datePickerMode) { + showModalBottomSheet( + context: context, + builder: (BuildContext builder) { + return Container( + height: MediaQuery.of(context).copyWith().size.height / 3, + color: Colors.white, + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(left: 10.0, right: 10.0), + child: Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + TextButton( + onPressed: () { + onDateChange(this.selectedDate); + Navigator.pop(context); + }, + child: Text(Localize.done.tr), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text(Localize.cancel.tr), + ), + ], + ), + ), + ), + Expanded( + child: CupertinoDatePicker( + mode: datePickerMode ?? CupertinoDatePickerMode.date, + onDateTimeChanged: (picked) { + this.selectedDate = picked; + onDateChange(picked); + }, + initialDateTime: selectedDate ?? this.selectedDate, + minimumDate: minimumDate ?? DateTime(2000), + maximumDate: maximumDate ?? DateTime(2050), + ), + ), + ], + ), + ); + }, + ); + } +} diff --git a/lib/common/widgets/empty_view.dart b/lib/common/widgets/empty_view.dart new file mode 100644 index 0000000..eb9adb8 --- /dev/null +++ b/lib/common/widgets/empty_view.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:odoo_common_code_latest/common/config/app_colors.dart'; +import 'package:odoo_common_code_latest/common/config/app_fonts.dart'; + +class EmptyView extends StatelessWidget { + String errorMsg; + + EmptyView({required this.errorMsg}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.only(right: 16.0), + alignment: Alignment.center, + child: Text( + errorMsg, + style: AppFont.Caption1_Body(color: AppColors.grey), + ), + ); + } +} diff --git a/lib/common/widgets/log.dart b/lib/common/widgets/log.dart new file mode 100644 index 0000000..052dac2 --- /dev/null +++ b/lib/common/widgets/log.dart @@ -0,0 +1,8 @@ +import 'package:flutter/foundation.dart'; + +class Log { + Log(var value) { + if (!kReleaseMode) + print("===============> ${value.toString()} <====================="); + } +} diff --git a/lib/common/widgets/main_container.dart b/lib/common/widgets/main_container.dart new file mode 100644 index 0000000..65330d9 --- /dev/null +++ b/lib/common/widgets/main_container.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; +import 'package:odoo_common_code_latest/common/config/app_fonts.dart'; + +class MainContainer extends StatelessWidget { + String? appBarTitle; + Widget child; + List? actions = []; + bool isAppBar = true; + Widget? leading; + Color? backgroundColor; + Widget? floatingActionButton; + double? padding, elevation; + Widget? bottomNavigationBar; + + MainContainer( + {required this.child, + this.backgroundColor, + this.appBarTitle, + this.isAppBar = true, + this.actions, + this.floatingActionButton, + this.padding, + this.elevation, + this.leading, + this.bottomNavigationBar}); + + @override + Widget build(BuildContext context) { + return Scaffold( + floatingActionButton: floatingActionButton ?? null, + appBar: isAppBar == true + ? AppBar( + iconTheme: IconThemeData(color: Colors.white), + leading: leading ?? null, + elevation: elevation ?? 0.0, + centerTitle: true, + actions: actions, + title: Text(appBarTitle ?? '', + style: AppFont.Title_H6_Medium(color: Colors.white)), + ) + : null, + body: SafeArea( + child: SingleChildScrollView( + padding: EdgeInsets.all(padding ?? 0.0), + child: child, + ), + ), + bottomNavigationBar: bottomNavigationBar ?? null, + ); + } +} diff --git a/lib/common/widgets/text_input.dart b/lib/common/widgets/text_input.dart new file mode 100644 index 0000000..15d679d --- /dev/null +++ b/lib/common/widgets/text_input.dart @@ -0,0 +1,155 @@ +import 'package:country_code_picker/country_code_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:odoo_common_code_latest/common/config/app_colors.dart'; + +typedef void OnChangeCountryCode(CountryCode countryCode); +typedef void OnFieldSubmitted(String text); + +class TextInput extends StatelessWidget { + TextEditingController controller; + String? validationMsg, + hintText, + labelText, + helperText, + prefixText, + suffixText; + Widget? prefix, suffix; + int? maxLength; + bool? isPassword, countryCodeEnabled, isEnabled; + bool? isSimpleField; + BorderRadius? borderRadius; + TextInputType? textInputType; + OnChangeCountryCode? onChangeCountryCode; + TextInputAction? textInputAction; + OnFieldSubmitted? onFieldSubmitted; + FocusNode? focusNode; + + TextInput( + {this.validationMsg, + required this.controller, + this.helperText, + this.suffixText, + this.prefixText, + this.prefix, + this.labelText, + this.hintText, + this.suffix, + this.textInputType, + this.isPassword, + this.maxLength, + this.countryCodeEnabled, + this.borderRadius, + this.isSimpleField, + this.onChangeCountryCode, + this.textInputAction, + this.onFieldSubmitted, + this.focusNode, + this.isEnabled}); + + @override + Widget build(BuildContext context) { + return TextFormField( + minLines: 1, + maxLines: isPassword != null && isPassword == true ? 1 : 4, + onFieldSubmitted: (value) => + onFieldSubmitted != null ? onFieldSubmitted!(value) : null, + focusNode: focusNode ?? null, + readOnly: isEnabled ?? false, + style: TextStyle( + fontSize: 17, + color: AppColors.black, + fontWeight: FontWeight.normal, + ), + controller: controller, + validator: (String? value) { + if (value == null) return null; + return value.isEmpty ? validationMsg ?? null : null; + }, + maxLength: maxLength ?? null, + obscureText: isPassword ?? false, + keyboardType: textInputType ?? TextInputType.text, + textInputAction: textInputAction ?? null, + decoration: isSimpleField == true + // For Under border input field + ? InputDecoration( + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide(width: 1, color: AppColors.borderColor), + ), + hintStyle: TextStyle( + fontSize: 17, + color: AppColors.lightGrey, + fontWeight: FontWeight.normal, + ), + labelStyle: TextStyle( + fontSize: 17, + color: AppColors.lightGrey, + fontWeight: FontWeight.normal, + height: 0, + ), + hintText: hintText ?? null, + helperText: helperText ?? null, + labelText: labelText ?? null, + prefixIcon: prefix ?? null, + suffixIcon: suffix ?? null, + prefixText: prefixText ?? null, + suffixText: suffixText ?? null, + counterText: "", + prefix: countryCodeEnabled == true + ? CountryCodePicker( + onChanged: (countryCode) { + onChangeCountryCode!(countryCode); + }, + initialSelection: 'IN', + showCountryOnly: true, + showOnlyCountryWhenClosed: false, + alignLeft: false, + ) + : null, + ) + // For Outlined border input field + : InputDecoration( + fillColor: AppColors.textFieldBackgroundColor, + filled: true, + enabledBorder: OutlineInputBorder( + borderRadius: borderRadius ?? BorderRadius.circular(5.0), + borderSide: BorderSide(width: 1, color: AppColors.borderColor), + ), + border: OutlineInputBorder( + borderRadius: borderRadius ?? BorderRadius.circular(5.0), + borderSide: BorderSide( + width: 1, + ), + ), + hintStyle: TextStyle( + fontSize: 17, + color: AppColors.lightGrey, + fontWeight: FontWeight.normal, + ), + labelStyle: TextStyle( + fontSize: 17, + color: AppColors.lightGrey, + fontWeight: FontWeight.normal, + ), + hintText: hintText ?? null, + helperText: helperText ?? null, + labelText: labelText ?? null, + prefixIcon: prefix ?? null, + suffixIcon: suffix ?? null, + prefixText: prefixText ?? null, + suffixText: suffixText ?? null, + counterText: "", + prefix: countryCodeEnabled == true + ? CountryCodePicker( + onChanged: (countryCode) { + onChangeCountryCode!(countryCode); + }, + initialSelection: 'IN', + showCountryOnly: true, + showOnlyCountryWhenClosed: false, + alignLeft: false, + ) + : null, + ), + ); + } +} diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart deleted file mode 100755 index 30fdb7a..0000000 --- a/lib/generated/i18n.dart +++ /dev/null @@ -1,126 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -// ignore_for_file: non_constant_identifier_names -// ignore_for_file: camel_case_types -// ignore_for_file: prefer_single_quotes - -// This file is automatically generated. DO NOT EDIT, all your changes would be lost. -class S implements WidgetsLocalizations { - const S(); - - static S current; - - static const GeneratedLocalizationsDelegate delegate = - GeneratedLocalizationsDelegate(); - - static S of(BuildContext context) => Localizations.of(context, S); - - @override - TextDirection get textDirection => TextDirection.ltr; - -} - -class $en extends S { - const $en(); -} - -class GeneratedLocalizationsDelegate extends LocalizationsDelegate { - const GeneratedLocalizationsDelegate(); - - List get supportedLocales { - return const [ - Locale("en", ""), - ]; - } - - LocaleListResolutionCallback listResolution({Locale fallback, bool withCountry = true}) { - return (List locales, Iterable supported) { - if (locales == null || locales.isEmpty) { - return fallback ?? supported.first; - } else { - return _resolve(locales.first, fallback, supported, withCountry); - } - }; - } - - LocaleResolutionCallback resolution({Locale fallback, bool withCountry = true}) { - return (Locale locale, Iterable supported) { - return _resolve(locale, fallback, supported, withCountry); - }; - } - - @override - Future load(Locale locale) { - final String lang = getLang(locale); - if (lang != null) { - switch (lang) { - case "en": - S.current = const $en(); - return SynchronousFuture(S.current); - default: - // NO-OP. - } - } - S.current = const S(); - return SynchronousFuture(S.current); - } - - @override - bool isSupported(Locale locale) => _isSupported(locale, true); - - @override - bool shouldReload(GeneratedLocalizationsDelegate old) => false; - - /// - /// Internal method to resolve a locale from a list of locales. - /// - Locale _resolve(Locale locale, Locale fallback, Iterable supported, bool withCountry) { - if (locale == null || !_isSupported(locale, withCountry)) { - return fallback ?? supported.first; - } - - final Locale languageLocale = Locale(locale.languageCode, ""); - if (supported.contains(locale)) { - return locale; - } else if (supported.contains(languageLocale)) { - return languageLocale; - } else { - final Locale fallbackLocale = fallback ?? supported.first; - return fallbackLocale; - } - } - - /// - /// Returns true if the specified locale is supported, false otherwise. - /// - bool _isSupported(Locale locale, bool withCountry) { - if (locale != null) { - for (Locale supportedLocale in supportedLocales) { - // Language must always match both locales. - if (supportedLocale.languageCode != locale.languageCode) { - continue; - } - - // If country code matches, return this locale. - if (supportedLocale.countryCode == locale.countryCode) { - return true; - } - - // If no country requirement is requested, check if this locale has no country. - if (true != withCountry && (supportedLocale.countryCode == null || supportedLocale.countryCode.isEmpty)) { - return true; - } - } - } - return false; - } -} - -String getLang(Locale l) => l == null - ? null - : l.countryCode != null && l.countryCode.isEmpty - ? l.languageCode - : l.toString(); diff --git a/lib/main.dart b/lib/main.dart index f35f851..2c6998a 100755 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,62 +1,17 @@ -import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:odoo_json_rpc_flutter/app/data/services/odoo_api.dart'; -import 'app/pages/home.dart'; -import 'app/pages/login.dart'; -import 'app/utility/strings.dart'; -import 'base.dart'; +import 'package:odoo_common_code_latest/common/api_factory/dio_factory.dart'; +import 'package:odoo_common_code_latest/common/app.dart'; +import 'package:odoo_common_code_latest/common/config/dependencies.dart'; +import 'package:odoo_common_code_latest/common/config/prefs/pref_utils.dart'; -class MyHttpOverrides extends HttpOverrides { - @override - HttpClient createHttpClient(SecurityContext context) { - return super.createHttpClient(context) - ..badCertificateCallback = - (X509Certificate cert, String host, int port) => true; - } -} - -void main() { - HttpOverrides.global = new MyHttpOverrides(); +void main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(App()); -} -class App extends StatefulWidget { - @override - _AppState createState() => _AppState(); -} + // Controller dependencies which we use throughout the app + Dependencies.injectDependencies(); -class _AppState extends Base { - @override - void initState() { - super.initState(); - } + DioFactory.initialiseHeaders(await PrefUtils.getToken()); - @override - Widget build(BuildContext context) { - return MaterialApp( - debugShowCheckedModeBanner: false, - title: Strings.app_title, - theme: ThemeData( - primarySwatch: Colors.indigo, - fontFamily: "Montserrat", - ), - home: FutureBuilder( - future: getOdooInstance(), - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.done: - return isLoggedIn() ? Home() : Login(); - default: - return new Container( - decoration: new BoxDecoration(color: Colors.white), - child: new Center( - child: CircularProgressIndicator(), - ), - ); - } - }, - ), - ); - } + bool isLoggedIn = await PrefUtils.getIsLoggedIn(); + runApp(App(isLoggedIn)); } diff --git a/lib/src/authentication/controllers/signin_controller.dart b/lib/src/authentication/controllers/signin_controller.dart new file mode 100644 index 0000000..bb0e359 --- /dev/null +++ b/lib/src/authentication/controllers/signin_controller.dart @@ -0,0 +1,13 @@ +import 'package:get/get.dart'; +import 'package:odoo_common_code_latest/common/config/prefs/pref_utils.dart'; +import 'package:odoo_common_code_latest/src/authentication/models/user_model.dart'; + +var currentUser = UserModel().obs; + +class SignInController extends GetxController { + @override + void onInit() async { + super.onInit(); + currentUser.value = await PrefUtils.getUser(); + } +} diff --git a/lib/src/authentication/models/user_model.dart b/lib/src/authentication/models/user_model.dart new file mode 100644 index 0000000..9f046f8 --- /dev/null +++ b/lib/src/authentication/models/user_model.dart @@ -0,0 +1,92 @@ +class UserModel { + UserModel({ + this.uid, + this.isAdmin, + this.db, + this.serverVersion, + this.name, + this.username, + this.partnerDisplayName, + this.companyId, + this.partnerId, + this.webBaseUrl, + this.showEffect, + this.displaySwitchCompanyMenu, + this.maxTimeBetweenKeysInMs, + this.outOfOfficeMessage, + }); + + int? uid; + bool? isAdmin; + String? db; + String? serverVersion; + String? name; + String? username; + String? partnerDisplayName; + int? companyId; + int? partnerId; + String? webBaseUrl; + String? showEffect; + bool? displaySwitchCompanyMenu; + int? maxTimeBetweenKeysInMs; + bool? outOfOfficeMessage; + + factory UserModel.fromJson(Map json) => UserModel( + uid: json["uid"], + isAdmin: json["is_admin"], + db: json["db"], + serverVersion: json["server_version"], + name: json["name"], + username: json["username"], + partnerDisplayName: json["partner_display_name"], + companyId: json["company_id"], + partnerId: json["partner_id"], + webBaseUrl: json["web.base.url"], + showEffect: json["show_effect"], + displaySwitchCompanyMenu: json["display_switch_company_menu"], + maxTimeBetweenKeysInMs: json["max_time_between_keys_in_ms"], + outOfOfficeMessage: json["out_of_office_message"], + ); + + Map toJson() => { + "uid": uid, + "is_admin": isAdmin, + "db": db, + "server_version": serverVersion, + "name": name, + "username": username, + "partner_display_name": partnerDisplayName, + "company_id": companyId, + "partner_id": partnerId, + "web.base.url": webBaseUrl, + "show_effect": showEffect, + "display_switch_company_menu": displaySwitchCompanyMenu, + "max_time_between_keys_in_ms": maxTimeBetweenKeysInMs, + "out_of_office_message": outOfOfficeMessage, + }; +} + +class Currency { + Currency({ + this.symbol, + this.position, + this.digits, + }); + + String? symbol; + String? position; + List? digits; + + factory Currency.fromJson(Map json) => Currency( + symbol: json["symbol"], + position: json["position"], + digits: List.from(json["digits"].map((x) => x)), + ); + + Map toJson() => { + "symbol": symbol, + "position": position, + "digits": List.from(digits!.map((x) => x)), + }; +} + diff --git a/lib/src/authentication/views/signin.dart b/lib/src/authentication/views/signin.dart new file mode 100644 index 0000000..7701fc6 --- /dev/null +++ b/lib/src/authentication/views/signin.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:odoo_common_code_latest/common/api_factory/modules/authentication_module.dart'; +import 'package:odoo_common_code_latest/common/config/app_colors.dart'; +import 'package:odoo_common_code_latest/common/config/localization/localize.dart'; +import 'package:odoo_common_code_latest/common/utils/utils.dart'; +import 'package:odoo_common_code_latest/common/widgets/custom_button.dart'; +import 'package:odoo_common_code_latest/common/widgets/main_container.dart'; +import 'package:odoo_common_code_latest/common/widgets/text_input.dart'; + +class SignIn extends StatefulWidget { + @override + _SignInState createState() => _SignInState(); +} + +class _SignInState extends State { + final TextEditingController _emailController = + TextEditingController(text: "admin"); + final TextEditingController _passCtrl = TextEditingController(text: "admin"); + + @override + void initState() { + super.initState(); + getVersionInfoAPI(); + } + + @override + Widget build(BuildContext context) { + return MainContainer( + isAppBar: true, + appBarTitle: Localize.signin.tr, + padding: 20.0, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + height: MediaQuery.of(context).size.height / 4, + ), + TextInput( + textInputAction: TextInputAction.next, + borderRadius: BorderRadius.circular(10.0), + controller: _emailController, + textInputType: TextInputType.emailAddress, + hintText: Localize.email.tr, + ), + SizedBox( + height: 12, + ), + TextInput( + borderRadius: BorderRadius.circular(10.0), + controller: _passCtrl, + isPassword: true, + hintText: Localize.password.tr, + ), + SizedBox( + height: 17, + ), + SizedBox( + height: 55, + child: CustomButton( + color: AppColors.orange, + onPress: () { + FocusManager.instance.primaryFocus!.unfocus(); + if (_emailController.text.isEmpty) { + showWarning("Please enter email"); + } else if (_passCtrl.text.isEmpty) { + showWarning("Please enter password"); + } else { + authenticationAPI(_emailController.text, _passCtrl.text); + } + }, + child: Text( + Localize.signin.tr, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.normal, + fontSize: 17, + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/home/controller/home_controller.dart b/lib/src/home/controller/home_controller.dart new file mode 100644 index 0000000..5af1b36 --- /dev/null +++ b/lib/src/home/controller/home_controller.dart @@ -0,0 +1,21 @@ +import 'package:get/get.dart'; +import 'package:odoo_common_code_latest/common/api_factory/modules/home_api_module.dart'; +import 'package:odoo_common_code_latest/src/home/model/res_partner_model.dart'; + +class HomeController extends GetxController { + var listOfPartners = [].obs; + + @override + void onInit() { + super.onInit(); + _getPartners(); + } + + _getPartners() { + resPartnerApi( + onResponse: (response) { + listOfPartners.assignAll(response.records!); + }, + ); + } +} diff --git a/lib/src/home/model/res_partner_model.dart b/lib/src/home/model/res_partner_model.dart new file mode 100644 index 0000000..bd756f2 --- /dev/null +++ b/lib/src/home/model/res_partner_model.dart @@ -0,0 +1,47 @@ +class ResPartnerModel { + List? records; + + ResPartnerModel({this.records}); + + ResPartnerModel.fromJson(dynamic json) { + if (json["records"] != null) { + records = []; + json["records"].forEach((v) { + records?.add(Records.fromJson(v)); + }); + } + } + + Map toJson() { + var map = {}; + if (records != null) { + map["records"] = records?.map((v) => v.toJson()).toList(); + } + return map; + } +} + +class Records { + int? id; + String? name; + String? email; + String? image512; + + Records({this.id, this.name, this.email, this.image512}); + + Records.fromJson(dynamic json) { + id = json["id"]; + name = json["name"]; + email = json["email"] is! bool ? json["email"] : ""; + image512 = json["image_512"] is! bool ? json["image_512"] : ""; + } + + Map toJson() { + var map = {}; + map["id"] = id; + map["name"] = name; + map["email"] = email; + map["image_512"] = image512; + return map; + } +} diff --git a/lib/src/home/view/home.dart b/lib/src/home/view/home.dart new file mode 100644 index 0000000..7856051 --- /dev/null +++ b/lib/src/home/view/home.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:odoo_common_code_latest/common/widgets/main_container.dart'; +import 'package:odoo_common_code_latest/src/home/controller/home_controller.dart'; + +class Home extends StatelessWidget { + final _homeController = Get.put(HomeController()); + + @override + Widget build(BuildContext context) { + return MainContainer( + isAppBar: true, + appBarTitle: "Home", + padding: 20.0, + child: Obx( + () { + return ListView.builder( + shrinkWrap: true, + physics: ScrollPhysics(), + itemCount: _homeController.listOfPartners.length, + itemBuilder: (context, index) { + return ListTile( + // leading: CircleAvatar( + // child: CachedNetworkImage( + // imageUrl: '', + // + // ), + // ), + title: Text(_homeController.listOfPartners[index].name!), + subtitle: Text(_homeController.listOfPartners[index].email!), + ); + }, + ); + }, + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 6b54869..c89ac24 100755 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,95 +1,156 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + action_broadcast: + dependency: "direct main" + description: + name: action_broadcast + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.2" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.1" + version: "2.6.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.3" - convert: - dependency: transitive + version: "1.15.0" + country_code_picker: + dependency: "direct main" description: - name: convert + name: country_code_picker url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.0.1" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "3.0.1" cupertino_icons: dependency: "direct main" description: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.3" + device_info: + dependency: "direct main" + description: + name: device_info + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + device_info_platform_interface: + dependency: transitive + description: + name: device_info_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + dio: + dependency: "direct main" + description: + name: dio + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" ffi: dependency: transitive description: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "1.0.0" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "5.2.1" + version: "6.1.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_blurhash: + dependency: transitive + description: + name: flutter_blurhash + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -100,146 +161,202 @@ packages: description: flutter source: sdk version: "0.0.0" - http: + get: dependency: "direct main" + description: + name: get + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.4" + http: + dependency: transitive description: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.12.2" + version: "0.13.3" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.4" - intl: + version: "4.0.0" + image: dependency: transitive description: - name: intl + name: image url: "https://pub.dartlang.org" source: hosted - version: "0.16.1" - loading: + version: "3.0.2" + intl: dependency: "direct main" description: - name: loading + name: intl url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "0.17.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.1" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" + modal_bottom_sheet: + dependency: transitive + description: + name: modal_bottom_sheet + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + octo_image: + dependency: transitive + description: + name: octo_image + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0+1" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.1" + version: "1.8.0" + path_provider: + dependency: "direct main" + description: + name: path_provider + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+2" + version: "2.0.0" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+3" + version: "2.0.1" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.9.2" + version: "1.11.0" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" platform: dependency: transitive description: name: platform url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.0.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.0" process: dependency: transitive description: name: process url: "https://pub.dartlang.org" source: hosted - version: "3.0.13" + version: "4.2.1" + rxdart: + dependency: transitive + description: + name: rxdart + url: "https://pub.dartlang.org" + source: hosted + version: "0.27.0" shared_preferences: dependency: "direct main" description: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "0.5.12+4" + version: "2.0.5" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.2+4" + version: "2.0.0" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+11" + version: "2.0.0" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web url: "https://pub.dartlang.org" source: hosted - version: "0.1.2+7" + version: "2.0.0" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+3" + version: "2.0.0" sky_engine: dependency: transitive description: flutter @@ -251,84 +368,112 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.2" - sprintf: - dependency: "direct main" + version: "1.8.1" + sqflite: + dependency: transitive description: - name: sprintf + name: sqflite url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "2.0.0+3" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0+2" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.2" + version: "0.3.0" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" + universal_platform: + dependency: transitive + description: + name: universal_platform + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0-nullsafety" uuid: - dependency: "direct main" + dependency: transitive description: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "2.2.2" + version: "3.0.4" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "1.7.3" + version: "2.1.1" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "0.2.0" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" sdks: - dart: ">=2.10.0-110 <2.11.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + dart: ">=2.13.0 <3.0.0" + flutter: ">=1.24.0-10.2.pre" diff --git a/pubspec.yaml b/pubspec.yaml index b78cfc1..0de4466 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,20 +1,104 @@ -name: odoo_json_rpc_flutter -description: A new Flutter application. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +name: odoo_common_code_latest +description: A new Flutter project. + +publish_to: 'none' + version: 1.0.0+1 + environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" + dependencies: + flutter_localizations: + sdk: flutter flutter: sdk: flutter - cupertino_icons: ^1.0.0 - uuid: ^2.2.2 - http: ^0.12.2 - shared_preferences: ^0.5.12+4 - sprintf: ^5.0.0 - loading: ^1.0.2 + + cupertino_icons: ^1.0.3 + intl: ^0.17.0 + device_info: ^2.0.1 + dio: ^4.0.0 + shared_preferences: ^2.0.5 + get: ^4.1.4 + action_broadcast: ^3.0.0 + country_code_picker: ^2.0.1 + path_provider: ^2.0.1 + cached_network_image: ^3.0.0 + + dev_dependencies: flutter_test: sdk: flutter + flutter: - uses-material-design: true \ No newline at end of file + fonts: + - family: RobotoBlack + fonts: + - asset: assets/fonts/Roboto-Black.ttf + - family: RobotoBlackItalic + fonts: + - asset: assets/fonts/Roboto-BlackItalic.ttf + - family: RobotoBold + fonts: + - asset: assets/fonts/Roboto-Bold.ttf + - family: RobotoBoldItalic + fonts: + - asset: assets/fonts/Roboto-BoldItalic.ttf + - family: RobotoItalic + fonts: + - asset: assets/fonts/Roboto-Italic.ttf + - family: RobotoLight + fonts: + - asset: assets/fonts/Roboto-Light.ttf + - family: RobotoLightItalic + fonts: + - asset: assets/fonts/Roboto-LightItalic.ttf + - family: RobotoMedium + fonts: + - asset: assets/fonts/Roboto-Medium.ttf + - family: RobotoMediumItalic + fonts: + - asset: assets/fonts/Roboto-MediumItalic.ttf + - family: RobotoRegular + fonts: + - asset: assets/fonts/Roboto-Regular.ttf + - family: RobotoThin + fonts: + - asset: assets/fonts/Roboto-Thin.ttf + - family: RobotoThinItalic + fonts: + - asset: assets/fonts/Roboto-ThinItalic.ttf + uses-material-design: true + assets: + - assets/images/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/widget_test.dart b/test/widget_test.dart index f5b8a46..9ca1bce 100755 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -1,12 +1,20 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:odoo_common_code_latest/common/app.dart'; -import 'package:odoo_json_rpc_flutter/main.dart'; +import 'package:odoo_common_code_latest/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(App()); + await tester.pumpWidget(App(false)); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget);