commit 024e6ad920a7c6f1b83bfbb2c10340b393a470a5 Author: Komek Hayytnazarov Date: Mon Feb 27 12:12:45 2023 +0500 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0fa6b67 --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +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 new file mode 100644 index 0000000..be0f63d --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 4cc385b4b84ac2f816d939a49ea1f328c4e0b48e + channel: stable + +project_type: app diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..68fa48c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,29 @@ +{ + "cSpell.words": [ + "curr", + "draggable", + "elektronika", + "onepage", + "Prefs", + "pubspec", + "unfocus", + "vsync" + ], + "todohighlight.isEnable": true, + "todohighlight.isCaseSensitive": true, + "todohighlight.keywords": [ + "DEBUG:", + "REVIEW:", + { + "text": "NOTE:", + "color": "black", + "backgroundColor": "white", + "overviewRulerColor": "grey" + }, + { + "text": "HACK:", + "color": "#000", + "isWholeLine": false, + }, + ], +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..065af70 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# elektronika + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://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. +# elektronika_shop diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..db31fcf --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,278 @@ +# include: package:lint/analysis_options.yaml +analyzer: + # strong-mode: + # Will become the default once non-nullable types land + # https://github.com/dart-lang/sdk/issues/31410#issuecomment-510683629 + # implicit-casts: false + errors: + # treat missing required parameters as a warning (not a hint) + missing_required_param: warning + # treat missing returns as a warning (not a hint) + missing_return: warning + todo: ignore +# Rules are in the same order (alphabetically) as documented at http://dart-lang.github.io/linter/lints +# and https://github.com/dart-lang/linter/blob/master/example/all.yaml +linter: + rules: + # Prevents accidental return type changes which results in a breaking API change. + # Enforcing return type makes API changes visible in a diff + # pedantic: enabled + # http://dart-lang.github.io/linter/lints/always_declare_return_types.html + - always_declare_return_types + + # Single line `if`s are fine as recommended in Effective Dart "DO format your code using dartfmt" + # pedantic: disabled + # http://dart-lang.github.io/linter/lints/always_put_control_body_on_new_line.html + # - always_put_control_body_on_new_line + + # Flutter widgets always put a Key as first optional parameter which breaks this rule. + # Also violates other orderings like matching the class fields or alphabetically. + # pedantic: disabled + # http://dart-lang.github.io/linter/lints/always_declare_return_types.html + # - always_put_required_named_parameters_first + + # All non nullable named parameters should be and annotated with @required. + # This allows API consumers to get warnings via lint rather than a crash a runtime. + # Might become obsolete with Non-Nullable types + # pedantic: enabled + # http://dart-lang.github.io/linter/lints/always_require_non_null_named_parameters.html + - always_require_non_null_named_parameters + + # Since dart 2.0 dart is a sound language, specifying types is not required anymore. + # `var foo = 10;` is enough information for the compiler to make foo a int. + # Violates Effective Dart "AVOID type annotating initialized local variables". + # Makes code unnecessarily complex https://github.com/dart-lang/linter/issues/1620 + # pedantic: disabled + # http://dart-lang.github.io/linter/lints/always_specify_types.html + # - always_specify_types + + # Protect against unintentionally overriding superclass members + # pedantic: enabled + # http://dart-lang.github.io/linter/lints/annotate_overrides.html + - annotate_overrides + + # All methods should define a return type. dynamic is no exception. + # Violates Effective Dart "PREFER annotating with dynamic instead of letting inference fail" + # pedantic: disabled + # http://dart-lang.github.io/linter/lints/avoid_annotating_with_dynamic.html + # - avoid_annotating_with_dynamic + + # A leftover from dart1, should be deprecated + # pedantic: disabled + # - https://github.com/dart-lang/linter/issues/1401 + # http://dart-lang.github.io/linter/lints/avoid_as.html + # - avoid_as + + # Highlights boolean expressions which can be simplified + # http://dart-lang.github.io/linter/lints/avoid_bool_literals_in_conditional_expressions.html + - avoid_bool_literals_in_conditional_expressions + + # There are no strong arguments to enable this rule because it is very strict. Catching anything is useful + # and common even if not always the most correct thing to do. + # pedantic: disabled + # http://dart-lang.github.io/linter/lints/avoid_catches_without_on_clauses.html + # - avoid_catches_without_on_clauses + + # Errors aren't for catching but to prevent prior to runtime + # pedantic: disabled + # http://dart-lang.github.io/linter/lints/avoid_catching_errors.html + - avoid_catching_errors + + # Can usually be replaced with an extension + # pedantic: disabled + # http://dart-lang.github.io/linter/lints/avoid_classes_with_only_static_members.html + # - avoid_classes_with_only_static_members + + # Never accidentally use dynamic invocations + # Dart SDK: unreleased • (Linter vnull) + # https://dart-lang.github.io/linter/lints/avoid_dynamic_calls.html + # avoid_dynamic_calls + + # Only useful when targeting JS + # pedantic: disabled + # http://dart-lang.github.io/linter/lints/avoid_double_and_int_checks.html + # - avoid_double_and_int_checks + + # Prevents accidental empty else cases. See samples in documentation + # pedantic: enabled + # http://dart-lang.github.io/linter/lints/avoid_empty_else.html + - avoid_empty_else + + # It is expected that mutable objects which override hash & equals shouldn't be used as keys for hashmaps. + # This one use case doesn't make all hash & equals implementations for mutable classes bad. + # pedantic: disabled + # https://dart-lang.github.io/linter/lints/avoid_equals_and_hash_code_on_mutable_classes.html + # - avoid_equals_and_hash_code_on_mutable_classes + + # Use different quotes instead of escaping + # Dart SDK: >= 2.8.0-dev.11.0 • (Linter v0.1.111) + # https://dart-lang.github.io/linter/lints/avoid_escaping_inner_quotes.html + - avoid_escaping_inner_quotes + + # Prevents unnecessary allocation of a field + # pedantic: disabled + # http://dart-lang.github.io/linter/lints/avoid_field_initializers_in_const_classes.html + - avoid_field_initializers_in_const_classes + + # Prevents allocating a lambda and allows return/break/continue control flow statements inside the loop + # http://dart-lang.github.io/linter/lints/avoid_function_literals_in_foreach_calls.html + - avoid_function_literals_in_foreach_calls + + # Don't break value types by implementing them + # http://dart-lang.github.io/linter/lints/avoid_implementing_value_types.html + - avoid_implementing_value_types + + # Removes redundant `= null;` + # https://dart-lang.github.io/linter/lints/avoid_init_to_null.html + - avoid_init_to_null + + # Only useful when targeting JS + # Warns about too large integers when compiling to JS + # pedantic: disabled + # https://dart-lang.github.io/linter/lints/avoid_js_rounded_ints.html + # - avoid_js_rounded_ints + + # Null checks aren't required in ==() operators + # pedantic: enabled + # https://dart-lang.github.io/linter/lints/avoid_null_checks_in_equality_operators.html + - avoid_null_checks_in_equality_operators + + # Good APIs don't use ambiguous boolean parameters. Instead use named parameters + # https://dart-lang.github.io/linter/lints/avoid_positional_boolean_parameters.html + - avoid_positional_boolean_parameters + + # Don't call print in production code + # pedantic: disabled + # https://dart-lang.github.io/linter/lints/avoid_print.html + - avoid_print + + # Always prefer function references over typedefs. + # Jumping twice in code to see the signature of a lambda sucks. This is different from the flutter analysis_options + # https://dart-lang.github.io/linter/lints/avoid_private_typedef_functions.html + - avoid_private_typedef_functions + + # Don't explicitly set defaults + # Dart SDK: >= 2.8.0-dev.1.0 • (Linter v0.1.107) + # https://dart-lang.github.io/linter/lints/avoid_redundant_argument_values.html + - avoid_redundant_argument_values + + # package or relative? Let's end the discussion and use package everywhere. + # pedantic: enabled + # https://dart-lang.github.io/linter/lints/avoid_relative_lib_imports.html + - avoid_relative_lib_imports + + # Not recommended to break dartdoc but besides that there is no reason to continue with bad naming + # https://dart-lang.github.io/linter/lints/avoid_renaming_method_parameters.html + # - avoid_renaming_method_parameters + + # Setters always return void, therefore defining void is redundant + # pedantic: enabled + # https://dart-lang.github.io/linter/lints/avoid_return_types_on_setters.html + - avoid_return_types_on_setters + + # Especially with Non-Nullable types on the horizon, `int?` is fine. + # There are plenty of valid reasons to return null. + # pedantic: disabled + # https://dart-lang.github.io/linter/lints/avoid_returning_null.html + # - avoid_returning_null + + # Don't use `Future?`, therefore never return null instead of a Future. + # Will become obsolete one Non-Nullable types land + # https://dart-lang.github.io/linter/lints/avoid_returning_null_for_future.html + - avoid_returning_null_for_future + + # Use empty returns, don't show off with you knowledge about dart internals. + # https://dart-lang.github.io/linter/lints/avoid_returning_null_for_void.html + - avoid_returning_null_for_void + + # Hinting you forgot about the cascade operator. But too often you did this on purpose. + # There are plenty of valid reasons to return this. + # pedantic: disabled + # https://dart-lang.github.io/linter/lints/avoid_returning_this.html + # - avoid_returning_this + + # Prevents logical inconsistencies. It's good practice to define getters for all existing setters. + # https://dart-lang.github.io/linter/lints/avoid_setters_without_getters.html + - avoid_setters_without_getters + + # Don't reuse a type parameter when on with the same name already exists in the same scope + # pedantic: enabled + # https://dart-lang.github.io/linter/lints/avoid_shadowing_type_parameters.html + - avoid_shadowing_type_parameters + + # A single cascade operator can be replaced with a normal method call + # pedantic: enabled + # https://dart-lang.github.io/linter/lints/avoid_single_cascade_in_expression_statements.html + - avoid_single_cascade_in_expression_statements + + # Might cause frame drops because of synchronous file access on mobile, especially on older phones with slow storage. + # There are no known measurements sync access does *not* drop frames. + # pedantic: disabled + # https://dart-lang.github.io/linter/lints/avoid_slow_async_io.html + # - avoid_slow_async_io + + # Don't use .toString() in production code which might be minified + # Dart SDK: >= 2.10.0-144.0.dev • (Linter v0.1.119) + # https://dart-lang.github.io/linter/lints/avoid_type_to_string.html + - avoid_type_to_string + + # Don't use a parameter names which can be confused with a types (i.e. int, bool, num, ...) + # pedantic: enabled + # https://dart-lang.github.io/linter/lints/avoid_types_as_parameter_names.html + - avoid_types_as_parameter_names + + # Adding the type is not required, but sometimes improves readability. Therefore removing it doesn't always help + # https://dart-lang.github.io/linter/lints/avoid_types_on_closure_parameters.html + # - avoid_types_on_closure_parameters + + # Containers without parameters have no effect and can be removed + # https://dart-lang.github.io/linter/lints/avoid_unnecessary_containers.html + - avoid_unnecessary_containers + + # Unused parameters should be removed + # https://dart-lang.github.io/linter/lints/avoid_unused_constructor_parameters.html + - avoid_unused_constructor_parameters + + # TODO double check + # For async functions use `Future` as return value, not `void` + # This allows usage of the await keyword and prevents operations from running in parallel. + # pedantic: disabled + # https://dart-lang.github.io/linter/lints/avoid_void_async.html + - avoid_void_async + + # Flutter mobile only: Web packages aren't available in mobile flutter apps + # https://dart-lang.github.io/linter/lints/avoid_web_libraries_in_flutter.html + - avoid_web_libraries_in_flutter + + # Use the await keyword only for futures. There is nothing to await in synchronous code + # pedantic: enabled + # https://dart-lang.github.io/linter/lints/await_only_futures.html + - await_only_futures + + # Follow the style guide and use UpperCamelCase for extensions + # pedantic: enabled + # https://dart-lang.github.io/linter/lints/camel_case_extensions.html + - camel_case_extensions + + # Follow the style guide and use UpperCamelCase for class names and typedefs + # https://dart-lang.github.io/linter/lints/camel_case_types.html + - camel_case_types + + # Prevents leaks and code executing after their lifecycle. + # Discussion https://github.com/passsy/dart-lint/issues/4 + # + # pedantic: disabled + # https://dart-lang.github.io/linter/lints/cancel_subscriptions.html + - cancel_subscriptions + + - prefer_single_quotes + + # The cascade syntax is weird and you shouldn't be forced to use it. + # False positives: + # https://github.com/dart-lang/linter/issues/1589 + # + # https://dart-lang.github.io/linter/lints/cascade_invocations.html + # - cascade_invocations + + # Don't cast T? to T. Use ! instead + # Dart SDK: >= 2.11.0-182.0.dev • (Linter v0.1.120 \ No newline at end of file diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..e55e78f --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,81 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + +android { + compileSdkVersion 31 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.elektronika.tm" + minSdkVersion 20 //TODO: Change to 16 in production + targetSdkVersion 31 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } + + buildTypes { + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..2222447 --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..0f91158 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/elektronika/MainActivity.kt b/android/app/src/main/kotlin/com/example/elektronika/MainActivity.kt new file mode 100644 index 0000000..2c366a9 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/elektronika/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.elektronika + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png new file mode 100644 index 0000000..1448d35 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png new file mode 100644 index 0000000..f7019ec Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png new file mode 100644 index 0000000..0d2e270 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png new file mode 100644 index 0000000..dd75349 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png new file mode 100644 index 0000000..7ff722e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 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 new file mode 100644 index 0000000..d74aa35 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..2222447 --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..ba6fe4a --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.1.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..94adc3a --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..595fb86 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip diff --git a/android/key.properties.example b/android/key.properties.example new file mode 100644 index 0000000..18c6392 --- /dev/null +++ b/android/key.properties.example @@ -0,0 +1,4 @@ +storePassword=TPSELEKTRONIKA +keyPassword=TPSELEKTRONIKA +keyAlias=upload +storeFile=upload-keystore.jks \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/assets/appbar/cart_icon.svg b/assets/appbar/cart_icon.svg new file mode 100644 index 0000000..b049455 --- /dev/null +++ b/assets/appbar/cart_icon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/appbar/menu_icon.svg b/assets/appbar/menu_icon.svg new file mode 100644 index 0000000..6babf75 --- /dev/null +++ b/assets/appbar/menu_icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/cart/cart_empty.svg b/assets/cart/cart_empty.svg new file mode 100644 index 0000000..8f942d9 --- /dev/null +++ b/assets/cart/cart_empty.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/assets/category/filter.svg b/assets/category/filter.svg new file mode 100644 index 0000000..899eea9 --- /dev/null +++ b/assets/category/filter.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/category/sort.svg b/assets/category/sort.svg new file mode 100644 index 0000000..ce9f094 --- /dev/null +++ b/assets/category/sort.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/flags/ru.png b/assets/flags/ru.png new file mode 100755 index 0000000..8b8293c Binary files /dev/null and b/assets/flags/ru.png differ diff --git a/assets/flags/tm.png b/assets/flags/tm.png new file mode 100755 index 0000000..e0af17a Binary files /dev/null and b/assets/flags/tm.png differ diff --git a/assets/icons/coupon_applied_icon.svg b/assets/icons/coupon_applied_icon.svg new file mode 100644 index 0000000..4428569 --- /dev/null +++ b/assets/icons/coupon_applied_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/drag_line.svg b/assets/icons/drag_line.svg new file mode 100644 index 0000000..6248d0d --- /dev/null +++ b/assets/icons/drag_line.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/filter.svg b/assets/icons/filter.svg new file mode 100644 index 0000000..899eea9 --- /dev/null +++ b/assets/icons/filter.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/love_icon.svg b/assets/icons/love_icon.svg new file mode 100644 index 0000000..6b13151 --- /dev/null +++ b/assets/icons/love_icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/icons/sort.svg b/assets/icons/sort.svg new file mode 100644 index 0000000..ce9f094 --- /dev/null +++ b/assets/icons/sort.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/trash_icon.svg b/assets/icons/trash_icon.svg new file mode 100644 index 0000000..58cb266 --- /dev/null +++ b/assets/icons/trash_icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/images/error.svg b/assets/images/error.svg new file mode 100644 index 0000000..21720ec --- /dev/null +++ b/assets/images/error.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/no-results.png b/assets/images/no-results.png new file mode 100644 index 0000000..85f438d Binary files /dev/null and b/assets/images/no-results.png differ diff --git a/assets/images/product_not_found.svg b/assets/images/product_not_found.svg new file mode 100644 index 0000000..5379714 --- /dev/null +++ b/assets/images/product_not_found.svg @@ -0,0 +1,140 @@ +x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/logo/icon.png b/assets/logo/icon.png new file mode 100644 index 0000000..37fd47c Binary files /dev/null and b/assets/logo/icon.png differ diff --git a/assets/logo/logo.svg b/assets/logo/logo.svg new file mode 100644 index 0000000..41e2d58 --- /dev/null +++ b/assets/logo/logo.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/assets/navbar/home.svg b/assets/navbar/home.svg new file mode 100644 index 0000000..9485170 --- /dev/null +++ b/assets/navbar/home.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/navbar/layout.svg b/assets/navbar/layout.svg new file mode 100644 index 0000000..f65f09e --- /dev/null +++ b/assets/navbar/layout.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/navbar/settings.svg b/assets/navbar/settings.svg new file mode 100644 index 0000000..c36a888 --- /dev/null +++ b/assets/navbar/settings.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/navbar/user.svg b/assets/navbar/user.svg new file mode 100644 index 0000000..1077727 --- /dev/null +++ b/assets/navbar/user.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/other/300x300.jpg b/assets/other/300x300.jpg new file mode 100644 index 0000000..f6ce991 Binary files /dev/null and b/assets/other/300x300.jpg differ diff --git a/assets/other/phone.jpg b/assets/other/phone.jpg new file mode 100644 index 0000000..448c446 Binary files /dev/null and b/assets/other/phone.jpg differ diff --git a/assets/profile/archive.svg b/assets/profile/archive.svg new file mode 100644 index 0000000..a3ad4f7 --- /dev/null +++ b/assets/profile/archive.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/profile/coin.svg b/assets/profile/coin.svg new file mode 100644 index 0000000..5aa7741 --- /dev/null +++ b/assets/profile/coin.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/profile/heart.svg b/assets/profile/heart.svg new file mode 100644 index 0000000..57da680 --- /dev/null +++ b/assets/profile/heart.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/profile/log-out.svg b/assets/profile/log-out.svg new file mode 100644 index 0000000..ce72ea4 --- /dev/null +++ b/assets/profile/log-out.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/profile/remove-user.svg b/assets/profile/remove-user.svg new file mode 100644 index 0000000..af8ddc7 --- /dev/null +++ b/assets/profile/remove-user.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/profile/user.svg b/assets/profile/user.svg new file mode 100644 index 0000000..8802ca9 --- /dev/null +++ b/assets/profile/user.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/settings/mail-inbox-app.svg b/assets/settings/mail-inbox-app.svg new file mode 100644 index 0000000..1411106 --- /dev/null +++ b/assets/settings/mail-inbox-app.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/settings/phone-call.svg b/assets/settings/phone-call.svg new file mode 100644 index 0000000..809fc79 --- /dev/null +++ b/assets/settings/phone-call.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/settings/translate.svg b/assets/settings/translate.svg new file mode 100644 index 0000000..4502985 --- /dev/null +++ b/assets/settings/translate.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/settings/writing.svg b/assets/settings/writing.svg new file mode 100644 index 0000000..51e452f --- /dev/null +++ b/assets/settings/writing.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/assets/splash/splash_screen.png b/assets/splash/splash_screen.png new file mode 100644 index 0000000..0f8fe6d Binary files /dev/null and b/assets/splash/splash_screen.png differ diff --git a/cspell.json b/cspell.json new file mode 100644 index 0000000..23a382b --- /dev/null +++ b/cspell.json @@ -0,0 +1,23 @@ +{ + "version": "0.2", + "ignorePaths": [ + "lib/app/core/lang/ru_ru.dart", + "lib/app/core/lang/tm_tm.dart" + ], + "dictionaryDefinitions": [], + "dictionaries": [], + "words": [ + "dili", + "fluttericon", + "fontello", + "harakteristiki", + "LTRB", + "roundcheckbox", + "toggleable", + "Türkmen", + "Wishlisted", + "Русский" + ], + "ignoreWords": [], + "import": [] +} diff --git a/fonts/CustomIcons.ttf b/fonts/CustomIcons.ttf new file mode 100644 index 0000000..087777e Binary files /dev/null and b/fonts/CustomIcons.ttf differ diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..151026b --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,33 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..9625e10 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..88359b2 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '11.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..bbc0366 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,73 @@ +PODS: + - device_info_plus (0.0.1): + - Flutter + - Flutter (1.0.0) + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - path_provider_ios (0.0.1): + - Flutter + - shared_preferences_ios (0.0.1): + - Flutter + - sqflite (0.0.2): + - Flutter + - FMDB (>= 2.7.5) + - url_launcher_ios (0.0.1): + - Flutter + - video_player_avfoundation (0.0.1): + - Flutter + - wakelock (0.0.1): + - Flutter + - webview_flutter_wkwebview (0.0.1): + - Flutter + +DEPENDENCIES: + - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) + - Flutter (from `Flutter`) + - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) + - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) + - wakelock (from `.symlinks/plugins/wakelock/ios`) + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) + +SPEC REPOS: + trunk: + - FMDB + +EXTERNAL SOURCES: + device_info_plus: + :path: ".symlinks/plugins/device_info_plus/ios" + Flutter: + :path: Flutter + path_provider_ios: + :path: ".symlinks/plugins/path_provider_ios/ios" + shared_preferences_ios: + :path: ".symlinks/plugins/shared_preferences_ios/ios" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + video_player_avfoundation: + :path: ".symlinks/plugins/video_player_avfoundation/ios" + wakelock: + :path: ".symlinks/plugins/wakelock/ios" + webview_flutter_wkwebview: + :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" + +SPEC CHECKSUMS: + device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 + shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad + sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 + url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de + video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff + wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f + webview_flutter_wkwebview: 005fbd90c888a42c5690919a1527ecc6649e1162 + +PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 + +COCOAPODS: 1.11.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..2ed31bd --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,561 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 254BA050D82AF8FEF3809DD7 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A85E9D6A4DFD56FDD682FD /* Pods_Runner.framework */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 15A85E9D6A4DFD56FDD682FD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3F18407BE8A79EE2307E2EB9 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 52306709286D664D009453DF /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B78937F8C2A1A4F4CC3EBA69 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + D9B3039DD4634396437F69E8 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 254BA050D82AF8FEF3809DD7 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 44FDD469DA3537A51D276323 /* Pods */ = { + isa = PBXGroup; + children = ( + D9B3039DD4634396437F69E8 /* Pods-Runner.debug.xcconfig */, + B78937F8C2A1A4F4CC3EBA69 /* Pods-Runner.release.xcconfig */, + 3F18407BE8A79EE2307E2EB9 /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 4E26FCEF2DD2C69FEDF54D54 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 15A85E9D6A4DFD56FDD682FD /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 44FDD469DA3537A51D276323 /* Pods */, + 4E26FCEF2DD2C69FEDF54D54 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 52306709286D664D009453DF /* Runner.entitlements */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 7B4D8CE951920DB3AC9FB901 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 17C2BBCFF10F68320204D65E /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 17C2BBCFF10F68320204D65E /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 7B4D8CE951920DB3AC9FB901 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CURRENT_PROJECT_VERSION = 7; + DEVELOPMENT_TEAM = QQPXL8D953; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 2.0.2; + PRODUCT_BUNDLE_IDENTIFIER = com.elektronika.tm; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CURRENT_PROJECT_VERSION = 7; + DEVELOPMENT_TEAM = QQPXL8D953; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 2.0.2; + PRODUCT_BUNDLE_IDENTIFIER = com.elektronika.tm; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CURRENT_PROJECT_VERSION = 7; + DEVELOPMENT_TEAM = QQPXL8D953; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 2.0.2; + PRODUCT_BUNDLE_IDENTIFIER = com.elektronika.tm; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..c87d15a --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..8ef46e7 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..a7f8a34 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..b00f7ba Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..86e9a12 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..332c1ce Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..00df3be Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..c836738 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..b00f7ba Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..b9b2ac5 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..6c45c15 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..6c45c15 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..450f126 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..3ddfae6 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..c93687a Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..4ca9966 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist new file mode 100644 index 0000000..09bd32e --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Elektronika + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Elektronika + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements new file mode 100644 index 0000000..903def2 --- /dev/null +++ b/ios/Runner/Runner.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + diff --git a/ios/build/Pods.build/Release-iphonesimulator/FMDB.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/FMDB.build/dgph new file mode 100644 index 0000000..78b4c88 Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/FMDB.build/dgph differ diff --git a/ios/build/Pods.build/Release-iphonesimulator/Flutter.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/Flutter.build/dgph new file mode 100644 index 0000000..78b4c88 Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/Flutter.build/dgph differ diff --git a/ios/build/Pods.build/Release-iphonesimulator/Pods-Runner.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/Pods-Runner.build/dgph new file mode 100644 index 0000000..78b4c88 Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/Pods-Runner.build/dgph differ diff --git a/ios/build/Pods.build/Release-iphonesimulator/path_provider_ios.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/path_provider_ios.build/dgph new file mode 100644 index 0000000..78b4c88 Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/path_provider_ios.build/dgph differ diff --git a/ios/build/Pods.build/Release-iphonesimulator/sqflite.build/dgph b/ios/build/Pods.build/Release-iphonesimulator/sqflite.build/dgph new file mode 100644 index 0000000..78b4c88 Binary files /dev/null and b/ios/build/Pods.build/Release-iphonesimulator/sqflite.build/dgph differ diff --git a/lib/app/app.dart b/lib/app/app.dart new file mode 100644 index 0000000..e97b978 --- /dev/null +++ b/lib/app/app.dart @@ -0,0 +1,6 @@ +library app; + +export 'core/core.dart'; +export 'data/data.dart'; +export 'global_widgets/global_widgets.dart'; +export 'pages/pages.dart'; diff --git a/lib/app/core/core.dart b/lib/app/core/core.dart new file mode 100644 index 0000000..f92abde --- /dev/null +++ b/lib/app/core/core.dart @@ -0,0 +1,5 @@ +library core; + +export 'themes/theme.dart'; +export 'utils/utils.dart'; +export 'lang/localization_service.dart'; diff --git a/lib/app/core/lang/localization_service.dart b/lib/app/core/lang/localization_service.dart new file mode 100644 index 0000000..4aca543 --- /dev/null +++ b/lib/app/core/lang/localization_service.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../app.dart'; +import 'ru_ru.dart'; +import 'tm_tm.dart'; + +class LocalizationService extends Translations { + // Default locale + // static final locale = Locale('tm', 'TM'); + + // fallbackLocale saves the day when the locale gets in trouble + static final fallbackLocale = Locale('tm', 'TM'); + + // Supported languages + // Needs to be same order with locales + static final langs = [ + new LanguageModel(id: 1, language: 'Türkmen dili', code: 'tm', icon: 'tm.png'), + new LanguageModel(id: 2, language: 'Русский', code: 'ru', icon: 'ru.png'), + ]; + + // Supported locales + // Needs to be same order with langs + static final locales = [ + Locale('tm', 'TM'), + Locale('ru', 'RU'), + ]; + + // Keys and their translations + // Translations are separated maps in `lang` file + @override + Map> get keys => { + 'tm_TM': tmTM, // tm_tm.dart + 'ru_RU': ruRu, // ru_ru.dart + }; + + // Gets locale from language, and updates the locale + void changeLocale(String lang) { + final locale = _getLocaleFromLanguage(lang); + Get.updateLocale(locale); + } + + // Finds language in `langs` list and returns it as Locale + Locale _getLocaleFromLanguage(String lang) { + for (int i = 0; i < langs.length; i++) { + if (lang == langs[i].code) return locales[i]; + } + return Get.locale!; + } +} diff --git a/lib/app/core/lang/ru_ru.dart b/lib/app/core/lang/ru_ru.dart new file mode 100644 index 0000000..5759813 --- /dev/null +++ b/lib/app/core/lang/ru_ru.dart @@ -0,0 +1,131 @@ +const Map ruRu = { + 'about_product': 'О товаре', + 'add_address': 'Добавить адрес', + 'add_to_cart': 'Добавить в корзину', + 'address': 'Адрес', + 'already_registered': 'У вас уже есть профиль?', + 'applied': 'Применяемый', + 'can_not_add_item_to_wishlist': 'Не могу добавить товар в список желаний', + 'can_not_send_sms': 'Не могу отправить код подтверждения. Пожалуйста, повторите попытку позже!', + 'cart_updated': 'Корзина успешно обновлена', + 'cart': 'Корзина', + 'categories': 'Категории', + 'category_name': 'Введите название категории', + 'change_lang': 'Изменение языка', + 'cheaper_first': 'Сначала дешевле', + 'checkout': 'Оформить заказ', + 'city': 'Город', + 'clear': 'Очистить', + 'client_address': 'Адрес покупателя', + 'comments': 'Комментарии', + 'confirm': 'Подтверждать', + 'contacts': 'Контакты', + 'coupon_code_applied': 'Код купона успешно применен', + 'delivery_time': 'Время доставки', + 'delivery': 'Доставка:', + 'details': 'Подробнее', + 'discount_price': 'Цена со скидкой:', + 'discount': 'Скидка:', + 'enter_comment': 'Пожалуйста, введите комментарий!', + 'enter_coupon_code': 'Введите код купона', + 'enter_password': 'Введите пароль', + 'enter_sms_code': 'Введите код из отправленного SMS на', + 'enter_star': 'Пожалуйста, введите звездочку', + 'error_occurred': 'Произошла ошибка', + 'error': 'Ошибка', + 'expensive_first': 'Дорого сначала', + 'featured_products': 'Рекомендуемые товары', + 'feedback': 'Обратная связь', + 'filter': 'Фильтр', + 'forgot_password?': 'Забыли пароль?', + 'grand_total': 'Итого:', + 'have_account': 'Если у вас нет профиля, то:', + 'home': 'Главная', + 'incorrect_code': 'Неправильно введено. \nПожалуйста, проверьте код и введите еще раз', + 'invalid_coupon_code': 'Неверный код купона', + 'invalid_credentials': 'Недействительные учетные данные или пользователь не существует', + 'invalid_phone_number': 'Неправильный номер телефона', + 'is_required': 'требуется', + 'item_added': 'Товар успешно добавлен', + 'item_removed': 'Товар удален из корзины', + 'lang': 'Язык', + 'leave_feedback': 'Оставить отзыв', + 'login': 'Вход', + 'login1': 'Войти', + 'login2': 'Войдите', + 'logout': 'Выход', + 'low_price': 'Низкие цены', + 'min_item': 'Количество предметов должно быть не менее 1', + 'name': 'Имя', + 'new_products': 'Новые товары', + 'normal_order': 'В первоначальном порядке', + 'order_completed': 'Заказ выполнен', + 'order_details': 'Детали заказа', + 'order_history': 'История заказов', + 'order_now': 'Заказать сейчас', + 'orders': 'Заказы', + 'our_address': 'Ваш адрес', + 'password': 'Пароль', + 'payment_method': 'Метод оплаты', + 'personal_detail': 'Персональные данные', + 'phone_number': 'Номер телефона', + 'phone': 'тел.', + 'please_login_to_add_cart': 'Пожалуйста, войдите, чтобы добавить корзину!', + 'please_login_to_purchase': 'Пожалуйста, войдите, чтобы совершить покупку!', + 'please_login': 'Пожалуйста, войдите', + 'price': 'Цена', + 'product_info': 'Информация о товаре', + 'product_quantity': 'Количество продукта', + 'product_review': 'Отзыв о товаре', + 'product_total_price': 'Итоговая цена:', + 'profile_detail': 'Данные профиля', + 'purchase_date': 'Дата покупки', + 'pwd_validation': 'Пароль должен быть минимум 6 символов', + 'qty_not_available': 'Запрошенное количество недоступно, повторите попытку позже.', + 'quantity': 'Количество', + 'recover_password': 'Восстановление пароля', + 'register': 'Зарегистрируйтесь', + 'register1': 'Регистрация', + 'register2': 'Зарегистрироваться', + 'reset_password': 'Сброс пароля', + 'reviews': 'Отзывы', + 'save_changes': 'Сохранить изменения', + 'search_key': 'Ключ поиска', + 'search': 'Напишите бренд или название продукта', + 'send': 'Отправить', + 'settings': 'Настройки', + 'sort': 'Сортировать', + 'specifications': 'Характеристики', + 'state': 'Область', + 'sub_total_price': 'Сумма товаров:', + 'success': 'Успешно', + 'surname': 'Фамилия', + 'top_price': 'мак. цена', + 'total_price': 'Сумма товаров:', + 'total_qty_ordered': 'Количество товара', + 'update_password': 'Обновить пароль', + 'user': 'Пользователь', + 'verification': 'Проверка', + 'warning': 'Предупреждение', + 'wishlist': 'Избранные', + 'done': 'Подать заявление', + 'select_state': 'Выберите регион или город', + 'call': 'Вызов', + 'phone_registered': 'Номер телефона зарегистрирован', + 'delete_account': 'Удалить аккаунт', + 'delete_account_warning': 'Вы хотите удалить аккаунт?', + 'ok': 'OK', + 'cancel': 'Отмена ', + 'are_you_sure': 'Вы уверены?', + 'password_updated': 'пароль обновлен', + 'insufficient_product': 'Недостаточно товаров', + 'checkout_complete': 'Оформить заказ', + 'select_shipping_method': 'Выберите способ доставки', + 'select_payment_method': 'Выберите метод оплаты', + 'loading': 'Загрузка ...', + 'payment_unsuccess': 'Платеж не прошел, повторите попытку позже!', + 'approve_lang': 'Продолжить', + 'select_language': 'Выберите язык', + 'profile':'Профиль', + 'discounted_price': 'Товары со скидкой', +}; diff --git a/lib/app/core/lang/tm_tm.dart b/lib/app/core/lang/tm_tm.dart new file mode 100644 index 0000000..a5aa240 --- /dev/null +++ b/lib/app/core/lang/tm_tm.dart @@ -0,0 +1,131 @@ +const Map tmTM = { + 'about_product': 'Haryt hakynda', + 'add_address': 'Salgyny goş', + 'add_to_cart': 'Sebede goş', + 'address': 'Salgy', + 'already_registered': 'Siziň profiliňiz barmy?', + 'applied': 'Saýlandy', + 'can_not_add_item_to_wishlist': 'Haryt islegler sanawyna goşulmady', + 'can_not_send_sms': 'Tassyklaýyş koduny ugradyp bolmady. Soň täzeden synanşyň!', + 'cart_updated': 'Sebet üstünlikli täzelendi', + 'cart': 'Sebet', + 'categories': 'Kategoriýalar', + 'category_name': 'Kategoriýanyň adyny giriziň', + 'change_lang': 'Dili çalyşmak', + 'cheaper_first': 'Arzandan gymmada', + 'checkout': 'Sargydy resmileşdirmek', + 'city': 'Şäher', + 'clear': 'Arassala', + 'client_address': 'Satyn alyjynyň salgysy', + 'comments': 'Teswirler', + 'confirm': 'Tassykla', + 'contacts': 'Habarlaşmak üçin', + 'coupon_code_applied': 'Kupon kody üstünlikli ulanyldy', + 'delivery_time': 'Eltip berme wagty', + 'delivery': 'Eltip berme:', + 'details': 'Giňişleýin', + 'discount_price': 'Arzanladylan bahasy:', + 'discount': 'Arzanladyş:', + 'enter_comment': 'Teswir ýazmagyňyzy haýyş edýäris!', + 'enter_coupon_code': 'Kuponuň kodyny giriziň', + 'enter_password': 'Açar sözi giriziň', + 'enter_sms_code': 'Iberilen SMS koduny giriziň', + 'enter_star': 'Ýyldyzy giriň!', + 'error_occurred': 'Näsazlyk ýüze çykdy', + 'error': 'Näsazlyk', + 'expensive_first': 'Gymmatdan arzana', + 'featured_products': 'Esasy harytlar', + 'feedback': 'Habarlaşmak üçin', + 'filter': 'Süzgüç', + 'forgot_password?': 'Açar sözüni unutdyňyzmy?', + 'grand_total': 'Jemi:', + 'have_account': 'Siziň profiliňiziň ýok ýagdaýynda:', + 'home': 'Baş sahypa', + 'incorrect_code': 'Nädogry kod. \nKody barlaň we täzeden giriziň!', + 'invalid_coupon_code': 'Nädogry kod', + 'invalid_credentials': 'Girilen maglumatlar nädogry ýa-da beýle ulanyjy ýok', + 'invalid_phone_number': 'Nädogry telefon belgisi', + 'is_required': 'hökmany', + 'item_added': 'Haryt üstünlikli goşuldy', + 'item_removed': 'Haryt sebetden aýryldy', + 'lang': 'Dil', + 'leave_feedback': 'Teswir ýazmak', + 'login': 'Girmek', + 'login1': 'Gir', + 'login2': 'Giriň', + 'logout': 'Çykmak', + 'low_price': 'pes baha', + 'min_item': 'Azyndan bir haryt bolmaly', + 'name': 'Ady', + 'new_products': 'Täze harytlar', + 'normal_order': 'Asyl tertipde', + 'order_completed': 'Sargyt tamamlandy', + 'order_details': 'Sargyt maglumatlary', + 'order_history': 'Sargytlaryň taryhy', + 'order_now': 'Satyn al', + 'orders': 'Sargytlar', + 'our_address': 'Siziň salgyňyz', + 'password': 'Açar sözi', + 'payment_method': 'Tölegiň görnüşi', + 'personal_detail': 'Şahsy maglumat', + 'phone_number': 'Telefon belgi', + 'phone': 'tel.', + 'please_login_to_add_cart': 'Sebede goşmak üçin girmegiňizi haýyş edýäris!', + 'please_login_to_purchase': 'Haryt satyn almak üçin girmegiňizi haýyş edýäris!', + 'please_login': 'Giriş ediň!', + 'price': 'Bahasy', + 'product_info': 'Haryt barada maglumat', + 'product_quantity': 'Haryt sany', + 'product_review': 'Haryt barada syn', + 'product_total_price': 'Jemi bahasy:', + 'profile_detail': 'Profiliň maglumatlary', + 'purchase_date': 'Satyn alnan senesi', + 'pwd_validation': 'Parol azyndan 6 simwoldan ybarat bolmaly', + 'qty_not_available': 'Talap edilýän mukdar elýeterli däl, soňrak synanyşyň.', + 'quantity': 'Mukdary', + 'recover_password': 'Açar sözüni dikeltmek', + 'register': 'Hasaba almak', + 'register1': 'Hasaba almak', + 'register2': 'Hasaba almak', + 'reset_password': 'Paroly täzelemek', + 'reviews': 'Teswirler', + 'save_changes': 'Üýtgetmeleri ýatda sakla', + 'search_key': 'Gözleg sözi', + 'search': 'Brendiň ýa-da harydyň adyny ýazyň', + 'send': 'Ugratmak', + 'settings': 'Sazlama', + 'sort': 'Tertiple', + 'specifications': 'Aýratynlyklary', + 'state': 'Welaýat', + 'sub_total_price': 'Jemi bahasy:', + 'success': 'Üstünlik', + 'surname': 'Familiýasy', + 'top_price': 'ýokary baha', + 'total_price': 'Jemi bahasy:', + 'total_qty_ordered': 'Harydyň sany', + 'update_password': 'Paroly täzele', + 'user': 'Ulanyjy', + 'verification': 'Tassyklama', + 'warning': 'Duýduryş', + 'wishlist': 'Halalanlarym', + 'done': 'Ýerine ýetir', + 'select_state': 'Welaýat ýa-da şäher saýlaň', + 'call': 'Jaň ediň', + 'phone_registered': 'Telefon belgisi hasaba alnan', + 'delete_account': 'Hasaby pozuň', + 'delete_account_warning': 'Hasaby pozmak isleýärsiňizmi?', + 'ok': 'Bolýar', + 'cancel': 'Goýbolsun', + 'are_you_sure': 'Вы уверены?', + 'password_updated': 'parol täzelendi', + 'insufficient_product': 'Ýeterlik haryt mukdary ýok', + 'checkout_complete': 'Sargydy tamamlamak', + 'select_shipping_method': 'Eltip bemegiň görnüşini saýlaň', + 'select_payment_method': 'Tölegiň görnüşini saýlaň', + 'loading': 'Ýüklenilyär ...', + 'payment_unsuccess': 'Töleg geçmedi. soň barlap görüň!', + 'approve_lang': 'Dowam et', + 'select_language': 'Dil saýlaň', + 'profile': 'Profil', + 'discounted_price': 'Arzanladyşdaky harytlar', +}; diff --git a/lib/app/core/themes/app_theme.dart b/lib/app/core/themes/app_theme.dart new file mode 100644 index 0000000..08d5eba --- /dev/null +++ b/lib/app/core/themes/app_theme.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +import 'colors.dart'; +import 'dark_theme.dart'; +import 'light_theme.dart'; + +class AppTheme { + static const appName = 'elektronika'; + + static final ThemeData light = lightTheme; + static final ThemeData dark = darkTheme; + + static final Widget appColorDivider = new Divider(color: Colors.grey.withOpacity(0.50), thickness: 1); + + static final Widget appSizeDivider30H = new SizedBox(height: 30.h); + + static final Widget appSizeDivider20H = new SizedBox(height: 20.h); + + static final Widget appSizeDivider15H = new SizedBox(height: 15.h); + + static final Widget appSizeDivider10H = new SizedBox(height: 10.h); + + static final ShapeBorder bottomSheetBorder = RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ); + + static final TextStyle unselectedScrollTxtStyle = new TextStyle( + color: Color(0xFF4A4A51), + fontWeight: FontWeight.w400, + fontSize: 14.sp, + ); + + static final TextStyle selectedTxtStyle = new TextStyle( + color: Colors.black, + fontWeight: FontWeight.w500, + fontSize: 14.sp, + ); + + static final TextStyle bottomSheetHeaderStyle = new TextStyle( + color: ThemeColor.black, + fontSize: 22.sp, + fontWeight: FontWeight.w500, + ); + + static final TextStyle radioListTxtStyle = new TextStyle( + color: ThemeColor.black, + fontSize: 16.sp, + ); + + static final TextStyle homepageTitleTxtStyle = new TextStyle( + color: ThemeColor.black, + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ); + + static final TextStyle subHeaderTxtStyle = new TextStyle( + color: ThemeColor.color3A3A3A, + fontSize: 14.sp, + fontWeight: FontWeight.w700, + ); + + static final TextStyle styleColorC4C4 = new TextStyle( + color: ThemeColor.colorC4C4C4, + fontSize: 14.sp, + ); + + static final sortFilterTxtStyle = new TextStyle( + color: ThemeColor.color717278, + fontSize: 14.sp, + ); + + static final TextStyle headerStyle = new TextStyle( + color: ThemeColor.color3A3A3A, + fontSize: 14.sp, + fontWeight: FontWeight.bold, + ); +} diff --git a/lib/app/core/themes/colors.dart b/lib/app/core/themes/colors.dart new file mode 100644 index 0000000..db1196d --- /dev/null +++ b/lib/app/core/themes/colors.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; + +class ThemeColor { + static const Color white = Color(0xFFFFFFFF); + static const Color black = Color(0xFF000000); + static const Color grey = Colors.grey; + static const Color greyTxtColor = Color(0XFF4A4A51); + static const Color mainColor = Color(0xFFC3000E); + static const Color green = Color(0xFF00C259); + static const Color cursorColor = Colors.grey; + static const Color blackColorsTxt = Color(0xFF292C31); + static const Color color717278 = Color(0xFF717278); + static const Color colorEFF0F4 = Color(0xFFEFF0F4); + static const Color colorE5E5E5 = Color(0xFFE5E5E5); + static const Color color3A3A3A = Color(0xFF3A3A3A); + static const Color colorC4C4C4 = Color(0xFFC4C4C4); + static const Color searchBoxFillColor = Color(0xFFF5F5F5); + static Color scaffoldBckColor = Color(0xFFE5E5E5); + + static const MaterialColor mainTheme = const MaterialColor( + 0xFF3EA3EB, + const { + 50: const Color(0xFF30A8FF), + 100: const Color(0xFF30A8FF), + 200: const Color(0xFF30A8FF), + 300: const Color(0xFF30A8FF), + 400: const Color(0xFF30A8FF), + 500: const Color(0xFF30A8FF), + 600: const Color(0xFF30A8FF), + 700: const Color(0xFF30A8FF), + 800: const Color(0xFF30A8FF), + 900: const Color(0xFF30A8FF), + }, + ); +} diff --git a/lib/app/core/themes/dark_theme.dart b/lib/app/core/themes/dark_theme.dart new file mode 100644 index 0000000..38f80d7 --- /dev/null +++ b/lib/app/core/themes/dark_theme.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +ThemeData darkTheme = ThemeData( + brightness: Brightness.dark, + scaffoldBackgroundColor: Colors.black, + backgroundColor: Colors.black, + bottomNavigationBarTheme: BottomNavigationBarThemeData( + backgroundColor: Colors.black, + unselectedItemColor: Colors.white, + selectedItemColor: Colors.redAccent, + elevation: 0, + ), + highlightColor: Colors.transparent, + splashColor: Colors.transparent, + appBarTheme: AppBarTheme( + color: Colors.black, + elevation: 0, + // textTheme: TextTheme( + // headline6: TextStyle( + // color: Colors.white, + // fontSize: 20, + // ), + // ), + ), +); diff --git a/lib/app/core/themes/light_theme.dart b/lib/app/core/themes/light_theme.dart new file mode 100644 index 0000000..c0c6637 --- /dev/null +++ b/lib/app/core/themes/light_theme.dart @@ -0,0 +1,24 @@ +import 'package:elektronika/app/app.dart'; +import 'package:flutter/material.dart'; + +ThemeData lightTheme = ThemeData( + colorScheme: ColorScheme.fromSwatch( + primarySwatch: Colors.red, + ), + primaryColorLight: ThemeColor.mainColor.withOpacity(0.30), + brightness: Brightness.light, + scaffoldBackgroundColor: Colors.white, + backgroundColor: Colors.white, + bottomNavigationBarTheme: BottomNavigationBarThemeData( + backgroundColor: Colors.white, + unselectedItemColor: Colors.black, + selectedItemColor: Colors.redAccent, + elevation: 0, + ), + highlightColor: Colors.transparent, + splashColor: Colors.grey.withOpacity(0.20), + appBarTheme: AppBarTheme( + color: Colors.white, + elevation: 0, + ), +); diff --git a/lib/app/core/themes/theme.dart b/lib/app/core/themes/theme.dart new file mode 100644 index 0000000..5e22cb5 --- /dev/null +++ b/lib/app/core/themes/theme.dart @@ -0,0 +1,6 @@ +library theme; + +export 'app_theme.dart'; +export 'colors.dart'; +export 'dark_theme.dart'; +export 'light_theme.dart'; diff --git a/lib/app/core/utils/calculate_aspect_ratio.dart b/lib/app/core/utils/calculate_aspect_ratio.dart new file mode 100644 index 0000000..9ca53af --- /dev/null +++ b/lib/app/core/utils/calculate_aspect_ratio.dart @@ -0,0 +1,44 @@ +// import 'package:flutter/material.dart'; + +// // iphone 5 => Size(375.0, 667.0) +// // iphone 8 => Size(375.0, 667.0) +// // iphone 8 pro => Size(414.0, 736.0) +// // iphone 11 => Size(414.0, 896.0) +// // iphone 11 pro => Size(414.0, 896.0) +// // iphone 12 pro => Size(390.0, 844.0) +// // ipad 8th generation => Size(810.0, 1080.0) +// // ipad pro 9.7' => Size(768.0, 1024.0) +// // ipad air 4th generation => Size(820.0, 1180.0) + +// // samsung a51 => Size(411.4, 866.3) + +// double getAspectRatio(BuildContext context) { +// var deviceWidth = MediaQuery.of(context).size.shortestSide; +// debugPrint('deviceWidth $deviceWidth'); +// if (deviceWidth >= 1200) { +// return 2 / 2; //desktop; +// } else if (deviceWidth >= 720) { +// return 2 / 2; //largeTablet; +// } else if (deviceWidth >= 600) { +// return 2 / 3; // smallerTablet; +// } else if (deviceWidth < 300) { +// return 2 / 3; // watch; +// } else { +// //mobile + +// if (deviceWidth >= 540) { +// return 2 / 2.30; +// } else if (deviceWidth >= 500) { +// return 2 / 2.50; +// } else if (deviceWidth >= 450) { +// return 2 / 2.90; +// } else if (deviceWidth >= 450) { +// return 2 / 3.0; +// } else if (deviceWidth < 450 && deviceWidth >= 350) { +// return 2 / 3.0; +// } else if (deviceWidth < 350 && deviceWidth > 300) { +// return 2 / 3.50; +// } else +// return 2 / 3.10; +// } +// } diff --git a/lib/app/core/utils/constants.dart b/lib/app/core/utils/constants.dart new file mode 100644 index 0000000..1f3b5ac --- /dev/null +++ b/lib/app/core/utils/constants.dart @@ -0,0 +1,19 @@ +class Constants { + static const BASE_URL = 'https://elektronika.tm/api/'; + static const BASE_URL_WEB = 'https://elektronika.tm/'; + + static const ASSET_PATH_SETTINGS = 'assets/settings'; + static const ASSET_PATH_PROFILE = 'assets/profile'; + + static const DESC_ONLY = 'description_only'; + static const PRODUCTS_AND_DESC = 'products_and_description'; + + static const PAGE_SIZE = 10; + + // shared_preferences + static const IS_LOGGED_IN = 'is_logged_in'; + static const TOKEN = 'token'; + static const USER_NAME = 'user_name'; + static const CART_LIST = 'cart_list'; + static const LOCALE = 'locale'; +} diff --git a/lib/app/core/utils/device_info.dart b/lib/app/core/utils/device_info.dart new file mode 100644 index 0000000..b4c77fe --- /dev/null +++ b/lib/app/core/utils/device_info.dart @@ -0,0 +1,68 @@ +import 'dart:io'; + +import 'package:device_info_plus/device_info_plus.dart'; + +Map _readAndroidBuildData(AndroidDeviceInfo build) { + return { + 'version.securityPatch': build.version.securityPatch, + 'version.sdkInt': build.version.sdkInt, + 'version.release': build.version.release, + 'version.previewSdkInt': build.version.previewSdkInt, + 'version.incremental': build.version.incremental, + 'version.codename': build.version.codename, + 'version.baseOS': build.version.baseOS, + 'board': build.board, + 'bootloader': build.bootloader, + 'brand': build.brand, + 'device': build.device, + 'display': build.display, + 'fingerprint': build.fingerprint, + 'hardware': build.hardware, + 'host': build.host, + 'id': build.id, + 'manufacturer': build.manufacturer, + 'model': build.model, + 'product': build.product, + 'supported32BitAbis': build.supported32BitAbis, + 'supported64BitAbis': build.supported64BitAbis, + 'supportedAbis': build.supportedAbis, + 'tags': build.tags, + 'type': build.type, + 'isPhysicalDevice': build.isPhysicalDevice, + 'androidId': build.androidId, + 'systemFeatures': build.systemFeatures, + }; +} + +Map _readIosDeviceInfo(IosDeviceInfo data) { + return { + 'name': data.name, + 'systemName': data.systemName, + 'systemVersion': data.systemVersion, + 'model': data.model, + 'localizedModel': data.localizedModel, + 'identifierForVendor': data.identifierForVendor, + 'isPhysicalDevice': data.isPhysicalDevice, + 'utsname.sysname:': data.utsname.sysname, + 'utsname.nodename:': data.utsname.nodename, + 'utsname.release:': data.utsname.release, + 'utsname.version:': data.utsname.version, + 'utsname.machine:': data.utsname.machine, + }; +} + +Future getDeviceName() async { + final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); + + String deviceName = 'otherDeviceType'; + + if (Platform.isAndroid) { + final map = _readAndroidBuildData(await deviceInfoPlugin.androidInfo); + deviceName = map['brand'] + map['model']; + } + if (Platform.isIOS) { + final map = _readIosDeviceInfo(await deviceInfoPlugin.iosInfo); + deviceName = map['name']; + } + return deviceName; +} diff --git a/lib/app/core/utils/grid_view_load_more.dart b/lib/app/core/utils/grid_view_load_more.dart new file mode 100644 index 0000000..84e094d --- /dev/null +++ b/lib/app/core/utils/grid_view_load_more.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../app.dart'; + +class GridViewLoadMoreWidget extends StatelessWidget { + final int index; + const GridViewLoadMoreWidget({ + Key? key, + required this.index, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Transform.translate( + offset: Offset(index % 2 == 0 ? context.width / 4 : 0, 0), + child: CustomLoader(), + ); + } +} diff --git a/lib/app/core/utils/hex_to_color.dart b/lib/app/core/utils/hex_to_color.dart new file mode 100644 index 0000000..83d76c3 --- /dev/null +++ b/lib/app/core/utils/hex_to_color.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; + +class HexColor extends Color { + HexColor(final String hexColor) : super(_getColorFromHex(hexColor)); + + static int _getColorFromHex(String hexColor) { + hexColor = hexColor.toUpperCase().replaceAll('#', ''); + if (hexColor.length == 6) { + hexColor = 'FF' + hexColor; + } + return int.parse(hexColor, radix: 16); + } +} diff --git a/lib/app/core/utils/http_util.dart b/lib/app/core/utils/http_util.dart new file mode 100644 index 0000000..cd807c3 --- /dev/null +++ b/lib/app/core/utils/http_util.dart @@ -0,0 +1,306 @@ +import 'dart:async'; + +import 'package:dio/dio.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../app.dart'; + +class HttpUtil { + static HttpUtil _instance = HttpUtil._internal(); + + factory HttpUtil() => _instance; + + late Dio dio; + CancelToken cancelToken = new CancelToken(); + + HttpUtil._internal() { + BaseOptions options = new BaseOptions( + baseUrl: Constants.BASE_URL, + connectTimeout: 100000, + receiveTimeout: 50000, + headers: {}, + contentType: 'application/json; charset=utf-8', + ); + + dio = new Dio(options); + + // CookieJar cookieJar = CookieJar(); + // dio.interceptors.add(CookieManager(cookieJar)); + + dio.interceptors.add(InterceptorsWrapper( + onRequest: (options, handler) { + return handler.next(options); + }, + onResponse: (response, handler) { + return handler.next(response); + }, + onError: (DioError e, handler) { + ErrorEntity eInfo = createErrorEntity(e); + + switch (eInfo.code) { + case 401: // No permission to log in again + setLoginStatus(false); + break; + default: + } + return handler.next(e); + }, + )); + } + + ErrorEntity createErrorEntity(DioError error) { + switch (error.type) { + case DioErrorType.cancel: + return ErrorEntity(code: -1, message: 'Request cancellation'); + case DioErrorType.connectTimeout: + return ErrorEntity(code: -1, message: 'Connection timed out'); + case DioErrorType.sendTimeout: + return ErrorEntity(code: -1, message: 'Request timed out'); + case DioErrorType.receiveTimeout: + return ErrorEntity(code: -1, message: 'Response timeout'); + case DioErrorType.response: + { + try { + int? errCode = error.response?.statusCode; + switch (errCode) { + case 400: + return ErrorEntity(code: errCode, message: 'Request syntax error'); + case 401: + return ErrorEntity(code: errCode, message: 'Username or password incorrect'); + case 403: + return ErrorEntity(code: errCode, message: 'Server refused to execute'); + case 404: + return ErrorEntity(code: errCode, message: 'Can not reach server'); + case 405: + return ErrorEntity(code: errCode, message: 'Request method is forbidden'); + case 405: + return ErrorEntity(code: errCode, message: 'User already registered'); + case 500: + return ErrorEntity(code: errCode, message: 'Server internal error'); + case 502: + return ErrorEntity(code: errCode, message: 'Invalid request'); + case 503: + return ErrorEntity(code: errCode, message: 'Server hung up'); + case 505: + return ErrorEntity(code: errCode, message: 'Does not support HTTP protocol request'); + default: + { + // return ErrorEntity(code: errCode, message: 'Unknown error'); + return ErrorEntity( + code: errCode, + message: error.response?.statusMessage, + ); + } + } + } on Exception catch (_) { + return ErrorEntity(code: -1, message: 'Unknown error'); + } + } + default: + { + return ErrorEntity(code: -1, message: error.message); + } + } + } + + void cancelRequests(CancelToken token) { + token.cancel('cancelled'); + } + + Future> getAuthorizationHeader() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + Map headers; + String? accessToken = prefs.getString(Constants.TOKEN); + headers = { + 'Authorization': 'Bearer $accessToken', + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }; + return headers; + } + + /// restful get + /// refresh false + /// noCache true + /// list false + /// cacheKey + /// cacheDisk + Future get({ + required String path, + Map? queryParameters, + Options? options, + bool refresh = false, + bool noCache = false, + bool list = false, + String cacheKey = '', + bool cacheDisk = false, + }) async { + Options requestOptions = options ?? Options(); + if (requestOptions.extra == null) { + requestOptions.extra = Map(); + } + requestOptions.extra!.addAll({ + 'refresh': refresh, + 'noCache': noCache, + 'list': list, + 'cacheKey': cacheKey, + 'cacheDisk': cacheDisk, + }); + requestOptions.headers = requestOptions.headers ?? {}; + Map? authorization = await getAuthorizationHeader(); + requestOptions.headers!.addAll(authorization); + + var response = await dio.get(path, queryParameters: queryParameters, options: requestOptions, cancelToken: cancelToken); + + return response.data; + } + + /// restful post + Future post( + String path, { + dynamic data, + Map? queryParameters, + Options? options, + }) async { + Options requestOptions = options ?? Options(); + requestOptions.headers = requestOptions.headers ?? {}; + requestOptions.headers?.addAll({'Accept': 'application/json'}); + Map? authorization = await getAuthorizationHeader(); + requestOptions.headers!.addAll(authorization); + + var response = await dio.post( + path, + data: data, + queryParameters: queryParameters, + options: requestOptions, + cancelToken: cancelToken, + ); + + return response.data; + } + + /// restful put + Future put( + String path, { + dynamic data, + Map? queryParameters, + Options? options, + }) async { + Options requestOptions = options ?? Options(); + requestOptions.headers = requestOptions.headers ?? {}; + Map? authorization = await getAuthorizationHeader(); + requestOptions.headers!.addAll(authorization); + var response = await dio.put( + path, + data: data, + queryParameters: queryParameters, + options: requestOptions, + cancelToken: cancelToken, + ); + return response.data; + } + + /// restful patch + Future patch( + String path, { + dynamic data, + Map? queryParameters, + Options? options, + }) async { + Options requestOptions = options ?? Options(); + requestOptions.headers = requestOptions.headers ?? {}; + Map? authorization = await getAuthorizationHeader(); + requestOptions.headers!.addAll(authorization); + var response = await dio.patch( + path, + data: data, + queryParameters: queryParameters, + options: requestOptions, + cancelToken: cancelToken, + ); + return response.data; + } + + /// restful delete + Future delete( + String path, { + dynamic data, + Map? queryParameters, + Options? options, + }) async { + Options requestOptions = options ?? Options(); + requestOptions.headers = requestOptions.headers ?? {}; + Map? authorization = await getAuthorizationHeader(); + requestOptions.headers!.addAll(authorization); + var response = await dio.delete( + path, + data: data, + queryParameters: queryParameters, + options: requestOptions, + cancelToken: cancelToken, + ); + return response.data; + } + + /// restful post form +Future postForm( + String path, { + required Map data, + Map? queryParameters, + Options? options, + }) async { + Options requestOptions = options ?? Options(); + requestOptions.headers = requestOptions.headers ?? {}; + Map? authorization = await getAuthorizationHeader(); + requestOptions.headers!.addAll(authorization); + var response = await dio.post( + path, + data: FormData.fromMap(data), + queryParameters: queryParameters, + options: requestOptions, + cancelToken: cancelToken, + ); + return response.data; + } + + /// restful post Stream +/*Future postStream( + String path, { + dynamic data, + int dataLength = 0, + Map? queryParameters, + Options? options, + }) async { + Options requestOptions = options ?? Options(); + requestOptions.headers = requestOptions.headers ?? {}; + Map? authorization = getAuthorizationHeader(); + if (authorization != null) { + requestOptions.headers!.addAll(authorization); + } + requestOptions.headers!.addAll({ + Headers.contentLengthHeader: dataLength.toString(), + }); + var response = await dio.post( + path, + data: Stream.fromIterable(data.map((e) => [e])), + queryParameters: queryParameters, + options: requestOptions, + cancelToken: cancelToken, + ); + return response.data; + } */ +} + +// Exception handling +class ErrorEntity implements Exception { + int? code; + String? message; + + ErrorEntity({this.code, this.message}); + + @override + String toString() { + if (message == null) return 'Exception'; + return 'Exception: code $code, $message'; + } +} diff --git a/lib/app/core/utils/image_controller.dart b/lib/app/core/utils/image_controller.dart new file mode 100644 index 0000000..421fca4 --- /dev/null +++ b/lib/app/core/utils/image_controller.dart @@ -0,0 +1,5 @@ +import '../../data/models/models.dart'; + +String getImagePath(List images) { + return images.length > 0 ? images.first.originalImageUrl : ''; +} diff --git a/lib/app/core/utils/iterable_fn.dart b/lib/app/core/utils/iterable_fn.dart new file mode 100644 index 0000000..dbb195d --- /dev/null +++ b/lib/app/core/utils/iterable_fn.dart @@ -0,0 +1,8 @@ +Iterable mapIndexed(Iterable items, E Function(int index, T item) f) sync* { + var index = 0; + + for (final item in items) { + yield f(index, item); + index = index + 1; + } +} diff --git a/lib/app/core/utils/keyboard.dart b/lib/app/core/utils/keyboard.dart new file mode 100644 index 0000000..ba1a866 --- /dev/null +++ b/lib/app/core/utils/keyboard.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class KeyboardUtil { + static void hideKeyboard(BuildContext context) { + FocusScopeNode currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) { + currentFocus.unfocus(); + } + } +} diff --git a/lib/app/core/utils/locale.dart b/lib/app/core/utils/locale.dart new file mode 100644 index 0000000..8209afe --- /dev/null +++ b/lib/app/core/utils/locale.dart @@ -0,0 +1,15 @@ +import 'package:shared_preferences/shared_preferences.dart'; + +import 'utils.dart'; + +Future getLocale() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + + return prefs.getString(Constants.LOCALE) ?? 'tm'; +} + +Future setLocale(String code) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + + prefs.setString(Constants.LOCALE, code); +} diff --git a/lib/app/core/utils/login_status.dart b/lib/app/core/utils/login_status.dart new file mode 100644 index 0000000..b788817 --- /dev/null +++ b/lib/app/core/utils/login_status.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'utils.dart'; + +Future initLoginStatus() async { + debugPrint('initLoginStatus'); + SharedPreferences prefs = await SharedPreferences.getInstance(); + + final bool status = prefs.getBool(Constants.IS_LOGGED_IN) ?? false; + + await setLoginStatus(status); +} + +Future setLoginStatus(status) async { + debugPrint('setLoginStatus $status'); + SharedPreferences prefs = await SharedPreferences.getInstance(); + prefs.setBool(Constants.IS_LOGGED_IN, status); + + LoginStatusController loginStatusController = Get.put(LoginStatusController()); + + loginStatusController.loginStatus = status; +} diff --git a/lib/app/core/utils/login_status_controller.dart b/lib/app/core/utils/login_status_controller.dart new file mode 100644 index 0000000..1946a70 --- /dev/null +++ b/lib/app/core/utils/login_status_controller.dart @@ -0,0 +1,7 @@ +import 'package:get/get.dart'; + +class LoginStatusController extends GetxController { + final RxBool _loginStatus = false.obs; + set loginStatus(value) => this._loginStatus.value = value; + bool get loginStatus => this._loginStatus.value; +} diff --git a/lib/app/core/utils/mask_formatter.dart b/lib/app/core/utils/mask_formatter.dart new file mode 100644 index 0000000..b3a04c1 --- /dev/null +++ b/lib/app/core/utils/mask_formatter.dart @@ -0,0 +1,3 @@ +import 'package:mask_text_input_formatter/mask_text_input_formatter.dart'; + +final maskFormatterPhone = new MaskTextInputFormatter(mask: '(##) ## ## ##', filter: {'#': RegExp(r'[0-9]')}); diff --git a/lib/app/core/utils/navigate_to_login.dart b/lib/app/core/utils/navigate_to_login.dart new file mode 100644 index 0000000..e3bf05c --- /dev/null +++ b/lib/app/core/utils/navigate_to_login.dart @@ -0,0 +1,9 @@ +import 'package:get/get.dart'; +import '../../pages/dashboard/controller.dart'; + +void navigateToLoginScreen() { + Get.offNamedUntil('/', (route) => false); + // Get.back(); + final DashboardController _dashboardController = Get.put(DashboardController()); + _dashboardController.changeTabIndex(2); +} diff --git a/lib/app/core/utils/navigate_to_product_list.dart b/lib/app/core/utils/navigate_to_product_list.dart new file mode 100644 index 0000000..c4c8c6d --- /dev/null +++ b/lib/app/core/utils/navigate_to_product_list.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import '../../app.dart'; + +void navigateToProductListScreen(Map params) { + final Map queryParams = { + params['type']: params['id'], + }; + + debugPrint('queryParams $queryParams'); + + /// [FilterController] + Get.delete(); + + Get.putAsync(() async => FilterController(queryParams)) + .then( + (fc) => fc.state.filterableQueryParams.value = queryParams, + ) + .then( + (value) => Get.toNamed(AppRoutes.PRODUCT_LIST, arguments: params), + ); +} diff --git a/lib/app/core/utils/remove_last_char.dart b/lib/app/core/utils/remove_last_char.dart new file mode 100644 index 0000000..d199192 --- /dev/null +++ b/lib/app/core/utils/remove_last_char.dart @@ -0,0 +1,6 @@ +String removeLastChar(String str) { + if (str.length > 0) { + str = str.substring(0, str.length - 1); + } + return str; +} diff --git a/lib/app/core/utils/route_to_sub_page.dart b/lib/app/core/utils/route_to_sub_page.dart new file mode 100644 index 0000000..292dc5e --- /dev/null +++ b/lib/app/core/utils/route_to_sub_page.dart @@ -0,0 +1,7 @@ +import 'package:get/get.dart'; + +void routeToSubPage(String? route, Map? params) { + if (route != null) { + Get.toNamed(route, arguments: params); + } +} diff --git a/lib/app/core/utils/utils.dart b/lib/app/core/utils/utils.dart new file mode 100644 index 0000000..db59378 --- /dev/null +++ b/lib/app/core/utils/utils.dart @@ -0,0 +1,19 @@ +library utils; + +export 'calculate_aspect_ratio.dart'; +export 'constants.dart'; +export 'device_info.dart'; +export 'grid_view_load_more.dart'; +export 'hex_to_color.dart'; +export 'http_util.dart'; +export 'image_controller.dart'; +export 'iterable_fn.dart'; +export 'keyboard.dart'; +export 'locale.dart'; +export 'login_status_controller.dart'; +export 'login_status.dart'; +export 'mask_formatter.dart'; +export 'navigate_to_login.dart'; +export 'navigate_to_product_list.dart'; +export 'remove_last_char.dart'; +export 'route_to_sub_page.dart'; diff --git a/lib/app/data/apis/addresses.dart b/lib/app/data/apis/addresses.dart new file mode 100644 index 0000000..02a1dce --- /dev/null +++ b/lib/app/data/apis/addresses.dart @@ -0,0 +1,122 @@ +import 'dart:convert'; + +import 'package:flutter/cupertino.dart'; + +import '../../app.dart'; + +class AddressesApi { + static String className = 'AddressesApi'; + + static List states = []; + + static Future create(Map params) async { + try { + // first get states + await getStates(); + + const String path = Constants.BASE_URL + 'customer/addresses'; + + final response = await HttpUtil().post(path, data: jsonEncode(params)); + + final newAddress = new AddressModel.fromJson(response['data']); + + final stateTr = states.firstWhere((state) => state.code == newAddress.stateCode).translations; + + newAddress.stateTranslations = [...stateTr]; + + return newAddress; + } catch (error) { + debugPrint('AddressesApi create error: ${error.toString()}'); + return null; + } + } + + static Future?> get() async { + final String fnName = 'get'; + + debugPrint('class: $className, method: $fnName'); + + try { + // first get states + await getStates(); + + final List addresses = []; + const String path = Constants.BASE_URL + 'customer/addresses'; + + final response = await HttpUtil().get(path: path); + + for (final address in response['data']) { + final newAddress = new AddressModel.fromJson(address); + + final stateTr = states.firstWhere((state) => state.code == newAddress.stateCode).translations; + + newAddress.stateTranslations = [...stateTr]; + + addresses.add(newAddress); + } + + return addresses; + } catch (error) { + debugPrint('AddressesApi get error: $error'); + return null; + } + } + + static Future delete(int id) async { + final String fnName = 'delete'; + try { + String path = Constants.BASE_URL + 'customer/addresses/$id'; + + debugPrint('class: $className, method: $fnName, path: ' + path); + + final response = await HttpUtil().delete(path); + + debugPrint('delete address response $response'); + + return true; + } catch (error) { + debugPrint('AddressesApi get error: $error'); + return false; + } + } + + static Future> getStates() async { + final String fnName = 'getStates'; + + if (states.isNotEmpty) return states; + + try { + String path = Constants.BASE_URL + 'v1/countries/states/groups'; + + debugPrint('class: $className, method: $fnName, path: ' + path); + + final response = await HttpUtil().get(path: path); + + states = [...StateModel.listFromJson(response['data']['TM'] as List)]; + + debugPrint('states $states'); + + return states; + } catch (error) { + debugPrint('getStates get error: $error'); + return []; + } + } + + static Future getContacts() async { + final String fnName = 'getContacts'; + + try { + String path = Constants.BASE_URL + 'contacts'; + + debugPrint('class: $className, method: $fnName, path: ' + path); + + final response = await HttpUtil().get(path: path); + + return ContactsModel.fromJson(response); + } catch (error) { + debugPrint('$fnName error: $error'); + return null; + } + } +} diff --git a/lib/app/data/apis/apis.dart b/lib/app/data/apis/apis.dart new file mode 100644 index 0000000..21add2d --- /dev/null +++ b/lib/app/data/apis/apis.dart @@ -0,0 +1,13 @@ +library apis; + +export 'addresses.dart'; +export 'auth.dart'; +export 'category.dart'; +export 'cms.dart'; +export 'filter.dart'; +export 'order.dart'; +export 'product.dart'; +export 'search.dart'; +export 'shopping_cart.dart'; +export 'slider.dart'; +export 'wishlist.dart'; diff --git a/lib/app/data/apis/auth.dart b/lib/app/data/apis/auth.dart new file mode 100644 index 0000000..5723f97 --- /dev/null +++ b/lib/app/data/apis/auth.dart @@ -0,0 +1,167 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:get/get.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../app.dart'; + +class AuthApi { + static String className = 'AuthApi'; + + static Future registerUser(Map params) async { + final String fnName = 'registerUser'; + + debugPrint('class: $className, method: $fnName, params: $params'); + try { + SharedPreferences prefs = await SharedPreferences.getInstance(); + + const String path = Constants.BASE_URL + 'customer/register'; + + final response = await HttpUtil().post(path, queryParameters: params); + + prefs.remove(Constants.TOKEN); + prefs.setString(Constants.TOKEN, response['token']); + + return true; + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401 || errCode == 422) { + showSnack('warning'.tr, 'phone_registered'.tr, SnackType.WARNING); + } + return false; + } catch (error) { + debugPrint('registerUser error: $error'); + return false; + } + } + + static Future updateUser(Map params) async { + try { + const String path = Constants.BASE_URL + 'customer/profile'; + + final response = await HttpUtil().put(path, queryParameters: params); + return response['message']; + } catch (error) { + debugPrint('updateUser error: $error'); + return null; + } + } + + static Future resetPassword(Map params) async { + final String fnName = 'resetPassword'; + try { + const String path = Constants.BASE_URL + 'customer/reset_password'; + + debugPrint('class: $className, method: $fnName, params: $params'); + final response = await HttpUtil().post(path, queryParameters: params); + + debugPrint('response resetPassword $response'); + + return true; + } catch (error) { + debugPrint('resetPassword error: $error'); + return false; + } + } + + static Future updatePassword(Map params) async { + final String fnName = 'updatePassword'; + try { + const String path = Constants.BASE_URL + 'customer/update_password'; + debugPrint('class: $className, method: $fnName, params: $params'); + + final response = await HttpUtil().post(path, queryParameters: params); + + debugPrint('response updatePassword $response'); + return true; + } catch (error) { + debugPrint('updatePassword error: $error'); + return false; + } + } + + static Future login(Map params) async { + try { + SharedPreferences prefs = await SharedPreferences.getInstance(); + + const String path = Constants.BASE_URL + 'customer/login'; + + final response = await HttpUtil().post(path, queryParameters: params); + + prefs.remove(Constants.TOKEN); + prefs.setString(Constants.TOKEN, response['token']); + + return true; + } on DioError catch (error) { + int? errCode = error.response?.statusCode; + + if (errCode == 401 || errCode == 422) { + showSnack('error'.tr, 'invalid_credentials'.tr, SnackType.ERROR); + } + return false; + } catch (error) { + debugPrint('login error: $error'); + return false; + } + } + + static Future getCurrentUser() async { + try { + const String path = Constants.BASE_URL + 'v1/customer/get'; + + final response = await HttpUtil().get(path: path); + + return UserModel.fromJson(response['data']); + } on DioError catch (error) { + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + } + return null; + } catch (error) { + debugPrint('getCurrentUser error: $error'); + return null; + } + } + +/* static Future getVerificationCode(String phone) async { + final String fnName = 'getVerificationCode'; + + try { + final Map params = { + 'phone': phone, + }; + + debugPrint('class: $className, method: $fnName, params: $params'); + + const String path = 'http://sms.digital-tps.tk/api/verify'; + + final response = await HttpUtil().postForm(path, data: params); + + return response['verify_code'].toString(); + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + return null; + } + } */ + + static Future deleteAccount() async { + final String fnName = 'deleteAccount'; + + try { + debugPrint('class: $className, method: $fnName'); + const String path = Constants.BASE_URL + 'customer/delete'; + + await HttpUtil().delete(path); + + return true; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + return false; + } + } +} diff --git a/lib/app/data/apis/category.dart b/lib/app/data/apis/category.dart new file mode 100644 index 0000000..db6d7b4 --- /dev/null +++ b/lib/app/data/apis/category.dart @@ -0,0 +1,50 @@ +import 'package:flutter/cupertino.dart'; +import '../../app.dart'; + +class CategoryApi { + static List _categories = []; + + static List get categories => [..._categories]; + + static Future> getDescendantCategories(Map params) async { + if (_categories.length == 0) { + try { + const String path = Constants.BASE_URL + 'descendant-categories'; + + final response = await HttpUtil().get(path: path, queryParameters: params); + + for (final json in response['data']) { + final CategoryModel category = CategoryModel.fromJson(json); + _categories.add(category); + } + + return _categories; + } catch (error) { + debugPrint('CategoryApi get error: $error '); + return []; + } + } + return _categories; + } + + static List buildCategoryTree(String newValue) { + if (categories.isEmpty) return []; + + final List list = []; + + buildTree(newValue, _categories, list); + + return list; + } + + // build category tree recursively + static void buildTree(String searchKey, List sourceList, List destinationList) { + for (final category in sourceList) { + if (category.name.toLowerCase().contains(searchKey.toLowerCase())) { + destinationList.add(category); + } else { + buildTree(searchKey, category.children, destinationList); + } + } + } +} diff --git a/lib/app/data/apis/cms.dart b/lib/app/data/apis/cms.dart new file mode 100644 index 0000000..58febc8 --- /dev/null +++ b/lib/app/data/apis/cms.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; + +import '../../app.dart'; + +class CMSApi { + static String className = 'CMSApi'; + + static Future> get() async { + final String fnName = 'get'; + + List list = []; + + try { + debugPrint('class: $className, method: $fnName'); + + String path = Constants.BASE_URL + 'cms'; + + final response = await HttpUtil().get( + path: path, + queryParameters: { + 'locale': await getLocale(), + }, + ); + + for (final json in response['data']) { + list.add(CMSModel.fromJson(json)); + } + + return list; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + return list; + } + } +} diff --git a/lib/app/data/apis/filter.dart b/lib/app/data/apis/filter.dart new file mode 100644 index 0000000..bbd5b23 --- /dev/null +++ b/lib/app/data/apis/filter.dart @@ -0,0 +1,146 @@ +import 'package:elektronika/app/core/utils/utils.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import '../data.dart'; + +class FilterApi { + static String className = 'FilterApi'; + + static Future?> getFilters(int categoryId) async { + final String fnName = 'getFilters'; + + List filters = []; + try { + String path = Constants.BASE_URL + 'categories/$categoryId/filters'; + + debugPrint('class: $className, method: $fnName, path: ' + path); + + final response = await HttpUtil().get( + path: path, + queryParameters: { + 'locale': await getLocale(), + }, + ); + + for (final filter in response['attributes']) { + filters.add(FilterModel.fromJson(filter)); + } + + return filters; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName'); + return null; + } + } + + static Future> getSortMethods() async { + final String fnName = 'getSortMethods'; + + // await Future.delayed(const Duration(milliseconds: 5000), () {}); + + List list = []; + + try { + debugPrint('class: $className, method: $fnName'); + + list.add( + new SortModel( + id: 1, + label: 'normal_order'.tr, + queryParameters: {}, + ), + ); + + list.add( + new SortModel( + id: 2, + label: 'expensive_first'.tr, + queryParameters: {'sort': 'price', 'order': 'desc'}, + ), + ); //?sort=price&order=desc + + list.add( + new SortModel( + id: 3, + label: 'cheaper_first'.tr, + queryParameters: {'sort': 'price', 'order': 'asc'}, + ), + ); //?sort=price&order=asc + + // list.add(new SortModel(id: 4, label: 'Discount')); + + // String path = Constants.BASE_URL + 'categories/$categoryId/filters'; + + // final response = await HttpUtil().get(path: path); + + // debugPrint('getFilters response $response'); + return list; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName'); + return []; + } + } + + static Future> getPriceFilters() async { + final String fnName = 'getPriceFilters'; + + List list = []; + + try { + debugPrint('class: $className, method: $fnName'); + + list.add(new PriceFilterModel( + id: 1, + label: '0 m. - 100 m.', + start: 0.0, + end: 100.0, + queryValue: '0,100', + )); + list.add(new PriceFilterModel( + id: 2, + label: '100 m. - 250 m.', + start: 100.0, + end: 250.0, + queryValue: '100,250', + )); + list.add(new PriceFilterModel( + id: 3, + label: '250 m. - 500 m.', + start: 250.0, + end: 500.0, + queryValue: '250,500', + )); + list.add(new PriceFilterModel( + id: 4, + label: '500 m. - 900 m.', + start: 500.0, + end: 900.0, + queryValue: '500,900', + )); + list.add(new PriceFilterModel( + id: 5, + label: '900 m. - 3000 m.', + start: 900.0, + end: 3000.0, + queryValue: '900,3000', + )); + + list.add(new PriceFilterModel( + id: 6, + label: '3000 m. - 40000 m.', + start: 3000.0, + end: 40000.0, + queryValue: '900,3000', + )); + // String path = Constants.BASE_URL + 'categories/$categoryId/filters'; + + // final response = await HttpUtil().get(path: path); + + // debugPrint('getFilters response $response'); + return list; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName'); + return []; + } + } +} diff --git a/lib/app/data/apis/order.dart b/lib/app/data/apis/order.dart new file mode 100644 index 0000000..e57ecda --- /dev/null +++ b/lib/app/data/apis/order.dart @@ -0,0 +1,176 @@ +import 'dart:convert'; + +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../app.dart'; + +class OrderApi { + static String className = 'OrderApi'; + + static Future> get(Map params) async { + final String fnName = 'get'; + + List list = []; + + try { + debugPrint('class: $className, method: $fnName, params $params'); + + String path = Constants.BASE_URL + 'customer/orders'; + + final response = await HttpUtil().get(path: path, queryParameters: params); + + for (final json in response['data']) { + final OrderModel orderModel = OrderModel.fromJson(json); + list.add(orderModel); + } + + return list; + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + Get.back(); + } + return throw new Exception('Error occurred'); + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + throw new Exception('Error occurred'); + } + } + + static Future?> saveAddress(Map params) async { + final String fnName = 'saveAddress'; + + final Map map = { + 'shipping_rates': null, + 'payment_methods': null, + }; + + try { + debugPrint('class: $className, method: $fnName, params: $params'); + + String path = Constants.BASE_URL + 'customer/checkout/save-address'; + + final response = await HttpUtil().post(path, data: jsonEncode(params)); + + if (response['data']['shipping_rates'] != null) { + final List list = []; + for (var json in response['data']['shipping_rates']) { + list.add(ShippingRateModel.fromJson(json)); + } + + map['shipping_rates'] = list; + } + + if (response['data']['payment_methods'] != null) { + final List list = []; + for (final json in response['data']['payment_methods']) { + list.add(PaymentMethodModel.fromJson(json)); + } + + map['payment_methods'] = list; + } + + return map; + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + Get.offNamedUntil('/', (route) => false); + navigateToLoginScreen(); + + showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + } + return null; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, params: $params, error: $e '); + // throw new Exception('Error occurred'); + return null; + } + } + + static Future> saveOrder(Map params) async { + final String fnName = 'saveOrder'; + + try { + debugPrint('class: $className, method: $fnName, params: $params'); + + String path = Constants.BASE_URL + 'customer/checkout/save-order'; + + final response = await HttpUtil().post(path, queryParameters: params); + + debugPrint('response $fnName, $response'); + + if (!response['success']) showSnack('error'.tr, 'error_occurred'.tr, SnackType.ERROR); + + return {'success': response['success'], 'url': response['url'] ?? ''}; + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + Get.offNamedUntil('/', (route) => false); + navigateToLoginScreen(); + showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + } + return {'success': false, 'url': ''}; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, params: $params, error: $e '); + showSnack('error'.tr, 'error_occurred'.tr, SnackType.ERROR); + return {'success': false, 'url': ''}; + } + } + + static Future cancelOrder(int orderId) async { + final String fnName = 'cancel'; + + try { + debugPrint('class: $className, method: $fnName'); + + String path = Constants.BASE_URL + 'customer/orders/$orderId/cancel'; + + await HttpUtil().post(path); + + return true; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + return false; + } + } + + static Future saveShipping(Map params) async { + final String fnName = 'saveShipping'; + + try { + debugPrint('class: $className, method: $fnName, params: $params'); + + String path = Constants.BASE_URL + 'customer/checkout/save_shipping'; + + final response = await HttpUtil().post(path, queryParameters: params); + + return CartModel.fromJson(response['data']['cart']); + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + Get.offNamedUntil('/', (route) => false); + navigateToLoginScreen(); + showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + } + return null; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, params: $params, error: $e '); + showSnack('error'.tr, 'error_occurred'.tr, SnackType.ERROR); + return null; + } + } +} diff --git a/lib/app/data/apis/product.dart b/lib/app/data/apis/product.dart new file mode 100644 index 0000000..156460b --- /dev/null +++ b/lib/app/data/apis/product.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import '../../app.dart'; + +class ProductApi { + static String className = 'ProductApi'; + + static Future> getHomePageProducts(Map params, String url) async { + final String fnName = 'getHomePageProducts'; + + try { + debugPrint('class: $className, method: $fnName, params: $params, url: $url'); + + String path = Constants.BASE_URL + url; + + final response = await HttpUtil().get(path: path, queryParameters: params); + + return ProductModel.listFromJson(response['data'] as List); + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, params: $params, error: $e '); + throw new Exception('Error occurred'); + } + } + + static Future> get(Map params) async { + final String fnName = 'get'; + + try { + debugPrint('class: $className, method: $fnName, params: $params'); + + String path = Constants.BASE_URL + 'products'; + + final response = await HttpUtil().get(path: path, queryParameters: params); + + return ProductModel.listFromJson(response['data'] as List); + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, params: $params, error: $e '); + throw new Exception('Error occurred'); + } + } + + static Future?> getProductVariants(int productId) async { + final String fnName = 'getProductVariants'; + + final Map params = { + 'currency': 'TMT', + 'locale': await getLocale(), + }; + + try { + final String path = Constants.BASE_URL + 'products/$productId/variants'; + // final String path = Constants.BASE_URL + 'products/3098/variants'; + + debugPrint('class: $className, method: $fnName, params: $params, path: $path'); + + final response = await HttpUtil().get(path: path, queryParameters: params); + + return response; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, params: $params, error: $e '); + return null; + } + } + + static Future?> getProductAdditionalInfo(int productId, Map params) async { + final String fnName = 'getProductAdditionalInfo'; + + final List list = []; + + try { + debugPrint('class: $className, method: $fnName, params: $params'); + + String path = Constants.BASE_URL + 'product-additional-information/$productId'; + + final response = await HttpUtil().get(path: path, queryParameters: params); + + for (final json in response['data']) { + list.add(ProductAdditionalInfoModel.fromJson(json)); + } + + return list; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, params: $params, error: $e '); + return null; + } + } + + static Future?> getProductReviews(int productId) async { + final String fnName = 'getProductReviews'; + try { + debugPrint('class: $className, method: $fnName'); + + String path = Constants.BASE_URL + 'products/$productId/reviews'; + + final response = await HttpUtil().get(path: path); + + return ReviewModel.listFromJson(response['data'] as List); + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, productId: $productId, error: $e '); + return null; + } + } + + static Future createProductReviews(Map params, int productId) async { + final String fnName = 'createProductReviews'; + try { + debugPrint('class: $className, method: $fnName'); + + String path = Constants.BASE_URL + 'customer/reviews/create/$productId'; + + final response = await HttpUtil().post(path, queryParameters: params); + + showSnack('success'.tr, response['message']); + + return true; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, productId: $productId, error: $e '); + return false; + } + } +} diff --git a/lib/app/data/apis/search.dart b/lib/app/data/apis/search.dart new file mode 100644 index 0000000..e491a16 --- /dev/null +++ b/lib/app/data/apis/search.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:elektronika/app/core/utils/utils.dart'; +import 'package:elektronika/app/data/models/models.dart'; + +class SearchApi { + static Future getSearchResult(Map params) async { + final List products = []; + try { + const String path = Constants.BASE_URL + 'products'; + final response = await HttpUtil().get(path: path, queryParameters: params); + + for (final source in response['data']) { + debugPrint('source: $source'); + products.add(ProductModel.fromJson(source)); + } + + return null; + } catch (e) { + debugPrint('error getProducts: $e'); + return null; + } + } +} + +class TempSearchResult { + late int id; +} diff --git a/lib/app/data/apis/shopping_cart.dart b/lib/app/data/apis/shopping_cart.dart new file mode 100644 index 0000000..9991004 --- /dev/null +++ b/lib/app/data/apis/shopping_cart.dart @@ -0,0 +1,267 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../app.dart'; + +class ShoppingCartApi { + static String className = 'ShoppingCartApi'; + + static Future get() async { + final String fnName = 'get'; + + try { + debugPrint('class: $className, method: $fnName'); + + final String path = Constants.BASE_URL + 'customer/cart'; + + final response = await HttpUtil().get( + path: path, + queryParameters: {'currency': 'tmt'}, + ); + + if (response['data'] == null) return null; + + CartModel cartModel = CartModel.fromJson(response['data']); + + return cartModel; + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + } + + return null; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + showSnack('error'.tr, 'error_occurred'.tr, SnackType.ERROR); + return null; + } + } + + static Future add(BuildContext context, Map params, int productId) async { + final String fnName = 'add'; + + try { + debugPrint('class: $className, method: $fnName , params: $params'); + + final String path = Constants.BASE_URL + 'customer/cart/add/$productId'; + + final response = await HttpUtil().post(path, queryParameters: params); + + final cartModel = CartModel.fromJson(response['data']); + + // showSnack('SUCCESS', 'Item added to cart'); + showSnack('success'.tr, 'item_added'.tr); + + return cartModel; + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + Get.offNamedUntil('/', (route) => false); + navigateToLoginScreen(); + + showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + } + + if (errCode == 405) { + showSnack('warning'.tr, 'qty_not_available'.tr, SnackType.WARNING); + } + + return null; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + + showSnack('error'.tr, 'error_occurred'.tr, SnackType.ERROR); + return null; + } + } + + static Future update(int cartItemId, int quantity) async { + final String fnName = 'update'; + + try { + final Map params = { + 'qty': { + '$cartItemId': quantity, + }, + 'locale': await getLocale(), + }; + + debugPrint('class: $className, method: $fnName , params: $params'); + + final String path = Constants.BASE_URL + 'customer/cart/update'; + + final response = await HttpUtil().put(path, queryParameters: params); + + if (!response['success']) { + showSnack('warning'.tr, response['message'], SnackType.WARNING); + return null; + } + + showSnack('success'.tr, response['message']); + + CartModel cartModel = CartModel.fromJson(response['data']); + + return cartModel; + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + debugPrint('error $error'); + + if (errCode == 401) showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + + return null; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + showSnack('error'.tr, 'error_occurred'.tr, SnackType.ERROR); + return null; + } + } + + static Future remove(int cartItemId) async { + final String fnName = 'remove'; + + try { + debugPrint('class: $className, method: $fnName'); + + final String path = Constants.BASE_URL + 'customer/cart/remove/$cartItemId'; + + final response = await HttpUtil().delete(path); + + showSnack('success'.tr, 'item_removed'.tr); + + if (response['data'] == null) { + return null; + } + + return CartModel.fromJson(response['data']); + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + } + + return null; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + showSnack('error'.tr, 'error_occurred'.tr, SnackType.ERROR); + return null; + } + } + + static Future empty() async { + final String fnName = 'empty'; + + try { + debugPrint('class: $className, method: $fnName'); + + final String path = Constants.BASE_URL + 'customer/cart/empty'; + + await HttpUtil().delete(path); + + return true; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + return false; + } + } + + static Future applyCoupon(String code) async { + final String fnName = 'applyCoupon'; + + try { + debugPrint('class: $className, method: $fnName , code: $code'); + + String path = Constants.BASE_URL + 'customer/cart/coupon'; + + final Map params = { + 'code': code, + 'locale': await getLocale(), + }; + + final response = await HttpUtil().post(path, queryParameters: params); + + if (response['success']) { + showSnack('success'.tr, response['message']); + return CartModel.fromJson(response['data']); + } else { + showSnack('warning'.tr, response['message'], SnackType.WARNING); + return null; + } + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + navigateToLoginScreen(); + + showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + } + + if (errCode == 405) { + showSnack('warning'.tr, 'invalid_coupon_code'.tr, SnackType.WARNING); + } + + return null; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + + showSnack('error'.tr, 'error_occurred'.tr, SnackType.ERROR); + return null; + } + } + + static Future deleteCoupon() async { + final String fnName = 'deleteCoupon'; + + try { + debugPrint('class: $className, method: $fnName '); + + String path = Constants.BASE_URL + 'customer/cart/coupon'; + + final response = await HttpUtil().delete(path); + + if (response['success']) { + showSnack('success'.tr, response['message']); + return CartModel.fromJson(response['data']); + } else { + showSnack('warning'.tr, response['message'], SnackType.WARNING); + return null; + } + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + navigateToLoginScreen(); + + showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + } + + if (errCode == 405) { + showSnack('warning'.tr, 'invalid_coupon_code'.tr, SnackType.WARNING); + } + + return null; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + + showSnack('error'.tr, 'error_occurred'.tr, SnackType.ERROR); + return null; + } + } +} diff --git a/lib/app/data/apis/slider.dart b/lib/app/data/apis/slider.dart new file mode 100644 index 0000000..cac5192 --- /dev/null +++ b/lib/app/data/apis/slider.dart @@ -0,0 +1,41 @@ +import 'package:elektronika/app/core/utils/utils.dart'; +import 'package:elektronika/app/data/models/models.dart'; +import 'package:flutter/material.dart'; + +class SliderApi { + static String className = 'SliderApi'; + + static List sliders = []; + + static Future> get() async { + final String fnName = 'get'; + + if (sliders.isNotEmpty) return sliders; + + final List list = []; + + try { + debugPrint('class: $className, method: $fnName'); + + const String path = Constants.BASE_URL + 'sliders'; + + final response = await HttpUtil().get( + path: path, + queryParameters: { + 'locale': await getLocale(), + }, + ); + + for (final json in response['data']) { + final SliderModel slider = SliderModel.fromJson(json); + sliders.add(slider); + list.add(slider); + } + + return list; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName, error: $e '); + return list; + } + } +} diff --git a/lib/app/data/apis/wishlist.dart b/lib/app/data/apis/wishlist.dart new file mode 100644 index 0000000..5128170 --- /dev/null +++ b/lib/app/data/apis/wishlist.dart @@ -0,0 +1,72 @@ +import 'package:dio/dio.dart'; +import 'package:get/get.dart'; + +import '../../app.dart'; +import 'package:flutter/material.dart'; + +class WishlistApi { + static String className = 'WishlistApi'; + + static Future> get(Map params) async { + final String fnName = 'get'; + + try { + String path = Constants.BASE_URL + 'customer/wishlist'; + + debugPrint('class: $className, method: $fnName, $path'); + + final response = await HttpUtil().get(path: path, queryParameters: params); + + return WishlistModel.listFromJson(response['data'] as List); + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + } + + return throw new Exception('Error occurred'); + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName'); + showSnack('error'.tr, 'error_occurred'.tr, SnackType.ERROR); + throw new Exception('Error occurred'); + } + } + +// add and remove from wishlist + static Future addRemove(int productId) async { + final String fnName = 'addRemove'; + + try { + String path = Constants.BASE_URL + 'customer/wishlist/$productId'; + + debugPrint('class: $className, method: $fnName $path'); + + final response = await HttpUtil().post( + path, + queryParameters: { + 'locale': await getLocale(), + }, + ); + + showSnack('success'.tr, response['message']); + return true; + } on DioError catch (error) { + debugPrint('ERROR: class: $className, method: $fnName, error: $error '); + + int? errCode = error.response?.statusCode; + + if (errCode == 401) { + showSnack('warning'.tr, 'please_login'.tr, SnackType.WARNING); + } + + return false; + } catch (e) { + debugPrint('ERROR: class: $className, method: $fnName'); + showSnack('error', 'can_not_add_item_to_wishlist'.tr, SnackType.ERROR); + return false; + } + } +} diff --git a/lib/app/data/data.dart b/lib/app/data/data.dart new file mode 100644 index 0000000..964f081 --- /dev/null +++ b/lib/app/data/data.dart @@ -0,0 +1,7 @@ +library data; + +export 'apis/apis.dart'; +export 'db/db_helper.dart'; +export 'enums/enums.dart'; +export 'models/models.dart'; +export 'routes/routes.dart'; diff --git a/lib/app/data/db/db_helper.dart b/lib/app/data/db/db_helper.dart new file mode 100644 index 0000000..6f0cf19 --- /dev/null +++ b/lib/app/data/db/db_helper.dart @@ -0,0 +1,73 @@ +import 'dart:async'; +import 'dart:io' as io; + +import 'package:path/path.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:elektronika/app/data/models/models.dart'; +import 'package:sqflite/sqflite.dart'; + +class DBHelper { + Database? _db; + + static const String ID = 'id'; + static const String KEYWORD = 'keyword'; + static const String FIELD = 'field'; + + static const String TABLE = 'history'; + static const String DB_NAME = 'search_history.db'; + + Future get db async { + if (_db != null) { + return _db; + } + _db = await initDb(); + return _db; + } + + Future initDb() async { + io.Directory documentsDirectory = await getApplicationDocumentsDirectory(); + String path = join(documentsDirectory.path, DB_NAME); + var db = await openDatabase(path, version: 1, onCreate: _onCreate); + return db; + } + + Future _onCreate(Database db, int version) async { + await db.execute('CREATE TABLE IF NOT EXISTS $TABLE ($ID INTEGER PRIMARY KEY AUTOINCREMENT, $KEYWORD TEXT,$FIELD TEXT )'); + } + + Future save(SearchHistory searchHistory) async { + var dbClient = await db; + if (dbClient != null) await dbClient.insert(TABLE, searchHistory.toJson()); + } + + Future> getSearchHistory() async { + var dbClient = await db; + if (dbClient != null) { + List maps = await dbClient.rawQuery('SELECT * FROM $TABLE ORDER BY $ID DESC;'); + List products = []; + if (maps.length > 0) { + for (int i = 0; i < maps.length; i++) { + products.add(SearchHistory.fromJson(maps[i])); + } + } + return products; + } + return []; + } + + Future resetDb() async { + var dbClient = await db; + if (dbClient != null) { + await dbClient.delete(TABLE); + // reset id + await dbClient.execute('UPDATE sqlite_sequence SET seq = (SELECT MAX($ID) FROM $TABLE) WHERE name="$TABLE"'); + } + } + + Future close() async { + var dbClient = await db; + if (dbClient != null) dbClient.close(); + } +} + + diff --git a/lib/app/data/enums/bottom_navbar.dart b/lib/app/data/enums/bottom_navbar.dart new file mode 100644 index 0000000..2da4314 --- /dev/null +++ b/lib/app/data/enums/bottom_navbar.dart @@ -0,0 +1,7 @@ +enum BottomNavbar { + HOME, + CATEGORIES, + DISCOUNT, + CARD, + PROFILE, +} diff --git a/lib/app/data/enums/enums.dart b/lib/app/data/enums/enums.dart new file mode 100644 index 0000000..1c8d62e --- /dev/null +++ b/lib/app/data/enums/enums.dart @@ -0,0 +1,2 @@ +export 'bottom_navbar.dart'; +export 'snack_type.dart'; diff --git a/lib/app/data/enums/snack_type.dart b/lib/app/data/enums/snack_type.dart new file mode 100644 index 0000000..f2074df --- /dev/null +++ b/lib/app/data/enums/snack_type.dart @@ -0,0 +1,5 @@ +enum SnackType { + INFO, + WARNING, + ERROR, +} diff --git a/lib/app/data/models/address.dart b/lib/app/data/models/address.dart new file mode 100644 index 0000000..35a3cb4 --- /dev/null +++ b/lib/app/data/models/address.dart @@ -0,0 +1,46 @@ +import 'state.dart'; + +class AddressModel { + late int id; + String? firstName; + String? lastName; + late List address1; + String? country; + String? countryName; + late String stateCode; + String? city; + String? postcode; + String? phone; + late bool isDefault; + late List stateTranslations; + + AddressModel({ + required this.id, + this.firstName, + this.lastName, + required this.address1, + this.country, + this.countryName, + required this.stateCode, + this.city, + this.postcode, + this.phone, + required this.isDefault, + required this.stateTranslations, + }); + + AddressModel.fromJson(Map json) { + id = json['id']; + firstName = json['first_name']; + lastName = json['last_name']; + address1 = json['address1'].cast(); + country = json['country']; + countryName = json['country_name']; + stateCode = json['state']; + city = json['city']; + postcode = json['postcode']; + phone = json['phone']; + isDefault = json['is_default'] ?? false; + stateTranslations = []; + } +} diff --git a/lib/app/data/models/attribute.dart b/lib/app/data/models/attribute.dart new file mode 100644 index 0000000..ea0d057 --- /dev/null +++ b/lib/app/data/models/attribute.dart @@ -0,0 +1,79 @@ +import 'models.dart'; + +class AttributeModel { + late Attribute attribute; + late List