diff --git a/.gitignore b/.gitignore index 7115609f..8b1d2ace 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,25 @@ ios/Podfile.lock ios/Flutter/.last_build_id ios/Runner.xcodeproj/project.pbxproj +devtools_options.yaml +linux/flutter/ephemeral/.plugin_symlinks/flutter_keyboard_visibility_linux +linux/flutter/ephemeral/.plugin_symlinks/maps_launcher +linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux +linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux +linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux +linux/flutter/generated_plugin_registrant.cc +linux/flutter/generated_plugin_registrant.h +linux/flutter/generated_plugins.cmake +macos/Flutter/GeneratedPluginRegistrant.swift +macos/Flutter/ephemeral/Flutter-Generated.xcconfig +macos/Flutter/ephemeral/flutter_export_environment.sh +windows/flutter/ephemeral/.plugin_symlinks/file_picker +windows/flutter/ephemeral/.plugin_symlinks/firebase_core +windows/flutter/ephemeral/.plugin_symlinks/flutter_inappwebview_windows +windows/flutter/ephemeral/.plugin_symlinks/flutter_keyboard_visibility_windows +windows/flutter/ephemeral/.plugin_symlinks/local_auth_windows +windows/flutter/ephemeral/.plugin_symlinks/maps_launcher +windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows +windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows +windows/flutter/ephemeral/.plugin_symlinks/shared_preferences_windows +windows/flutter/ephemeral/.plugin_symlinks/url_launcher_windows diff --git a/.metadata b/.metadata index 01d2dcb9..d2765fcb 100644 --- a/.metadata +++ b/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 0b8abb4724aa590dd0f429683339b1e045a1594d - channel: stable + revision: "54e66469a933b60ddf175f858f82eaeb97e48c8d" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + - platform: android + create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + - platform: ios + create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + - platform: linux + create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + - platform: macos + create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + - platform: web + create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + - platform: windows + create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 00000000..0d290213 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/android/app/build.gradle b/android/app/build.gradle index 8e026908..48fb27f4 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -120,14 +120,17 @@ dependencies { //openTok implementation 'com.opentok.android:opentok-android-sdk:2.20.1' //permissions - implementation 'pub.devrel:easypermissions:0.4.0' +// implementation 'pub.devrel:easypermissions:0.4.0' + implementation project(':easypermissions') + //retrofit + implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.6.2' implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1' implementation 'com.squareup.retrofit2:adapter-rxjava:2.1.0' - + implementation 'com.android.support:multidex:1.0.3' implementation 'com.google.firebase:firebase-analytics:17.4.1' } apply plugin: 'com.google.gms.google-services' \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index db0fe5f0..e9c14541 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -29,6 +29,10 @@ + + + + + if (project.plugins.hasPlugin("com.android.application") || + project.plugins.hasPlugin("com.android.library")) { + project.android { + compileSdkVersion 34 + buildToolsVersion "34.0.0" + } + } + } +} +// to here subprojects { project.evaluationDependsOn(':app') } diff --git a/android/easypermissions/build.gradle b/android/easypermissions/build.gradle new file mode 100644 index 00000000..89a6fb5f --- /dev/null +++ b/android/easypermissions/build.gradle @@ -0,0 +1,52 @@ +apply plugin: 'com.android.library' + +// See: https://github.com/vanniktech/gradle-maven-publish-plugin/issues/206 +ext { + RELEASE_REPOSITORY_URL = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" + SNAPSHOT_REPOSITORY_URL = "https://s01.oss.sonatype.org/content/repositories/snapshots/" +} + +//apply plugin: 'com.vanniktech.maven.publish' + +android { + compileSdkVersion 30 + testOptions.unitTests.includeAndroidResources = true + + defaultConfig { + minSdkVersion 14 + targetSdkVersion 30 + versionCode 1 + versionName "3.0.0" + } + + buildTypes { + debug { + testCoverageEnabled true + } + release { + minifyEnabled false + consumerProguardFiles 'proguard-rules.pro' + } + } + + testOptions { + unitTests { + includeAndroidResources = true + } + } + +} + +dependencies { + api "androidx.appcompat:appcompat:1.1.0" + api "androidx.annotation:annotation:1.1.0" + api "androidx.core:core:1.3.0" + api "androidx.fragment:fragment:1.2.5" + + testImplementation 'junit:junit:4.13' + testImplementation 'com.google.truth:truth:0.42' + testImplementation 'org.robolectric:robolectric:4.1' + testImplementation 'androidx.test:core:1.3.0-rc01' + testImplementation 'androidx.fragment:fragment-testing:1.2.5' + testImplementation 'org.mockito:mockito-core:2.23.4' +} diff --git a/android/easypermissions/gradle.properties b/android/easypermissions/gradle.properties new file mode 100644 index 00000000..3e0ef642 --- /dev/null +++ b/android/easypermissions/gradle.properties @@ -0,0 +1,18 @@ +GROUP=pub.devrel +POM_ARTIFACT_ID=easypermissions +VERSION_NAME=3.0.0 + +POM_NAME=EasyPermissions +POM_PACKAGING=aar + +POM_DESCRIPTION=A wrapper library for basic Android M system permissions logic + +POM_URL=https://github.com/googlesamples/easypermissions +POM_SCM_URL=https://github.com/googlesamples/easypermissions +POM_SCM_CONNECTION=https://github.com/googlesamples/easypermissions.git + +POM_LICENCE_NAME=The Apache Software License, Version 2.0 +POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt +POM_LICENCE_DIST=repo + +POM_DEVELOPER_NAME=Google diff --git a/android/easypermissions/proguard-rules.pro b/android/easypermissions/proguard-rules.pro new file mode 100644 index 00000000..e0ba183b --- /dev/null +++ b/android/easypermissions/proguard-rules.pro @@ -0,0 +1,3 @@ +-keepclassmembers class * { + @pub.devrel.easypermissions.AfterPermissionGranted ; +} diff --git a/android/easypermissions/src/main/AndroidManifest.xml b/android/easypermissions/src/main/AndroidManifest.xml new file mode 100644 index 00000000..16a209f6 --- /dev/null +++ b/android/easypermissions/src/main/AndroidManifest.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/AfterPermissionGranted.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/AfterPermissionGranted.java new file mode 100644 index 00000000..09202a22 --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/AfterPermissionGranted.java @@ -0,0 +1,29 @@ +/* + * Copyright Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package pub.devrel.easypermissions; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface AfterPermissionGranted { + + int value(); + +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialog.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialog.java new file mode 100644 index 00000000..4407e4fc --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialog.java @@ -0,0 +1,356 @@ +package pub.devrel.easypermissions; + +import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; +import androidx.annotation.StringRes; +import androidx.annotation.StyleRes; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.Fragment; + +/** + * Dialog to prompt the user to go to the app's settings screen and enable permissions. If the user + * clicks 'OK' on the dialog, they are sent to the settings screen. The result is returned to the + * Activity via {@see Activity#onActivityResult(int, int, Intent)}. + *

+ * Use the {@link Builder} to create and display a dialog. + */ +public class AppSettingsDialog implements Parcelable { + + private static final String TAG = "EasyPermissions"; + + public static final int DEFAULT_SETTINGS_REQ_CODE = 16061; + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public AppSettingsDialog createFromParcel(Parcel in) { + return new AppSettingsDialog(in); + } + + @Override + public AppSettingsDialog[] newArray(int size) { + return new AppSettingsDialog[size]; + } + }; + + static final String EXTRA_APP_SETTINGS = "extra_app_settings"; + + @StyleRes + private final int mThemeResId; + private final String mRationale; + private final String mTitle; + private final String mPositiveButtonText; + private final String mNegativeButtonText; + private final int mRequestCode; + private final int mIntentFlags; + + private Object mActivityOrFragment; + private Context mContext; + + private AppSettingsDialog(Parcel in) { + mThemeResId = in.readInt(); + mRationale = in.readString(); + mTitle = in.readString(); + mPositiveButtonText = in.readString(); + mNegativeButtonText = in.readString(); + mRequestCode = in.readInt(); + mIntentFlags = in.readInt(); + } + + private AppSettingsDialog(@NonNull final Object activityOrFragment, + @StyleRes int themeResId, + @Nullable String rationale, + @Nullable String title, + @Nullable String positiveButtonText, + @Nullable String negativeButtonText, + int requestCode, + int intentFlags) { + setActivityOrFragment(activityOrFragment); + mThemeResId = themeResId; + mRationale = rationale; + mTitle = title; + mPositiveButtonText = positiveButtonText; + mNegativeButtonText = negativeButtonText; + mRequestCode = requestCode; + mIntentFlags = intentFlags; + } + + static AppSettingsDialog fromIntent(Intent intent, Activity activity) { + AppSettingsDialog dialog = intent.getParcelableExtra(AppSettingsDialog.EXTRA_APP_SETTINGS); + + // It's not clear how this could happen, but in the case that it does we should try + // to avoid a runtime crash and just use the default dialog. + // https://github.com/googlesamples/easypermissions/issues/278 + if (dialog == null) { + Log.e(TAG, "Intent contains null value for EXTRA_APP_SETTINGS: " + + "intent=" + intent + + ", " + + "extras=" + intent.getExtras()); + + dialog = new AppSettingsDialog.Builder(activity).build(); + } + + dialog.setActivityOrFragment(activity); + return dialog; + } + + private void setActivityOrFragment(Object activityOrFragment) { + mActivityOrFragment = activityOrFragment; + + if (activityOrFragment instanceof Activity) { + mContext = (Activity) activityOrFragment; + } else if (activityOrFragment instanceof Fragment) { + mContext = ((Fragment) activityOrFragment).getContext(); + } else { + throw new IllegalStateException("Unknown object: " + activityOrFragment); + } + } + + private void startForResult(Intent intent) { + if (mActivityOrFragment instanceof Activity) { + ((Activity) mActivityOrFragment).startActivityForResult(intent, mRequestCode); + } else if (mActivityOrFragment instanceof Fragment) { + ((Fragment) mActivityOrFragment).startActivityForResult(intent, mRequestCode); + } + } + + /** + * Display the built dialog. + */ + public void show() { + startForResult(AppSettingsDialogHolderActivity.createShowDialogIntent(mContext, this)); + } + + /** + * Show the dialog. {@link #show()} is a wrapper to ensure backwards compatibility + */ + AlertDialog showDialog(DialogInterface.OnClickListener positiveListener, + DialogInterface.OnClickListener negativeListener) { + AlertDialog.Builder builder; + if (mThemeResId != -1) { + builder = new AlertDialog.Builder(mContext, mThemeResId); + } else { + builder = new AlertDialog.Builder(mContext); + } + return builder + .setCancelable(false) + .setTitle(mTitle) + .setMessage(mRationale) + .setPositiveButton(mPositiveButtonText, positiveListener) + .setNegativeButton(mNegativeButtonText, negativeListener) + .show(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mThemeResId); + dest.writeString(mRationale); + dest.writeString(mTitle); + dest.writeString(mPositiveButtonText); + dest.writeString(mNegativeButtonText); + dest.writeInt(mRequestCode); + dest.writeInt(mIntentFlags); + } + + int getIntentFlags() { + return mIntentFlags; + } + + /** + * Builder for an {@link AppSettingsDialog}. + */ + public static class Builder { + + private final Object mActivityOrFragment; + private final Context mContext; + @StyleRes + private int mThemeResId = -1; + private String mRationale; + private String mTitle; + private String mPositiveButtonText; + private String mNegativeButtonText; + private int mRequestCode = -1; + private boolean mOpenInNewTask = false; + + /** + * Create a new Builder for an {@link AppSettingsDialog}. + * + * @param activity the {@link Activity} in which to display the dialog. + */ + public Builder(@NonNull Activity activity) { + mActivityOrFragment = activity; + mContext = activity; + } + + /** + * Create a new Builder for an {@link AppSettingsDialog}. + * + * @param fragment the {@link Fragment} in which to display the dialog. + */ + public Builder(@NonNull Fragment fragment) { + mActivityOrFragment = fragment; + mContext = fragment.getContext(); + } + + /** + * Set the dialog theme. + */ + @NonNull + public Builder setThemeResId(@StyleRes int themeResId) { + mThemeResId = themeResId; + return this; + } + + /** + * Set the title dialog. Default is "Permissions Required". + */ + @NonNull + public Builder setTitle(@Nullable String title) { + mTitle = title; + return this; + } + + /** + * Set the title dialog. Default is "Permissions Required". + */ + @NonNull + public Builder setTitle(@StringRes int title) { + mTitle = mContext.getString(title); + return this; + } + + /** + * Set the rationale dialog. Default is + * "This app may not work correctly without the requested permissions. + * Open the app settings screen to modify app permissions." + */ + @NonNull + public Builder setRationale(@Nullable String rationale) { + mRationale = rationale; + return this; + } + + /** + * Set the rationale dialog. Default is + * "This app may not work correctly without the requested permissions. + * Open the app settings screen to modify app permissions." + */ + @NonNull + public Builder setRationale(@StringRes int rationale) { + mRationale = mContext.getString(rationale); + return this; + } + + /** + * Set the positive button text, default is {@link android.R.string#ok}. + */ + @NonNull + public Builder setPositiveButton(@Nullable String text) { + mPositiveButtonText = text; + return this; + } + + /** + * Set the positive button text, default is {@link android.R.string#ok}. + */ + @NonNull + public Builder setPositiveButton(@StringRes int textId) { + mPositiveButtonText = mContext.getString(textId); + return this; + } + + /** + * Set the negative button text, default is {@link android.R.string#cancel}. + *

+ * To know if a user cancelled the request, check if your permissions were given with {@link + * EasyPermissions#hasPermissions(Context, String...)} in {@see + * Activity#onActivityResult(int, int, Intent)}. If you still don't have the right + * permissions, then the request was cancelled. + */ + @NonNull + public Builder setNegativeButton(@Nullable String text) { + mNegativeButtonText = text; + return this; + } + + /** + * Set the negative button text, default is {@link android.R.string#cancel}. + */ + @NonNull + public Builder setNegativeButton(@StringRes int textId) { + mNegativeButtonText = mContext.getString(textId); + return this; + } + + /** + * Set the request code use when launching the Settings screen for result, can be retrieved + * in the calling Activity's {@see Activity#onActivityResult(int, int, Intent)} method. + * Default is {@link #DEFAULT_SETTINGS_REQ_CODE}. + */ + @NonNull + public Builder setRequestCode(int requestCode) { + mRequestCode = requestCode; + return this; + } + + /** + * Set whether the settings screen should be opened in a separate task. This is achieved by + * setting {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK#FLAG_ACTIVITY_NEW_TASK} on + * the Intent used to open the settings screen. + */ + @NonNull + public Builder setOpenInNewTask(boolean openInNewTask) { + mOpenInNewTask = openInNewTask; + return this; + } + + /** + * Build the {@link AppSettingsDialog} from the specified options. Generally followed by a + * call to {@link AppSettingsDialog#show()}. + */ + @NonNull + public AppSettingsDialog build() { + mRationale = TextUtils.isEmpty(mRationale) ? + mContext.getString(R.string.rationale_ask_again) : mRationale; + mTitle = TextUtils.isEmpty(mTitle) ? + mContext.getString(R.string.title_settings_dialog) : mTitle; + mPositiveButtonText = TextUtils.isEmpty(mPositiveButtonText) ? + mContext.getString(android.R.string.ok) : mPositiveButtonText; + mNegativeButtonText = TextUtils.isEmpty(mNegativeButtonText) ? + mContext.getString(android.R.string.cancel) : mNegativeButtonText; + mRequestCode = mRequestCode > 0 ? mRequestCode : DEFAULT_SETTINGS_REQ_CODE; + + int intentFlags = 0; + if (mOpenInNewTask) { + intentFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; + } + + return new AppSettingsDialog( + mActivityOrFragment, + mThemeResId, + mRationale, + mTitle, + mPositiveButtonText, + mNegativeButtonText, + mRequestCode, + intentFlags); + } + + } + +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialogHolderActivity.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialogHolderActivity.java new file mode 100644 index 00000000..d996dd7f --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialogHolderActivity.java @@ -0,0 +1,65 @@ +package pub.devrel.easypermissions; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.provider.Settings; +import androidx.annotation.RestrictTo; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +public class AppSettingsDialogHolderActivity extends AppCompatActivity implements DialogInterface.OnClickListener { + private static final int APP_SETTINGS_RC = 7534; + + private AlertDialog mDialog; + private int mIntentFlags; + + public static Intent createShowDialogIntent(Context context, AppSettingsDialog dialog) { + Intent intent = new Intent(context, AppSettingsDialogHolderActivity.class); + intent.putExtra(AppSettingsDialog.EXTRA_APP_SETTINGS, dialog); + return intent; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + AppSettingsDialog appSettingsDialog = AppSettingsDialog.fromIntent(getIntent(), this); + mIntentFlags = appSettingsDialog.getIntentFlags(); + mDialog = appSettingsDialog.showDialog(this, this); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mDialog != null && mDialog.isShowing()) { + mDialog.dismiss(); + } + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (which == Dialog.BUTTON_POSITIVE) { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + .setData(Uri.fromParts("package", getPackageName(), null)); + intent.addFlags(mIntentFlags); + startActivityForResult(intent, APP_SETTINGS_RC); + } else if (which == Dialog.BUTTON_NEGATIVE) { + setResult(Activity.RESULT_CANCELED); + finish(); + } else { + throw new IllegalStateException("Unknown button type: " + which); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + setResult(resultCode, data); + finish(); + } +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java new file mode 100644 index 00000000..dfc20d0e --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java @@ -0,0 +1,358 @@ +/* + * Copyright Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package pub.devrel.easypermissions; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Build; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Size; +import androidx.core.app.ActivityCompat; +import androidx.fragment.app.Fragment; +import androidx.core.content.ContextCompat; +import android.util.Log; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import pub.devrel.easypermissions.helper.PermissionHelper; + +/** + * Utility to request and check System permissions for apps targeting Android M (API >= 23). + */ +public class EasyPermissions { + + /** + * Callback interface to receive the results of {@code EasyPermissions.requestPermissions()} + * calls. + */ + public interface PermissionCallbacks extends ActivityCompat.OnRequestPermissionsResultCallback { + + void onPermissionsGranted(int requestCode, @NonNull List perms); + + void onPermissionsDenied(int requestCode, @NonNull List perms); + } + + /** + * Callback interface to receive button clicked events of the rationale dialog + */ + public interface RationaleCallbacks { + void onRationaleAccepted(int requestCode); + + void onRationaleDenied(int requestCode); + } + + private static final String TAG = "EasyPermissions"; + + /** + * Check if the calling context has a set of permissions. + * + * @param context the calling context. + * @param perms one ore more permissions, such as {@link Manifest.permission#CAMERA}. + * @return true if all permissions are already granted, false if at least one permission is not + * yet granted. + * @see Manifest.permission + */ + public static boolean hasPermissions(@NonNull Context context, + @Size(min = 1) @NonNull String... perms) { + // Always return true for SDK < M, let the system deal with the permissions + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + Log.w(TAG, "hasPermissions: API version < M, returning true by default"); + + // DANGER ZONE!!! Changing this will break the library. + return true; + } + + // Null context may be passed if we have detected Low API (less than M) so getting + // to this point with a null context should not be possible. + if (context == null) { + throw new IllegalArgumentException("Can't check permissions for null context"); + } + + for (String perm : perms) { + if (ContextCompat.checkSelfPermission(context, perm) + != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + + return true; + } + + /** + * Request a set of permissions, showing a rationale if the system requests it. + * + * @param host requesting context. + * @param rationale a message explaining why the application needs this set of permissions; + * will be displayed if the user rejects the request the first time. + * @param requestCode request code to track this request, must be < 256. + * @param perms a set of permissions to be requested. + * @see Manifest.permission + */ + public static void requestPermissions( + @NonNull Activity host, @NonNull String rationale, + @IntRange(from = 0, to = 255) int requestCode, @Size(min = 1) @NonNull String... perms) { + requestPermissions( + new PermissionRequest.Builder(host, requestCode, perms) + .setRationale(rationale) + .build()); + } + + /** + * Request permissions from a Support Fragment with standard OK/Cancel buttons. + * + * @see #requestPermissions(Activity, String, int, String...) + */ + public static void requestPermissions( + @NonNull Fragment host, @NonNull String rationale, + @IntRange(from = 0, to = 255) int requestCode, @Size(min = 1) @NonNull String... perms) { + requestPermissions( + new PermissionRequest.Builder(host, requestCode, perms) + .setRationale(rationale) + .build()); + } + + /** + * Request a set of permissions. + * + * @param request the permission request + * @see PermissionRequest + */ + public static void requestPermissions(PermissionRequest request) { + + // Check for permissions before dispatching the request + if (hasPermissions(request.getHelper().getContext(), request.getPerms())) { + notifyAlreadyHasPermissions( + request.getHelper().getHost(), request.getRequestCode(), request.getPerms()); + return; + } + + // Request permissions + request.getHelper().requestPermissions( + request.getRationale(), + request.getPositiveButtonText(), + request.getNegativeButtonText(), + request.getTheme(), + request.getRequestCode(), + request.getPerms()); + } + + /** + * Handle the result of a permission request, should be called from the calling {@link + * Activity}'s {@link ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, + * String[], int[])} method. + *

+ * If any permissions were granted or denied, the {@code object} will receive the appropriate + * callbacks through {@link PermissionCallbacks} and methods annotated with {@link + * AfterPermissionGranted} will be run if appropriate. + * + * @param requestCode requestCode argument to permission result callback. + * @param permissions permissions argument to permission result callback. + * @param grantResults grantResults argument to permission result callback. + * @param receivers an array of objects that have a method annotated with {@link + * AfterPermissionGranted} or implement {@link PermissionCallbacks}. + */ + public static void onRequestPermissionsResult(@IntRange(from = 0, to = 255) int requestCode, + @NonNull String[] permissions, + @NonNull int[] grantResults, + @NonNull Object... receivers) { + // Make a collection of granted and denied permissions from the request. + List granted = new ArrayList<>(); + List denied = new ArrayList<>(); + for (int i = 0; i < permissions.length; i++) { + String perm = permissions[i]; + if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + granted.add(perm); + } else { + denied.add(perm); + } + } + + // iterate through all receivers + for (Object object : receivers) { + // Report granted permissions, if any. + if (!granted.isEmpty()) { + if (object instanceof PermissionCallbacks) { + ((PermissionCallbacks) object).onPermissionsGranted(requestCode, granted); + } + } + + // Report denied permissions, if any. + if (!denied.isEmpty()) { + if (object instanceof PermissionCallbacks) { + ((PermissionCallbacks) object).onPermissionsDenied(requestCode, denied); + } + } + + // If 100% successful, call annotated methods + if (!granted.isEmpty() && denied.isEmpty()) { + runAnnotatedMethods(object, requestCode); + } + } + } + + /** + * Check if at least one permission in the list of denied permissions has been permanently + * denied (user clicked "Never ask again"). + * + * Note: Due to a limitation in the information provided by the Android + * framework permissions API, this method only works after the permission + * has been denied and your app has received the onPermissionsDenied callback. + * Otherwise the library cannot distinguish permanent denial from the + * "not yet denied" case. + * + * @param host context requesting permissions. + * @param deniedPermissions list of denied permissions, usually from {@link + * PermissionCallbacks#onPermissionsDenied(int, List)} + * @return {@code true} if at least one permission in the list was permanently denied. + */ + public static boolean somePermissionPermanentlyDenied(@NonNull Activity host, + @NonNull List deniedPermissions) { + return PermissionHelper.newInstance(host) + .somePermissionPermanentlyDenied(deniedPermissions); + } + + /** + * @see #somePermissionPermanentlyDenied(Activity, List) + */ + public static boolean somePermissionPermanentlyDenied(@NonNull Fragment host, + @NonNull List deniedPermissions) { + return PermissionHelper.newInstance(host) + .somePermissionPermanentlyDenied(deniedPermissions); + } + + /** + * Check if a permission has been permanently denied (user clicked "Never ask again"). + * + * @param host context requesting permissions. + * @param deniedPermission denied permission. + * @return {@code true} if the permissions has been permanently denied. + */ + public static boolean permissionPermanentlyDenied(@NonNull Activity host, + @NonNull String deniedPermission) { + return PermissionHelper.newInstance(host).permissionPermanentlyDenied(deniedPermission); + } + + /** + * @see #permissionPermanentlyDenied(Activity, String) + */ + public static boolean permissionPermanentlyDenied(@NonNull Fragment host, + @NonNull String deniedPermission) { + return PermissionHelper.newInstance(host).permissionPermanentlyDenied(deniedPermission); + } + + /** + * See if some denied permission has been permanently denied. + * + * @param host requesting context. + * @param perms array of permissions. + * @return true if the user has previously denied any of the {@code perms} and we should show a + * rationale, false otherwise. + */ + public static boolean somePermissionDenied(@NonNull Activity host, + @NonNull String... perms) { + return PermissionHelper.newInstance(host).somePermissionDenied(perms); + } + + /** + * @see #somePermissionDenied(Activity, String...) + */ + public static boolean somePermissionDenied(@NonNull Fragment host, + @NonNull String... perms) { + return PermissionHelper.newInstance(host).somePermissionDenied(perms); + } + + /** + * Run permission callbacks on an object that requested permissions but already has them by + * simulating {@link PackageManager#PERMISSION_GRANTED}. + * + * @param object the object requesting permissions. + * @param requestCode the permission request code. + * @param perms a list of permissions requested. + */ + private static void notifyAlreadyHasPermissions(@NonNull Object object, + int requestCode, + @NonNull String[] perms) { + int[] grantResults = new int[perms.length]; + for (int i = 0; i < perms.length; i++) { + grantResults[i] = PackageManager.PERMISSION_GRANTED; + } + + onRequestPermissionsResult(requestCode, perms, grantResults, object); + } + + /** + * Find all methods annotated with {@link AfterPermissionGranted} on a given object with the + * correct requestCode argument. + * + * @param object the object with annotated methods. + * @param requestCode the requestCode passed to the annotation. + */ + private static void runAnnotatedMethods(@NonNull Object object, int requestCode) { + Class clazz = object.getClass(); + if (isUsingAndroidAnnotations(object)) { + clazz = clazz.getSuperclass(); + } + + while (clazz != null) { + for (Method method : clazz.getDeclaredMethods()) { + AfterPermissionGranted ann = method.getAnnotation(AfterPermissionGranted.class); + if (ann != null) { + // Check for annotated methods with matching request code. + if (ann.value() == requestCode) { + // Method must be void so that we can invoke it + if (method.getParameterTypes().length > 0) { + throw new RuntimeException( + "Cannot execute method " + method.getName() + " because it is non-void method and/or has input parameters."); + } + + try { + // Make method accessible if private + if (!method.isAccessible()) { + method.setAccessible(true); + } + method.invoke(object); + } catch (IllegalAccessException e) { + Log.e(TAG, "runDefaultMethod:IllegalAccessException", e); + } catch (InvocationTargetException e) { + Log.e(TAG, "runDefaultMethod:InvocationTargetException", e); + } + } + } + } + + clazz = clazz.getSuperclass(); + } + } + + /** + * Determine if the project is using the AndroidAnnotations library. + */ + private static boolean isUsingAndroidAnnotations(@NonNull Object object) { + if (!object.getClass().getSimpleName().endsWith("_")) { + return false; + } + try { + Class clazz = Class.forName("org.androidannotations.api.view.HasViews"); + return clazz.isInstance(object); + } catch (ClassNotFoundException e) { + return false; + } + } +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/PermissionRequest.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/PermissionRequest.java new file mode 100644 index 00000000..02d2e6d1 --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/PermissionRequest.java @@ -0,0 +1,260 @@ +package pub.devrel.easypermissions; + +import android.app.Activity; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; +import androidx.annotation.Size; +import androidx.annotation.StringRes; +import androidx.annotation.StyleRes; +import androidx.fragment.app.Fragment; + +import java.util.Arrays; + +import pub.devrel.easypermissions.helper.PermissionHelper; + +/** + * An immutable model object that holds all of the parameters associated with a permission request, + * such as the permissions, request code, and rationale. + * + * @see EasyPermissions#requestPermissions(PermissionRequest) + * @see PermissionRequest.Builder + */ +public final class PermissionRequest { + private final PermissionHelper mHelper; + private final String[] mPerms; + private final int mRequestCode; + private final String mRationale; + private final String mPositiveButtonText; + private final String mNegativeButtonText; + private final int mTheme; + + private PermissionRequest(PermissionHelper helper, + String[] perms, + int requestCode, + String rationale, + String positiveButtonText, + String negativeButtonText, + int theme) { + mHelper = helper; + mPerms = perms.clone(); + mRequestCode = requestCode; + mRationale = rationale; + mPositiveButtonText = positiveButtonText; + mNegativeButtonText = negativeButtonText; + mTheme = theme; + } + + @NonNull + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + public PermissionHelper getHelper() { + return mHelper; + } + + @NonNull + public String[] getPerms() { + return mPerms.clone(); + } + + public int getRequestCode() { + return mRequestCode; + } + + @NonNull + public String getRationale() { + return mRationale; + } + + @NonNull + public String getPositiveButtonText() { + return mPositiveButtonText; + } + + @NonNull + public String getNegativeButtonText() { + return mNegativeButtonText; + } + + @StyleRes + public int getTheme() { + return mTheme; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + PermissionRequest request = (PermissionRequest) o; + + return Arrays.equals(mPerms, request.mPerms) && mRequestCode == request.mRequestCode; + } + + @Override + public int hashCode() { + int result = Arrays.hashCode(mPerms); + result = 31 * result + mRequestCode; + return result; + } + + @Override + public String toString() { + return "PermissionRequest{" + + "mHelper=" + mHelper + + ", mPerms=" + Arrays.toString(mPerms) + + ", mRequestCode=" + mRequestCode + + ", mRationale='" + mRationale + '\'' + + ", mPositiveButtonText='" + mPositiveButtonText + '\'' + + ", mNegativeButtonText='" + mNegativeButtonText + '\'' + + ", mTheme=" + mTheme + + '}'; + } + + /** + * Builder to build a permission request with variable options. + * + * @see PermissionRequest + */ + public static final class Builder { + private final PermissionHelper mHelper; + private final int mRequestCode; + private final String[] mPerms; + + private String mRationale; + private String mPositiveButtonText; + private String mNegativeButtonText; + private int mTheme = -1; + + /** + * Construct a new permission request builder with a host, request code, and the requested + * permissions. + * + * @param activity the permission request host + * @param requestCode request code to track this request; must be < 256 + * @param perms the set of permissions to be requested + */ + public Builder(@NonNull Activity activity, int requestCode, + @NonNull @Size(min = 1) String... perms) { + mHelper = PermissionHelper.newInstance(activity); + mRequestCode = requestCode; + mPerms = perms; + } + + /** + * @see #Builder(Activity, int, String...) + */ + public Builder(@NonNull Fragment fragment, int requestCode, + @NonNull @Size(min = 1) String... perms) { + mHelper = PermissionHelper.newInstance(fragment); + mRequestCode = requestCode; + mPerms = perms; + } + + /** + * Set the rationale to display to the user if they don't allow your permissions on the + * first try. This rationale will be shown as long as the user has denied your permissions + * at least once, but has not yet permanently denied your permissions. Should the user + * permanently deny your permissions, use the {@link AppSettingsDialog} instead. + *

+ * The default rationale text is {@link R.string#rationale_ask}. + * + * @param rationale the rationale to be displayed to the user should they deny your + * permission at least once + */ + @NonNull + public Builder setRationale(@Nullable String rationale) { + mRationale = rationale; + return this; + } + + /** + * @param resId the string resource to be used as a rationale + * @see #setRationale(String) + */ + @NonNull + public Builder setRationale(@StringRes int resId) { + mRationale = mHelper.getContext().getString(resId); + return this; + } + + /** + * Set the positive button text for the rationale dialog should it be shown. + *

+ * The default is {@link android.R.string#ok} + */ + @NonNull + public Builder setPositiveButtonText(@Nullable String positiveButtonText) { + mPositiveButtonText = positiveButtonText; + return this; + } + + /** + * @see #setPositiveButtonText(String) + */ + @NonNull + public Builder setPositiveButtonText(@StringRes int resId) { + mPositiveButtonText = mHelper.getContext().getString(resId); + return this; + } + + /** + * Set the negative button text for the rationale dialog should it be shown. + *

+ * The default is {@link android.R.string#cancel} + */ + @NonNull + public Builder setNegativeButtonText(@Nullable String negativeButtonText) { + mNegativeButtonText = negativeButtonText; + return this; + } + + /** + * @see #setNegativeButtonText(String) + */ + @NonNull + public Builder setNegativeButtonText(@StringRes int resId) { + mNegativeButtonText = mHelper.getContext().getString(resId); + return this; + } + + /** + * Set the theme to be used for the rationale dialog should it be shown. + * + * @param theme a style resource + */ + @NonNull + public Builder setTheme(@StyleRes int theme) { + mTheme = theme; + return this; + } + + /** + * Build the permission request. + * + * @return the permission request + * @see EasyPermissions#requestPermissions(PermissionRequest) + * @see PermissionRequest + */ + @NonNull + public PermissionRequest build() { + if (mRationale == null) { + mRationale = mHelper.getContext().getString(R.string.rationale_ask); + } + if (mPositiveButtonText == null) { + mPositiveButtonText = mHelper.getContext().getString(android.R.string.ok); + } + if (mNegativeButtonText == null) { + mNegativeButtonText = mHelper.getContext().getString(android.R.string.cancel); + } + + return new PermissionRequest( + mHelper, + mPerms, + mRequestCode, + mRationale, + mPositiveButtonText, + mNegativeButtonText, + mTheme); + } + } +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogClickListener.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogClickListener.java new file mode 100644 index 00000000..d07afffa --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogClickListener.java @@ -0,0 +1,77 @@ +package pub.devrel.easypermissions; + +import android.app.Activity; +import android.app.Dialog; +import android.content.DialogInterface; +import androidx.fragment.app.Fragment; + +import java.util.Arrays; + +import pub.devrel.easypermissions.helper.PermissionHelper; + +/** + * Click listener for either {@link RationaleDialogFragment} or {@link RationaleDialogFragmentCompat}. + */ +class RationaleDialogClickListener implements Dialog.OnClickListener { + + private Object mHost; + private RationaleDialogConfig mConfig; + private EasyPermissions.PermissionCallbacks mCallbacks; + private EasyPermissions.RationaleCallbacks mRationaleCallbacks; + + RationaleDialogClickListener(RationaleDialogFragmentCompat compatDialogFragment, + RationaleDialogConfig config, + EasyPermissions.PermissionCallbacks callbacks, + EasyPermissions.RationaleCallbacks rationaleCallbacks) { + + mHost = compatDialogFragment.getParentFragment() != null + ? compatDialogFragment.getParentFragment() + : compatDialogFragment.getActivity(); + + mConfig = config; + mCallbacks = callbacks; + mRationaleCallbacks = rationaleCallbacks; + + } + + RationaleDialogClickListener(RationaleDialogFragment dialogFragment, + RationaleDialogConfig config, + EasyPermissions.PermissionCallbacks callbacks, + EasyPermissions.RationaleCallbacks dialogCallback) { + + mHost = dialogFragment.getActivity(); + + mConfig = config; + mCallbacks = callbacks; + mRationaleCallbacks = dialogCallback; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + int requestCode = mConfig.requestCode; + if (which == Dialog.BUTTON_POSITIVE) { + String[] permissions = mConfig.permissions; + if (mRationaleCallbacks != null) { + mRationaleCallbacks.onRationaleAccepted(requestCode); + } + if (mHost instanceof Fragment) { + PermissionHelper.newInstance((Fragment) mHost).directRequestPermissions(requestCode, permissions); + } else if (mHost instanceof Activity) { + PermissionHelper.newInstance((Activity) mHost).directRequestPermissions(requestCode, permissions); + } else { + throw new RuntimeException("Host must be an Activity or Fragment!"); + } + } else { + if (mRationaleCallbacks != null) { + mRationaleCallbacks.onRationaleDenied(requestCode); + } + notifyPermissionDenied(); + } + } + + private void notifyPermissionDenied() { + if (mCallbacks != null) { + mCallbacks.onPermissionsDenied(mConfig.requestCode, Arrays.asList(mConfig.permissions)); + } + } +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogConfig.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogConfig.java new file mode 100644 index 00000000..c64999c6 --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogConfig.java @@ -0,0 +1,95 @@ +package pub.devrel.easypermissions; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.StyleRes; +import androidx.appcompat.app.AlertDialog; + +/** + * Configuration for either {@link RationaleDialogFragment} or {@link RationaleDialogFragmentCompat}. + */ +class RationaleDialogConfig { + + private static final String KEY_POSITIVE_BUTTON = "positiveButton"; + private static final String KEY_NEGATIVE_BUTTON = "negativeButton"; + private static final String KEY_RATIONALE_MESSAGE = "rationaleMsg"; + private static final String KEY_THEME = "theme"; + private static final String KEY_REQUEST_CODE = "requestCode"; + private static final String KEY_PERMISSIONS = "permissions"; + + String positiveButton; + String negativeButton; + int theme; + int requestCode; + String rationaleMsg; + String[] permissions; + + RationaleDialogConfig(@NonNull String positiveButton, + @NonNull String negativeButton, + @NonNull String rationaleMsg, + @StyleRes int theme, + int requestCode, + @NonNull String[] permissions) { + + this.positiveButton = positiveButton; + this.negativeButton = negativeButton; + this.rationaleMsg = rationaleMsg; + this.theme = theme; + this.requestCode = requestCode; + this.permissions = permissions; + } + + RationaleDialogConfig(Bundle bundle) { + positiveButton = bundle.getString(KEY_POSITIVE_BUTTON); + negativeButton = bundle.getString(KEY_NEGATIVE_BUTTON); + rationaleMsg = bundle.getString(KEY_RATIONALE_MESSAGE); + theme = bundle.getInt(KEY_THEME); + requestCode = bundle.getInt(KEY_REQUEST_CODE); + permissions = bundle.getStringArray(KEY_PERMISSIONS); + } + + Bundle toBundle() { + Bundle bundle = new Bundle(); + bundle.putString(KEY_POSITIVE_BUTTON, positiveButton); + bundle.putString(KEY_NEGATIVE_BUTTON, negativeButton); + bundle.putString(KEY_RATIONALE_MESSAGE, rationaleMsg); + bundle.putInt(KEY_THEME, theme); + bundle.putInt(KEY_REQUEST_CODE, requestCode); + bundle.putStringArray(KEY_PERMISSIONS, permissions); + + return bundle; + } + + AlertDialog createSupportDialog(Context context, Dialog.OnClickListener listener) { + AlertDialog.Builder builder; + if (theme > 0) { + builder = new AlertDialog.Builder(context, theme); + } else { + builder = new AlertDialog.Builder(context); + } + return builder + .setCancelable(false) + .setPositiveButton(positiveButton, listener) + .setNegativeButton(negativeButton, listener) + .setMessage(rationaleMsg) + .create(); + } + + android.app.AlertDialog createFrameworkDialog(Context context, Dialog.OnClickListener listener) { + android.app.AlertDialog.Builder builder; + if (theme > 0) { + builder = new android.app.AlertDialog.Builder(context, theme); + } else { + builder = new android.app.AlertDialog.Builder(context); + } + return builder + .setCancelable(false) + .setPositiveButton(positiveButton, listener) + .setNegativeButton(negativeButton, listener) + .setMessage(rationaleMsg) + .create(); + } + +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragment.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragment.java new file mode 100644 index 00000000..c055a4f7 --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragment.java @@ -0,0 +1,113 @@ +package pub.devrel.easypermissions; + +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.FragmentManager; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.RestrictTo; +import androidx.annotation.StyleRes; + +/** + * {@link DialogFragment} to display rationale for permission requests when the request comes from + * a Fragment or Activity that can host a Fragment. + */ +@RestrictTo(RestrictTo.Scope.LIBRARY) +public class RationaleDialogFragment extends DialogFragment { + + public static final String TAG = "RationaleDialogFragment"; + + private EasyPermissions.PermissionCallbacks mPermissionCallbacks; + private EasyPermissions.RationaleCallbacks mRationaleCallbacks; + private boolean mStateSaved = false; + + public static RationaleDialogFragment newInstance( + @NonNull String positiveButton, + @NonNull String negativeButton, + @NonNull String rationaleMsg, + @StyleRes int theme, + int requestCode, + @NonNull String[] permissions) { + + // Create new Fragment + RationaleDialogFragment dialogFragment = new RationaleDialogFragment(); + + // Initialize configuration as arguments + RationaleDialogConfig config = new RationaleDialogConfig( + positiveButton, negativeButton, rationaleMsg, theme, requestCode, permissions); + dialogFragment.setArguments(config.toBundle()); + + return dialogFragment; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && getParentFragment() != null) { + if (getParentFragment() instanceof EasyPermissions.PermissionCallbacks) { + mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) getParentFragment(); + } + if (getParentFragment() instanceof EasyPermissions.RationaleCallbacks){ + mRationaleCallbacks = (EasyPermissions.RationaleCallbacks) getParentFragment(); + } + + } + + if (context instanceof EasyPermissions.PermissionCallbacks) { + mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) context; + } + + if (context instanceof EasyPermissions.RationaleCallbacks) { + mRationaleCallbacks = (EasyPermissions.RationaleCallbacks) context; + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + mStateSaved = true; + super.onSaveInstanceState(outState); + } + + /** + * Version of {@link #show(FragmentManager, String)} that no-ops when an IllegalStateException + * would otherwise occur. + */ + public void showAllowingStateLoss(FragmentManager manager, String tag) { + // API 26 added this convenient method + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (manager.isStateSaved()) { + return; + } + } + + if (mStateSaved) { + return; + } + + show(manager, tag); + } + + @Override + public void onDetach() { + super.onDetach(); + mPermissionCallbacks = null; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // Rationale dialog should not be cancelable + setCancelable(false); + + // Get config from arguments, create click listener + RationaleDialogConfig config = new RationaleDialogConfig(getArguments()); + RationaleDialogClickListener clickListener = + new RationaleDialogClickListener(this, config, mPermissionCallbacks, mRationaleCallbacks); + + // Create an AlertDialog + return config.createFrameworkDialog(getActivity(), clickListener); + } + +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragmentCompat.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragmentCompat.java new file mode 100644 index 00000000..5a9306f4 --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragmentCompat.java @@ -0,0 +1,97 @@ +package pub.devrel.easypermissions; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.RestrictTo; +import androidx.annotation.StyleRes; +import androidx.fragment.app.FragmentManager; +import androidx.appcompat.app.AppCompatDialogFragment; + +/** + * {@link AppCompatDialogFragment} to display rationale for permission requests when the request + * comes from a Fragment or Activity that can host a Fragment. + */ +@RestrictTo(RestrictTo.Scope.LIBRARY) +public class RationaleDialogFragmentCompat extends AppCompatDialogFragment { + + public static final String TAG = "RationaleDialogFragmentCompat"; + + private EasyPermissions.PermissionCallbacks mPermissionCallbacks; + private EasyPermissions.RationaleCallbacks mRationaleCallbacks; + + public static RationaleDialogFragmentCompat newInstance( + @NonNull String rationaleMsg, + @NonNull String positiveButton, + @NonNull String negativeButton, + @StyleRes int theme, + int requestCode, + @NonNull String[] permissions) { + + // Create new Fragment + RationaleDialogFragmentCompat dialogFragment = new RationaleDialogFragmentCompat(); + + // Initialize configuration as arguments + RationaleDialogConfig config = new RationaleDialogConfig( + positiveButton, negativeButton, rationaleMsg, theme, requestCode, permissions); + dialogFragment.setArguments(config.toBundle()); + + return dialogFragment; + } + + /** + * Version of {@link #show(FragmentManager, String)} that no-ops when an IllegalStateException + * would otherwise occur. + */ + public void showAllowingStateLoss(FragmentManager manager, String tag) { + if (manager.isStateSaved()) { + return; + } + + show(manager, tag); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (getParentFragment() != null) { + if (getParentFragment() instanceof EasyPermissions.PermissionCallbacks) { + mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) getParentFragment(); + } + if (getParentFragment() instanceof EasyPermissions.RationaleCallbacks){ + mRationaleCallbacks = (EasyPermissions.RationaleCallbacks) getParentFragment(); + } + } + + if (context instanceof EasyPermissions.PermissionCallbacks) { + mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) context; + } + + if (context instanceof EasyPermissions.RationaleCallbacks) { + mRationaleCallbacks = (EasyPermissions.RationaleCallbacks) context; + } + } + + @Override + public void onDetach() { + super.onDetach(); + mPermissionCallbacks = null; + mRationaleCallbacks = null; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // Rationale dialog should not be cancelable + setCancelable(false); + + // Get config from arguments, create click listener + RationaleDialogConfig config = new RationaleDialogConfig(getArguments()); + RationaleDialogClickListener clickListener = + new RationaleDialogClickListener(this, config, mPermissionCallbacks, mRationaleCallbacks); + + // Create an AlertDialog + return config.createSupportDialog(getContext(), clickListener); + } +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/ActivityPermissionHelper.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/ActivityPermissionHelper.java new file mode 100644 index 00000000..74aa4228 --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/ActivityPermissionHelper.java @@ -0,0 +1,59 @@ +package pub.devrel.easypermissions.helper; + +import android.app.Activity; +import android.app.Fragment; +import android.app.FragmentManager; +import android.content.Context; +import androidx.annotation.NonNull; +import androidx.annotation.StyleRes; +import androidx.core.app.ActivityCompat; +import android.util.Log; + +import pub.devrel.easypermissions.RationaleDialogFragment; + +/** + * Permissions helper for {@link Activity}. + */ +class ActivityPermissionHelper extends PermissionHelper { + private static final String TAG = "ActPermissionHelper"; + + public ActivityPermissionHelper(Activity host) { + super(host); + } + + @Override + public void directRequestPermissions(int requestCode, @NonNull String... perms) { + ActivityCompat.requestPermissions(getHost(), perms, requestCode); + } + + @Override + public boolean shouldShowRequestPermissionRationale(@NonNull String perm) { + return ActivityCompat.shouldShowRequestPermissionRationale(getHost(), perm); + } + + @Override + public Context getContext() { + return getHost(); + } + + @Override + public void showRequestPermissionRationale(@NonNull String rationale, + @NonNull String positiveButton, + @NonNull String negativeButton, + @StyleRes int theme, + int requestCode, + @NonNull String... perms) { + FragmentManager fm = getHost().getFragmentManager(); + + // Check if fragment is already showing + Fragment fragment = fm.findFragmentByTag(RationaleDialogFragment.TAG); + if (fragment instanceof RationaleDialogFragment) { + Log.d(TAG, "Found existing fragment, not showing rationale."); + return; + } + + RationaleDialogFragment + .newInstance(positiveButton, negativeButton, rationale, theme, requestCode, perms) + .showAllowingStateLoss(fm, RationaleDialogFragment.TAG); + } +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/AppCompatActivityPermissionsHelper.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/AppCompatActivityPermissionsHelper.java new file mode 100644 index 00000000..0bc80a59 --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/AppCompatActivityPermissionsHelper.java @@ -0,0 +1,37 @@ +package pub.devrel.easypermissions.helper; + +import android.content.Context; +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.fragment.app.FragmentManager; +import androidx.appcompat.app.AppCompatActivity; + +/** + * Permissions helper for {@link AppCompatActivity}. + */ +class AppCompatActivityPermissionsHelper extends BaseSupportPermissionsHelper { + + public AppCompatActivityPermissionsHelper(AppCompatActivity host) { + super(host); + } + + @Override + public FragmentManager getSupportFragmentManager() { + return getHost().getSupportFragmentManager(); + } + + @Override + public void directRequestPermissions(int requestCode, @NonNull String... perms) { + ActivityCompat.requestPermissions(getHost(), perms, requestCode); + } + + @Override + public boolean shouldShowRequestPermissionRationale(@NonNull String perm) { + return ActivityCompat.shouldShowRequestPermissionRationale(getHost(), perm); + } + + @Override + public Context getContext() { + return getHost(); + } +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/BaseSupportPermissionsHelper.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/BaseSupportPermissionsHelper.java new file mode 100644 index 00000000..185da5a2 --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/BaseSupportPermissionsHelper.java @@ -0,0 +1,45 @@ +package pub.devrel.easypermissions.helper; + +import androidx.annotation.NonNull; +import androidx.annotation.StyleRes; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import android.util.Log; + +import pub.devrel.easypermissions.RationaleDialogFragmentCompat; + +/** + * Implementation of {@link PermissionHelper} for Support Library host classes. + */ +public abstract class BaseSupportPermissionsHelper extends PermissionHelper { + + private static final String TAG = "BSPermissionsHelper"; + + public BaseSupportPermissionsHelper(@NonNull T host) { + super(host); + } + + public abstract FragmentManager getSupportFragmentManager(); + + @Override + public void showRequestPermissionRationale(@NonNull String rationale, + @NonNull String positiveButton, + @NonNull String negativeButton, + @StyleRes int theme, + int requestCode, + @NonNull String... perms) { + + FragmentManager fm = getSupportFragmentManager(); + + // Check if fragment is already showing + Fragment fragment = fm.findFragmentByTag(RationaleDialogFragmentCompat.TAG); + if (fragment instanceof RationaleDialogFragmentCompat) { + Log.d(TAG, "Found existing fragment, not showing rationale."); + return; + } + + RationaleDialogFragmentCompat + .newInstance(rationale, positiveButton, negativeButton, theme, requestCode, perms) + .showAllowingStateLoss(fm, RationaleDialogFragmentCompat.TAG); + } +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/LowApiPermissionsHelper.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/LowApiPermissionsHelper.java new file mode 100644 index 00000000..6ec74376 --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/LowApiPermissionsHelper.java @@ -0,0 +1,47 @@ +package pub.devrel.easypermissions.helper; + +import android.app.Activity; +import android.content.Context; +import androidx.annotation.NonNull; +import androidx.annotation.StyleRes; +import androidx.fragment.app.Fragment; + +/** + * Permissions helper for apps built against API < 23, which do not need runtime permissions. + */ +class LowApiPermissionsHelper extends PermissionHelper { + public LowApiPermissionsHelper(@NonNull T host) { + super(host); + } + + @Override + public void directRequestPermissions(int requestCode, @NonNull String... perms) { + throw new IllegalStateException("Should never be requesting permissions on API < 23!"); + } + + @Override + public boolean shouldShowRequestPermissionRationale(@NonNull String perm) { + return false; + } + + @Override + public void showRequestPermissionRationale(@NonNull String rationale, + @NonNull String positiveButton, + @NonNull String negativeButton, + @StyleRes int theme, + int requestCode, + @NonNull String... perms) { + throw new IllegalStateException("Should never be requesting permissions on API < 23!"); + } + + @Override + public Context getContext() { + if (getHost() instanceof Activity) { + return (Context) getHost(); + } else if (getHost() instanceof Fragment) { + return ((Fragment) getHost()).getContext(); + } else { + throw new IllegalStateException("Unknown host: " + getHost()); + } + } +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/PermissionHelper.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/PermissionHelper.java new file mode 100644 index 00000000..db95a350 --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/PermissionHelper.java @@ -0,0 +1,113 @@ +package pub.devrel.easypermissions.helper; + +import android.app.Activity; +import android.content.Context; +import android.os.Build; +import androidx.annotation.NonNull; +import androidx.annotation.StyleRes; +import androidx.fragment.app.Fragment; +import androidx.appcompat.app.AppCompatActivity; + +import java.util.List; + +/** + * Delegate class to make permission calls based on the 'host' (Fragment, Activity, etc). + */ +public abstract class PermissionHelper { + + private T mHost; + + @NonNull + public static PermissionHelper newInstance(Activity host) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return new LowApiPermissionsHelper<>(host); + } + + if (host instanceof AppCompatActivity) + return new AppCompatActivityPermissionsHelper((AppCompatActivity) host); + else { + return new ActivityPermissionHelper(host); + } + } + + @NonNull + public static PermissionHelper newInstance(Fragment host) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return new LowApiPermissionsHelper<>(host); + } + + return new SupportFragmentPermissionHelper(host); + } + + // ============================================================================ + // Public concrete methods + // ============================================================================ + + public PermissionHelper(@NonNull T host) { + mHost = host; + } + + private boolean shouldShowRationale(@NonNull String... perms) { + for (String perm : perms) { + if (shouldShowRequestPermissionRationale(perm)) { + return true; + } + } + return false; + } + + public void requestPermissions(@NonNull String rationale, + @NonNull String positiveButton, + @NonNull String negativeButton, + @StyleRes int theme, + int requestCode, + @NonNull String... perms) { + if (shouldShowRationale(perms)) { + showRequestPermissionRationale( + rationale, positiveButton, negativeButton, theme, requestCode, perms); + } else { + directRequestPermissions(requestCode, perms); + } + } + + public boolean somePermissionPermanentlyDenied(@NonNull List perms) { + for (String deniedPermission : perms) { + if (permissionPermanentlyDenied(deniedPermission)) { + return true; + } + } + + return false; + } + + public boolean permissionPermanentlyDenied(@NonNull String perms) { + return !shouldShowRequestPermissionRationale(perms); + } + + public boolean somePermissionDenied(@NonNull String... perms) { + return shouldShowRationale(perms); + } + + @NonNull + public T getHost() { + return mHost; + } + + // ============================================================================ + // Public abstract methods + // ============================================================================ + + public abstract void directRequestPermissions(int requestCode, @NonNull String... perms); + + public abstract boolean shouldShowRequestPermissionRationale(@NonNull String perm); + + public abstract void showRequestPermissionRationale(@NonNull String rationale, + @NonNull String positiveButton, + @NonNull String negativeButton, + @StyleRes int theme, + int requestCode, + @NonNull String... perms); + + public abstract Context getContext(); + +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/SupportFragmentPermissionHelper.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/SupportFragmentPermissionHelper.java new file mode 100644 index 00000000..cf72eeb3 --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/SupportFragmentPermissionHelper.java @@ -0,0 +1,36 @@ +package pub.devrel.easypermissions.helper; + +import android.content.Context; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; + +/** + * Permissions helper for {@link Fragment} from the support library. + */ +class SupportFragmentPermissionHelper extends BaseSupportPermissionsHelper { + + public SupportFragmentPermissionHelper(@NonNull Fragment host) { + super(host); + } + + @Override + public FragmentManager getSupportFragmentManager() { + return getHost().getChildFragmentManager(); + } + + @Override + public void directRequestPermissions(int requestCode, @NonNull String... perms) { + getHost().requestPermissions(perms, requestCode); + } + + @Override + public boolean shouldShowRequestPermissionRationale(@NonNull String perm) { + return getHost().shouldShowRequestPermissionRationale(perm); + } + + @Override + public Context getContext() { + return getHost().getActivity(); + } +} diff --git a/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/package-info.java b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/package-info.java new file mode 100644 index 00000000..61617bce --- /dev/null +++ b/android/easypermissions/src/main/java/pub/devrel/easypermissions/helper/package-info.java @@ -0,0 +1,4 @@ +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +package pub.devrel.easypermissions.helper; + +import androidx.annotation.RestrictTo; diff --git a/android/easypermissions/src/main/res/values/colors.xml b/android/easypermissions/src/main/res/values/colors.xml new file mode 100644 index 00000000..2ca30829 --- /dev/null +++ b/android/easypermissions/src/main/res/values/colors.xml @@ -0,0 +1,7 @@ + + + + #ff212121 + @android:color/black + #ff80cbc4 + diff --git a/android/easypermissions/src/main/res/values/strings.xml b/android/easypermissions/src/main/res/values/strings.xml new file mode 100644 index 00000000..2ceab867 --- /dev/null +++ b/android/easypermissions/src/main/res/values/strings.xml @@ -0,0 +1,8 @@ + + This app may not work correctly without the requested permissions. + + This app may not work correctly without the requested permissions. + Open the app settings screen to modify app permissions. + + Permissions Required + diff --git a/android/easypermissions/src/main/res/values/styles.xml b/android/easypermissions/src/main/res/values/styles.xml new file mode 100644 index 00000000..91239929 --- /dev/null +++ b/android/easypermissions/src/main/res/values/styles.xml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/android/easypermissions/src/test/java/pub/devrel/easypermissions/AppSettingsDialogTest.java b/android/easypermissions/src/test/java/pub/devrel/easypermissions/AppSettingsDialogTest.java new file mode 100644 index 00000000..2b353846 --- /dev/null +++ b/android/easypermissions/src/test/java/pub/devrel/easypermissions/AppSettingsDialogTest.java @@ -0,0 +1,186 @@ +package pub.devrel.easypermissions; + +import android.app.Application; +import android.content.DialogInterface; +import android.content.Intent; +import android.widget.Button; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowApplication; +import org.robolectric.shadows.ShadowIntent; + +import java.util.Objects; + +import androidx.appcompat.app.AlertDialog; +import androidx.test.core.app.ApplicationProvider; +import pub.devrel.easypermissions.testhelper.ActivityController; +import pub.devrel.easypermissions.testhelper.FragmentController; +import pub.devrel.easypermissions.testhelper.TestActivity; +import pub.devrel.easypermissions.testhelper.TestFragment; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.robolectric.Shadows.shadowOf; +import static pub.devrel.easypermissions.AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = 23) +public class AppSettingsDialogTest { + + private static final String TITLE = "TITLE"; + private static final String RATIONALE = "RATIONALE"; + private static final String NEGATIVE = "NEGATIVE"; + private static final String POSITIVE = "POSITIVE"; + private ShadowApplication shadowApp; + private TestActivity spyActivity; + private TestFragment spyFragment; + private FragmentController fragmentController; + private ActivityController activityController; + @Mock + private DialogInterface.OnClickListener positiveListener; + @Mock + private DialogInterface.OnClickListener negativeListener; + @Captor + private ArgumentCaptor integerCaptor; + @Captor + private ArgumentCaptor intentCaptor; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + shadowApp = shadowOf((Application) ApplicationProvider.getApplicationContext()); + + activityController = new ActivityController<>(TestActivity.class); + fragmentController = new FragmentController<>(TestFragment.class); + + spyActivity = Mockito.spy(activityController.resume()); + spyFragment = Mockito.spy(fragmentController.resume()); + } + + // ------ From Activity ------ + + @Test + public void shouldShowExpectedSettingsDialog_whenBuildingFromActivity() { + new AppSettingsDialog.Builder(spyActivity) + .setTitle(android.R.string.dialog_alert_title) + .setRationale(android.R.string.unknownName) + .setPositiveButton(android.R.string.ok) + .setNegativeButton(android.R.string.cancel) + .setThemeResId(R.style.Theme_AppCompat) + .build() + .show(); + + verify(spyActivity, times(1)) + .startActivityForResult(intentCaptor.capture(), integerCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(DEFAULT_SETTINGS_REQ_CODE); + assertThat(Objects.requireNonNull(intentCaptor.getValue().getComponent()).getClassName()) + .isEqualTo(AppSettingsDialogHolderActivity.class.getName()); + + Intent startedIntent = shadowApp.getNextStartedActivity(); + ShadowIntent shadowIntent = shadowOf(startedIntent); + assertThat(shadowIntent.getIntentClass()).isEqualTo(AppSettingsDialogHolderActivity.class); + } + + @Test + public void shouldPositiveListener_whenClickingPositiveButtonFromActivity() { + AlertDialog alertDialog = new AppSettingsDialog.Builder(spyActivity) + .setTitle(TITLE) + .setRationale(RATIONALE) + .setPositiveButton(POSITIVE) + .setNegativeButton(NEGATIVE) + .setThemeResId(R.style.Theme_AppCompat) + .build() + .showDialog(positiveListener, negativeListener); + Button positive = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + positive.performClick(); + + verify(positiveListener, times(1)) + .onClick(any(DialogInterface.class), anyInt()); + } + + @Test + public void shouldNegativeListener_whenClickingPositiveButtonFromActivity() { + AlertDialog alertDialog = new AppSettingsDialog.Builder(spyActivity) + .setTitle(TITLE) + .setRationale(RATIONALE) + .setPositiveButton(POSITIVE) + .setNegativeButton(NEGATIVE) + .setThemeResId(R.style.Theme_AppCompat) + .build() + .showDialog(positiveListener, negativeListener); + Button positive = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE); + positive.performClick(); + + verify(negativeListener, times(1)) + .onClick(any(DialogInterface.class), anyInt()); + } + + @Test + public void shouldShowExpectedSettingsDialog_whenBuildingFromSupportFragment() { + new AppSettingsDialog.Builder(spyFragment) + .setTitle(android.R.string.dialog_alert_title) + .setRationale(android.R.string.unknownName) + .setPositiveButton(android.R.string.ok) + .setNegativeButton(android.R.string.cancel) + .setThemeResId(R.style.Theme_AppCompat) + .build() + .show(); + + verify(spyFragment, times(1)) + .startActivityForResult(intentCaptor.capture(), integerCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(DEFAULT_SETTINGS_REQ_CODE); + assertThat(Objects.requireNonNull(intentCaptor.getValue().getComponent()).getClassName()) + .isEqualTo(AppSettingsDialogHolderActivity.class.getName()); + + Intent startedIntent = shadowApp.getNextStartedActivity(); + ShadowIntent shadowIntent = shadowOf(startedIntent); + assertThat(shadowIntent.getIntentClass()).isEqualTo(AppSettingsDialogHolderActivity.class); + } + + @Test + public void shouldPositiveListener_whenClickingPositiveButtonFromSupportFragment() { + AlertDialog alertDialog = new AppSettingsDialog.Builder(spyFragment) + .setTitle(TITLE) + .setRationale(RATIONALE) + .setPositiveButton(POSITIVE) + .setNegativeButton(NEGATIVE) + .setThemeResId(R.style.Theme_AppCompat) + .build() + .showDialog(positiveListener, negativeListener); + Button positive = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + positive.performClick(); + + verify(positiveListener, times(1)) + .onClick(any(DialogInterface.class), anyInt()); + } + + @Test + public void shouldNegativeListener_whenClickingPositiveButtonFromSupportFragment() { + AlertDialog alertDialog = new AppSettingsDialog.Builder(spyFragment) + .setTitle(TITLE) + .setRationale(RATIONALE) + .setPositiveButton(POSITIVE) + .setNegativeButton(NEGATIVE) + .setThemeResId(R.style.Theme_AppCompat) + .build() + .showDialog(positiveListener, negativeListener); + Button positive = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE); + positive.performClick(); + + verify(negativeListener, times(1)) + .onClick(any(DialogInterface.class), anyInt()); + } + +} diff --git a/android/easypermissions/src/test/java/pub/devrel/easypermissions/EasyPermissionsLowApiTest.java b/android/easypermissions/src/test/java/pub/devrel/easypermissions/EasyPermissionsLowApiTest.java new file mode 100644 index 00000000..a6c6976b --- /dev/null +++ b/android/easypermissions/src/test/java/pub/devrel/easypermissions/EasyPermissionsLowApiTest.java @@ -0,0 +1,121 @@ +package pub.devrel.easypermissions; + +import android.Manifest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; + +import androidx.test.core.app.ApplicationProvider; +import pub.devrel.easypermissions.testhelper.ActivityController; +import pub.devrel.easypermissions.testhelper.FragmentController; +import pub.devrel.easypermissions.testhelper.TestActivity; +import pub.devrel.easypermissions.testhelper.TestAppCompatActivity; +import pub.devrel.easypermissions.testhelper.TestFragment; +import pub.devrel.easypermissions.testhelper.TestSupportFragmentActivity; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +/** + * Low-API (SDK = 19) tests for {@link pub.devrel.easypermissions.EasyPermissions}. + */ +@RunWith(RobolectricTestRunner.class) +@Config(sdk = 19) +public class EasyPermissionsLowApiTest { + + private static final String RATIONALE = "RATIONALE"; + private static final String[] ALL_PERMS = new String[]{ + Manifest.permission.READ_SMS, Manifest.permission.ACCESS_FINE_LOCATION}; + + private TestActivity spyActivity; + private TestSupportFragmentActivity spySupportFragmentActivity; + private TestAppCompatActivity spyAppCompatActivity; + private TestFragment spyFragment; + private FragmentController fragmentController; + private ActivityController activityController; + private ActivityController supportFragmentActivityController; + private ActivityController appCompatActivityController; + @Captor + private ArgumentCaptor integerCaptor; + @Captor + private ArgumentCaptor> listCaptor; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + activityController = new ActivityController<>(TestActivity.class); + supportFragmentActivityController = new ActivityController<>(TestSupportFragmentActivity.class); + appCompatActivityController = new ActivityController<>(TestAppCompatActivity.class); + fragmentController = new FragmentController<>(TestFragment.class); + + spyActivity = Mockito.spy(activityController.resume()); + spySupportFragmentActivity = Mockito.spy(supportFragmentActivityController.resume()); + spyAppCompatActivity = Mockito.spy(appCompatActivityController.resume()); + spyFragment = Mockito.spy(fragmentController.resume()); + } + + // ------ General tests ------ + + @Test + public void shouldHavePermission_whenHasPermissionsBeforeMarshmallow() { + assertThat(EasyPermissions.hasPermissions(ApplicationProvider.getApplicationContext(), + Manifest.permission.ACCESS_COARSE_LOCATION)).isTrue(); + } + + // ------ From Activity ------ + + @Test + public void shouldCallbackOnPermissionGranted_whenRequestFromActivity() { + EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS); + + verify(spyActivity, times(1)) + .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(TestActivity.REQUEST_CODE); + assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS); + } + + // ------ From Support Activity ------ + + @Test + public void shouldCallbackOnPermissionGranted_whenRequestFromSupportFragmentActivity() { + EasyPermissions.requestPermissions(spySupportFragmentActivity, RATIONALE, TestSupportFragmentActivity.REQUEST_CODE, ALL_PERMS); + + verify(spySupportFragmentActivity, times(1)) + .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(TestSupportFragmentActivity.REQUEST_CODE); + assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS); + } + + + @Test + public void shouldCallbackOnPermissionGranted_whenRequestFromAppCompatActivity() { + EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS); + + verify(spyAppCompatActivity, times(1)) + .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(TestAppCompatActivity.REQUEST_CODE); + assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS); + } + + @Test + public void shouldCallbackOnPermissionGranted_whenRequestFromFragment() { + EasyPermissions.requestPermissions(spyFragment, RATIONALE, TestFragment.REQUEST_CODE, ALL_PERMS); + + verify(spyFragment, times(1)) + .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(TestFragment.REQUEST_CODE); + assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS); + } + +} diff --git a/android/easypermissions/src/test/java/pub/devrel/easypermissions/EasyPermissionsTest.java b/android/easypermissions/src/test/java/pub/devrel/easypermissions/EasyPermissionsTest.java new file mode 100644 index 00000000..06ce723c --- /dev/null +++ b/android/easypermissions/src/test/java/pub/devrel/easypermissions/EasyPermissionsTest.java @@ -0,0 +1,611 @@ +package pub.devrel.easypermissions; + +import android.Manifest; +import android.app.Application; +import android.app.Dialog; +import android.app.Fragment; +import android.content.pm.PackageManager; +import android.widget.TextView; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowApplication; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; + +import androidx.test.core.app.ApplicationProvider; +import pub.devrel.easypermissions.testhelper.ActivityController; +import pub.devrel.easypermissions.testhelper.FragmentController; +import pub.devrel.easypermissions.testhelper.TestActivity; +import pub.devrel.easypermissions.testhelper.TestAppCompatActivity; +import pub.devrel.easypermissions.testhelper.TestFragment; +import pub.devrel.easypermissions.testhelper.TestSupportFragmentActivity; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; + +/** + * Basic Robolectric tests for {@link pub.devrel.easypermissions.EasyPermissions}. + */ +@RunWith(RobolectricTestRunner.class) +@Config(sdk = 23) +public class EasyPermissionsTest { + + private static final String RATIONALE = "RATIONALE"; + private static final String POSITIVE = "POSITIVE"; + private static final String NEGATIVE = "NEGATIVE"; + private static final String[] ONE_PERM = new String[]{Manifest.permission.READ_SMS}; + private static final String[] ALL_PERMS = new String[]{ + Manifest.permission.READ_SMS, Manifest.permission.ACCESS_FINE_LOCATION}; + private static final int[] SMS_DENIED_RESULT = new int[]{ + PackageManager.PERMISSION_DENIED, PackageManager.PERMISSION_GRANTED}; + + private ShadowApplication shadowApp; + private Application app; + private TestActivity spyActivity; + private TestSupportFragmentActivity spySupportFragmentActivity; + private TestAppCompatActivity spyAppCompatActivity; + private TestFragment spyFragment; + private FragmentController fragmentController; + private ActivityController activityController; + private ActivityController supportFragmentActivityController; + private ActivityController appCompatActivityController; + @Captor + private ArgumentCaptor integerCaptor; + @Captor + private ArgumentCaptor> listCaptor; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + app = ApplicationProvider.getApplicationContext(); + shadowApp = shadowOf(app); + + activityController = new ActivityController<>(TestActivity.class); + supportFragmentActivityController = new ActivityController<>(TestSupportFragmentActivity.class); + appCompatActivityController = new ActivityController<>(TestAppCompatActivity.class); + fragmentController = new FragmentController<>(TestFragment.class); + + spyActivity = Mockito.spy(activityController.resume()); + spySupportFragmentActivity = Mockito.spy(supportFragmentActivityController.resume()); + spyAppCompatActivity = Mockito.spy(appCompatActivityController.resume()); + spyFragment = Mockito.spy(fragmentController.resume()); + } + + // ------ General tests ------ + + @Test + public void shouldNotHavePermissions_whenNoPermissionsGranted() { + assertThat(EasyPermissions.hasPermissions(app, ALL_PERMS)).isFalse(); + } + + @Test + public void shouldNotHavePermissions_whenNotAllPermissionsGranted() { + shadowApp.grantPermissions(ONE_PERM); + assertThat(EasyPermissions.hasPermissions(app, ALL_PERMS)).isFalse(); + } + + @Test + public void shouldHavePermissions_whenAllPermissionsGranted() { + shadowApp.grantPermissions(ALL_PERMS); + assertThat(EasyPermissions.hasPermissions(app, ALL_PERMS)).isTrue(); + } + + @SuppressWarnings("ConstantConditions") + @Test + public void shouldThrowException_whenHasPermissionsWithNullContext() { + try { + EasyPermissions.hasPermissions(null, ALL_PERMS); + fail("IllegalStateException expected because of null context."); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessageThat() + .isEqualTo("Can't check permissions for null context"); + } + } + + // ------ From Activity ------ + + @Test + public void shouldCorrectlyCallback_whenOnRequestPermissionResultCalledFromActivity() { + EasyPermissions.onRequestPermissionsResult(TestActivity.REQUEST_CODE, ALL_PERMS, SMS_DENIED_RESULT, spyActivity); + + verify(spyActivity, times(1)) + .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(TestActivity.REQUEST_CODE); + assertThat(listCaptor.getValue()) + .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.ACCESS_FINE_LOCATION))); + + verify(spyActivity, times(1)) + .onPermissionsDenied(integerCaptor.capture(), listCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(TestActivity.REQUEST_CODE); + assertThat(listCaptor.getValue()) + .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.READ_SMS))); + + verify(spyActivity, never()).afterPermissionGranted(); + } + + @Test + public void shouldCallbackOnPermissionGranted_whenRequestAlreadyGrantedPermissionsFromActivity() { + grantPermissions(ALL_PERMS); + + EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS); + + verify(spyActivity, times(1)) + .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture()); + verify(spyActivity, never()).requestPermissions(any(String[].class), anyInt()); + assertThat(integerCaptor.getValue()).isEqualTo(TestActivity.REQUEST_CODE); + assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS); + } + + @Test + public void shouldCallbackAfterPermissionGranted_whenRequestAlreadyGrantedPermissionsFromActivity() { + grantPermissions(ALL_PERMS); + + EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS); + + // Called 2 times because this is a spy and library implementation invokes super classes annotated methods as well + verify(spyActivity, times(2)).afterPermissionGranted(); + } + + @Test + public void shouldNotCallbackAfterPermissionGranted_whenRequestNotGrantedPermissionsFromActivity() { + grantPermissions(ONE_PERM); + + EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS); + + verify(spyActivity, never()).afterPermissionGranted(); + } + + @Test + public void shouldRequestPermissions_whenMissingPermissionAndNotShowRationaleFromActivity() { + grantPermissions(ONE_PERM); + showRationale(false, ALL_PERMS); + + EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS); + + verify(spyActivity, times(1)) + .requestPermissions(ALL_PERMS, TestActivity.REQUEST_CODE); + } + + @Test + public void shouldShowCorrectDialog_whenMissingPermissionsAndShowRationaleFromActivity() { + grantPermissions(ONE_PERM); + showRationale(true, ALL_PERMS); + + EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS); + + Fragment dialogFragment = spyActivity.getFragmentManager() + .findFragmentByTag(RationaleDialogFragment.TAG); + assertThat(dialogFragment).isInstanceOf(RationaleDialogFragment.class); + + Dialog dialog = ((RationaleDialogFragment) dialogFragment).getDialog(); + assertThatHasExpectedRationale(dialog, RATIONALE); + } + + @Test + public void shouldShowCorrectDialogUsingRequest_whenMissingPermissionsAndShowRationaleFromActivity() { + grantPermissions(ONE_PERM); + showRationale(true, ALL_PERMS); + + PermissionRequest request = new PermissionRequest.Builder(spyActivity, TestActivity.REQUEST_CODE, ALL_PERMS) + .setPositiveButtonText(android.R.string.ok) + .setNegativeButtonText(android.R.string.cancel) + .setRationale(android.R.string.unknownName) + .setTheme(R.style.Theme_AppCompat) + .build(); + EasyPermissions.requestPermissions(request); + + Fragment dialogFragment = spyActivity.getFragmentManager() + .findFragmentByTag(RationaleDialogFragment.TAG); + assertThat(dialogFragment).isInstanceOf(RationaleDialogFragment.class); + + Dialog dialog = ((RationaleDialogFragment) dialogFragment).getDialog(); + assertThatHasExpectedButtonsAndRationale(dialog, android.R.string.unknownName, + android.R.string.ok, android.R.string.cancel); + } + + @Test + public void shouldHaveSomePermissionDenied_whenShowRationaleFromActivity() { + showRationale(true, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionDenied(spyActivity, ALL_PERMS)).isTrue(); + } + + @Test + public void shouldNotHaveSomePermissionDenied_whenNotShowRationaleFromActivity() { + showRationale(false, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionDenied(spyActivity, ALL_PERMS)).isFalse(); + } + + @Test + public void shouldHaveSomePermissionPermanentlyDenied_whenNotShowRationaleFromActivity() { + showRationale(false, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyActivity, Arrays.asList(ALL_PERMS))).isTrue(); + } + + @Test + public void shouldNotHaveSomePermissionPermanentlyDenied_whenShowRationaleFromActivity() { + showRationale(true, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyActivity, Arrays.asList(ALL_PERMS))).isFalse(); + } + + @Test + public void shouldHavePermissionPermanentlyDenied_whenNotShowRationaleFromActivity() { + showRationale(false, Manifest.permission.READ_SMS); + + assertThat(EasyPermissions.permissionPermanentlyDenied(spyActivity, Manifest.permission.READ_SMS)).isTrue(); + } + + @Test + public void shouldNotHavePermissionPermanentlyDenied_whenShowRationaleFromActivity() { + showRationale(true, Manifest.permission.READ_SMS); + + assertThat(EasyPermissions.permissionPermanentlyDenied(spyActivity, Manifest.permission.READ_SMS)).isFalse(); + } + + @Test + public void shouldCorrectlyCallback_whenOnRequestPermissionResultCalledFromAppCompatActivity() { + EasyPermissions.onRequestPermissionsResult(TestAppCompatActivity.REQUEST_CODE, ALL_PERMS, SMS_DENIED_RESULT, spyAppCompatActivity); + + verify(spyAppCompatActivity, times(1)) + .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(TestAppCompatActivity.REQUEST_CODE); + assertThat(listCaptor.getValue()) + .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.ACCESS_FINE_LOCATION))); + + verify(spyAppCompatActivity, times(1)) + .onPermissionsDenied(integerCaptor.capture(), listCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(TestAppCompatActivity.REQUEST_CODE); + assertThat(listCaptor.getValue()) + .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.READ_SMS))); + + verify(spyAppCompatActivity, never()).afterPermissionGranted(); + } + + @Test + public void shouldCallbackOnPermissionGranted_whenRequestAlreadyGrantedPermissionsFromAppCompatActivity() { + grantPermissions(ALL_PERMS); + + EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS); + + verify(spyAppCompatActivity, times(1)) + .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture()); + verify(spyAppCompatActivity, never()).requestPermissions(any(String[].class), anyInt()); + assertThat(integerCaptor.getValue()).isEqualTo(TestAppCompatActivity.REQUEST_CODE); + assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS); + } + + @Test + public void shouldCallbackAfterPermissionGranted_whenRequestAlreadyGrantedPermissionsFromAppCompatActivity() { + grantPermissions(ALL_PERMS); + + EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS); + + // Called 2 times because this is a spy and library implementation invokes super classes annotated methods as well + verify(spyAppCompatActivity, times(2)).afterPermissionGranted(); + } + + @Test + public void shouldNotCallbackAfterPermissionGranted_whenRequestNotGrantedPermissionsFromAppCompatActivity() { + grantPermissions(ONE_PERM); + + EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS); + + verify(spyAppCompatActivity, never()).afterPermissionGranted(); + } + + @Test + public void shouldRequestPermissions_whenMissingPermissionAndNotShowRationaleFromAppCompatActivity() { + grantPermissions(ONE_PERM); + showRationale(false, ALL_PERMS); + + EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS); + + verify(spyAppCompatActivity, times(1)) + .requestPermissions(ALL_PERMS, TestAppCompatActivity.REQUEST_CODE); + } + + @Test + public void shouldShowCorrectDialog_whenMissingPermissionsAndShowRationaleFromAppCompatActivity() { + grantPermissions(ONE_PERM); + showRationale(true, ALL_PERMS); + + EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS); + + androidx.fragment.app.Fragment dialogFragment = spyAppCompatActivity.getSupportFragmentManager() + .findFragmentByTag(RationaleDialogFragmentCompat.TAG); + assertThat(dialogFragment).isInstanceOf(RationaleDialogFragmentCompat.class); + + Dialog dialog = ((RationaleDialogFragmentCompat) dialogFragment).getDialog(); + assertThatHasExpectedRationale(dialog, RATIONALE); + } + + @Test + public void shouldShowCorrectDialog_whenMissingPermissionsAndShowRationaleFromSupportFragmentActivity() { + grantPermissions(ONE_PERM); + showRationale(true, ALL_PERMS); + + EasyPermissions.requestPermissions(spySupportFragmentActivity, RATIONALE, TestSupportFragmentActivity.REQUEST_CODE, ALL_PERMS); + + Fragment dialogFragment = spySupportFragmentActivity.getFragmentManager() + .findFragmentByTag(RationaleDialogFragment.TAG); + assertThat(dialogFragment).isInstanceOf(RationaleDialogFragment.class); + + Dialog dialog = ((RationaleDialogFragment) dialogFragment).getDialog(); + assertThatHasExpectedRationale(dialog, RATIONALE); + } + + @Test + public void shouldShowCorrectDialogUsingRequest_whenMissingPermissionsAndShowRationaleFromAppCompatActivity() { + grantPermissions(ONE_PERM); + showRationale(true, ALL_PERMS); + + PermissionRequest request = new PermissionRequest.Builder(spyAppCompatActivity, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS) + .setPositiveButtonText(android.R.string.ok) + .setNegativeButtonText(android.R.string.cancel) + .setRationale(android.R.string.unknownName) + .setTheme(R.style.Theme_AppCompat) + .build(); + EasyPermissions.requestPermissions(request); + + androidx.fragment.app.Fragment dialogFragment = spyAppCompatActivity.getSupportFragmentManager() + .findFragmentByTag(RationaleDialogFragmentCompat.TAG); + assertThat(dialogFragment).isInstanceOf(RationaleDialogFragmentCompat.class); + + Dialog dialog = ((RationaleDialogFragmentCompat) dialogFragment).getDialog(); + assertThatHasExpectedButtonsAndRationale(dialog, android.R.string.unknownName, + android.R.string.ok, android.R.string.cancel); + } + + @Test + public void shouldHaveSomePermissionDenied_whenShowRationaleFromAppCompatActivity() { + showRationale(true, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionDenied(spyAppCompatActivity, ALL_PERMS)).isTrue(); + } + + @Test + public void shouldNotHaveSomePermissionDenied_whenNotShowRationaleFromAppCompatActivity() { + showRationale(false, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionDenied(spyAppCompatActivity, ALL_PERMS)).isFalse(); + } + + @Test + public void shouldHaveSomePermissionPermanentlyDenied_whenNotShowRationaleFromAppCompatActivity() { + showRationale(false, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyAppCompatActivity, Arrays.asList(ALL_PERMS))).isTrue(); + } + + @Test + public void shouldNotHaveSomePermissionPermanentlyDenied_whenShowRationaleFromAppCompatActivity() { + showRationale(true, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyAppCompatActivity, Arrays.asList(ALL_PERMS))).isFalse(); + } + + @Test + public void shouldHavePermissionPermanentlyDenied_whenNotShowRationaleFromAppCompatActivity() { + showRationale(false, Manifest.permission.READ_SMS); + + assertThat(EasyPermissions.permissionPermanentlyDenied(spyAppCompatActivity, Manifest.permission.READ_SMS)).isTrue(); + } + + @Test + public void shouldNotHavePermissionPermanentlyDenied_whenShowRationaleFromAppCompatActivity() { + showRationale(true, Manifest.permission.READ_SMS); + + assertThat(EasyPermissions.permissionPermanentlyDenied(spyAppCompatActivity, Manifest.permission.READ_SMS)).isFalse(); + } + + @Test + public void shouldCorrectlyCallback_whenOnRequestPermissionResultCalledFromFragment() { + EasyPermissions.onRequestPermissionsResult(TestFragment.REQUEST_CODE, ALL_PERMS, SMS_DENIED_RESULT, + spyFragment); + + verify(spyFragment, times(1)) + .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(TestFragment.REQUEST_CODE); + assertThat(listCaptor.getValue()) + .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.ACCESS_FINE_LOCATION))); + + verify(spyFragment, times(1)) + .onPermissionsDenied(integerCaptor.capture(), listCaptor.capture()); + assertThat(integerCaptor.getValue()).isEqualTo(TestFragment.REQUEST_CODE); + assertThat(listCaptor.getValue()) + .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.READ_SMS))); + + verify(spyFragment, never()).afterPermissionGranted(); + } + + @Test + public void shouldCallbackOnPermissionGranted_whenRequestAlreadyGrantedPermissionsFromFragment() { + grantPermissions(ALL_PERMS); + + EasyPermissions.requestPermissions(spyFragment, RATIONALE, + TestFragment.REQUEST_CODE, ALL_PERMS); + + verify(spyFragment, times(1)) + .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture()); + verify(spyFragment, never()).requestPermissions(any(String[].class), anyInt()); + assertThat(integerCaptor.getValue()).isEqualTo(TestFragment.REQUEST_CODE); + assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS); + } + + @Test + public void shouldCallbackAfterPermissionGranted_whenRequestAlreadyGrantedPermissionsFragment() { + grantPermissions(ALL_PERMS); + + EasyPermissions.requestPermissions(spyFragment, RATIONALE, TestFragment.REQUEST_CODE, ALL_PERMS); + + // Called 2 times because this is a spy and library implementation invokes super classes annotated methods as well + verify(spyFragment, times(2)).afterPermissionGranted(); + } + + @Test + public void shouldNotCallbackAfterPermissionGranted_whenRequestNotGrantedPermissionsFromFragment() { + grantPermissions(ONE_PERM); + + EasyPermissions.requestPermissions(spyFragment, RATIONALE, TestFragment.REQUEST_CODE, ALL_PERMS); + + verify(spyFragment, never()).afterPermissionGranted(); + } + + @Test + public void shouldRequestPermissions_whenMissingPermissionsAndNotShowRationaleFromFragment() { + grantPermissions(ONE_PERM); + showRationale(false, ALL_PERMS); + + EasyPermissions.requestPermissions(spyFragment, RATIONALE, TestFragment.REQUEST_CODE, ALL_PERMS); + + verify(spyFragment, times(1)) + .requestPermissions(ALL_PERMS, TestFragment.REQUEST_CODE); + } + + @Test + public void shouldShowCorrectDialog_whenMissingPermissionsAndShowRationaleFromFragment() { + grantPermissions(ONE_PERM); + showRationale(true, ALL_PERMS); + + EasyPermissions.requestPermissions(spyFragment, RATIONALE, TestFragment.REQUEST_CODE, ALL_PERMS); + + androidx.fragment.app.Fragment dialogFragment = spyFragment.getChildFragmentManager() + .findFragmentByTag(RationaleDialogFragmentCompat.TAG); + assertThat(dialogFragment).isInstanceOf(RationaleDialogFragmentCompat.class); + + Dialog dialog = ((RationaleDialogFragmentCompat) dialogFragment).getDialog(); + assertThatHasExpectedRationale(dialog, RATIONALE); + } + + @Test + public void shouldShowCorrectDialogUsingRequest_whenMissingPermissionsAndShowRationaleFromFragment() { + grantPermissions(ONE_PERM); + showRationale(true, ALL_PERMS); + + PermissionRequest request = new PermissionRequest.Builder(spyFragment, TestFragment.REQUEST_CODE, ALL_PERMS) + .setPositiveButtonText(POSITIVE) + .setNegativeButtonText(NEGATIVE) + .setRationale(RATIONALE) + .setTheme(R.style.Theme_AppCompat) + .build(); + EasyPermissions.requestPermissions(request); + + androidx.fragment.app.Fragment dialogFragment = spyFragment.getChildFragmentManager() + .findFragmentByTag(RationaleDialogFragmentCompat.TAG); + assertThat(dialogFragment).isInstanceOf(RationaleDialogFragmentCompat.class); + + Dialog dialog = ((RationaleDialogFragmentCompat) dialogFragment).getDialog(); + assertThatHasExpectedButtonsAndRationale(dialog, RATIONALE, POSITIVE, NEGATIVE); + } + + @Test + public void shouldHaveSomePermissionDenied_whenShowRationaleFromFragment() { + showRationale(true, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionDenied(spyFragment, ALL_PERMS)).isTrue(); + } + + @Test + public void shouldNotHaveSomePermissionDenied_whenNotShowRationaleFromFragment() { + showRationale(false, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionDenied(spyFragment, ALL_PERMS)).isFalse(); + } + + @Test + public void shouldHaveSomePermissionPermanentlyDenied_whenNotShowRationaleFromFragment() { + showRationale(false, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyFragment, Arrays.asList(ALL_PERMS))).isTrue(); + } + + @Test + public void shouldNotHaveSomePermissionPermanentlyDenied_whenShowRationaleFromFragment() { + showRationale(true, ALL_PERMS); + + assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyFragment, Arrays.asList(ALL_PERMS))).isFalse(); + } + + + @Test + public void shouldHavePermissionPermanentlyDenied_whenNotShowRationaleFromFragment() { + showRationale(false, Manifest.permission.READ_SMS); + + assertThat(EasyPermissions.permissionPermanentlyDenied(spyFragment, Manifest.permission.READ_SMS)).isTrue(); + } + + @Test + public void shouldNotHavePermissionPermanentlyDenied_whenShowRationaleFromFragment() { + showRationale(true, Manifest.permission.READ_SMS); + + assertThat(EasyPermissions.permissionPermanentlyDenied(spyFragment, Manifest.permission.READ_SMS)).isFalse(); + } + + private void assertThatHasExpectedButtonsAndRationale(Dialog dialog, int rationale, + int positive, int negative) { + TextView dialogMessage = dialog.findViewById(android.R.id.message); + assertThat(dialogMessage.getText().toString()).isEqualTo(app.getString(rationale)); + TextView positiveMessage = dialog.findViewById(android.R.id.button1); + assertThat(positiveMessage.getText().toString()).isEqualTo(app.getString(positive)); + TextView negativeMessage = dialog.findViewById(android.R.id.button2); + assertThat(negativeMessage.getText().toString()).isEqualTo(app.getString(negative)); + } + + private void assertThatHasExpectedButtonsAndRationale(Dialog dialog, String rationale, + int positive, int negative) { + TextView dialogMessage = dialog.findViewById(android.R.id.message); + assertThat(dialogMessage.getText().toString()).isEqualTo(rationale); + TextView positiveMessage = dialog.findViewById(android.R.id.button1); + assertThat(positiveMessage.getText().toString()).isEqualTo(app.getString(positive)); + TextView negativeMessage = dialog.findViewById(android.R.id.button2); + assertThat(negativeMessage.getText().toString()).isEqualTo(app.getString(negative)); + } + + private void assertThatHasExpectedButtonsAndRationale(Dialog dialog, String rationale, + String positive, String negative) { + TextView dialogMessage = dialog.findViewById(android.R.id.message); + assertThat(dialogMessage.getText().toString()).isEqualTo(rationale); + TextView positiveMessage = dialog.findViewById(android.R.id.button1); + assertThat(positiveMessage.getText().toString()).isEqualTo(positive); + TextView negativeMessage = dialog.findViewById(android.R.id.button2); + assertThat(negativeMessage.getText().toString()).isEqualTo(negative); + } + + private void assertThatHasExpectedRationale(Dialog dialog, String rationale) { + TextView dialogMessage = dialog.findViewById(android.R.id.message); + assertThat(dialogMessage.getText().toString()).isEqualTo(rationale); + } + + private void grantPermissions(String[] perms) { + shadowApp.grantPermissions(perms); + } + + private void showRationale(boolean show, String... perms) { + for (String perm : perms) { + when(spyActivity.shouldShowRequestPermissionRationale(perm)).thenReturn(show); + when(spySupportFragmentActivity.shouldShowRequestPermissionRationale(perm)).thenReturn(show); + when(spyAppCompatActivity.shouldShowRequestPermissionRationale(perm)).thenReturn(show); + when(spyFragment.shouldShowRequestPermissionRationale(perm)).thenReturn(show); + } + } +} diff --git a/android/easypermissions/src/test/java/pub/devrel/easypermissions/RationaleDialogClickListenerTest.java b/android/easypermissions/src/test/java/pub/devrel/easypermissions/RationaleDialogClickListenerTest.java new file mode 100644 index 00000000..c05f99b1 --- /dev/null +++ b/android/easypermissions/src/test/java/pub/devrel/easypermissions/RationaleDialogClickListenerTest.java @@ -0,0 +1,134 @@ +package pub.devrel.easypermissions; + +import android.Manifest; +import android.app.Activity; +import android.app.Dialog; +import android.content.DialogInterface; + +import androidx.fragment.app.Fragment; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.Arrays; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = 23) +public class RationaleDialogClickListenerTest { + + private static final int REQUEST_CODE = 5; + private static final String[] PERMS = new String[]{ + Manifest.permission.READ_SMS, Manifest.permission.ACCESS_FINE_LOCATION}; + @Mock + private RationaleDialogFragment dialogFragment; + @Mock + private RationaleDialogFragmentCompat dialogFragmentCompat; + @Mock + private RationaleDialogConfig dialogConfig; + @Mock + private EasyPermissions.PermissionCallbacks permissionCallbacks; + @Mock + private EasyPermissions.RationaleCallbacks rationaleCallbacks; + @Mock + private DialogInterface dialogInterface; + @Mock + private Activity activity; + @Mock + private Fragment fragment; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(dialogFragment.getActivity()).thenReturn(activity); + dialogConfig.requestCode = REQUEST_CODE; + dialogConfig.permissions = PERMS; + } + + @Test + public void shouldOnRationaleAccepted_whenPositiveButtonWithRationaleCallbacks() { + RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig, + permissionCallbacks, rationaleCallbacks); + listener.onClick(dialogInterface, Dialog.BUTTON_POSITIVE); + + verify(rationaleCallbacks, times(1)).onRationaleAccepted(REQUEST_CODE); + } + + @Test + public void shouldNotOnRationaleAccepted_whenPositiveButtonWithoutRationaleCallbacks() { + RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig, + permissionCallbacks, null); + listener.onClick(dialogInterface, Dialog.BUTTON_POSITIVE); + + verify(rationaleCallbacks, never()).onRationaleAccepted(anyInt()); + } + + @Test + public void shouldRequestPermissions_whenPositiveButtonFromActivity() { + RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig, + permissionCallbacks, rationaleCallbacks); + listener.onClick(dialogInterface, Dialog.BUTTON_POSITIVE); + + verify(activity, times(1)).requestPermissions(PERMS, REQUEST_CODE); + } + + @Test + public void shouldRequestPermissions_whenPositiveButtonFromFragment() { + when(dialogFragmentCompat.getParentFragment()).thenReturn(fragment); + + RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragmentCompat, dialogConfig, + permissionCallbacks, rationaleCallbacks); + listener.onClick(dialogInterface, Dialog.BUTTON_POSITIVE); + + verify(fragment, times(1)).requestPermissions(PERMS, REQUEST_CODE); + } + + @Test + public void shouldOnRationaleDenied_whenNegativeButtonWithRationaleCallbacks() { + RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig, + permissionCallbacks, rationaleCallbacks); + listener.onClick(dialogInterface, Dialog.BUTTON_NEGATIVE); + + verify(rationaleCallbacks, times(1)).onRationaleDenied(REQUEST_CODE); + } + + @Test + public void shouldNotOnRationaleDenied_whenNegativeButtonWithoutRationaleCallbacks() { + RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig, + permissionCallbacks, null); + listener.onClick(dialogInterface, Dialog.BUTTON_NEGATIVE); + + verify(rationaleCallbacks, never()).onRationaleDenied(anyInt()); + } + + @Test + public void shouldOnPermissionsDenied_whenNegativeButtonWithPermissionCallbacks() { + RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig, + permissionCallbacks, rationaleCallbacks); + listener.onClick(dialogInterface, Dialog.BUTTON_NEGATIVE); + + verify(permissionCallbacks, times(1)) + .onPermissionsDenied(REQUEST_CODE, Arrays.asList(PERMS)); + } + + @Test + public void shouldNotOnPermissionsDenied_whenNegativeButtonWithoutPermissionCallbacks() { + RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig, + null, rationaleCallbacks); + listener.onClick(dialogInterface, Dialog.BUTTON_NEGATIVE); + + verify(permissionCallbacks, never()).onPermissionsDenied(anyInt(), ArgumentMatchers.anyList()); + } +} diff --git a/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/ActivityController.java b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/ActivityController.java new file mode 100644 index 00000000..fc44a2ec --- /dev/null +++ b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/ActivityController.java @@ -0,0 +1,45 @@ +package pub.devrel.easypermissions.testhelper; + +import android.app.Activity; + +import androidx.annotation.NonNull; +import androidx.test.core.app.ActivityScenario; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * Helper class to allow starting Activity, similar to the Robolectric ActivityConroller. + */ +public class ActivityController { + + private ActivityScenario scenario; + + public ActivityController(Class clazz) { + scenario = ActivityScenario.launch(clazz); + } + + public synchronized T resume() { + final CompletableFuture ActivityFuture = new CompletableFuture<>(); + + scenario.onActivity(new ActivityScenario.ActivityAction() { + @Override + public void perform(@NonNull T activity) { + ActivityFuture.complete(activity); + } + }); + + try { + return ActivityFuture.get(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } + } + + public void reset() { + scenario.recreate(); + } + +} diff --git a/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/FragmentController.java b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/FragmentController.java new file mode 100644 index 00000000..60447a65 --- /dev/null +++ b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/FragmentController.java @@ -0,0 +1,44 @@ +package pub.devrel.easypermissions.testhelper; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.testing.FragmentScenario; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * Helper class to allow starting Fragments, similar to the old SupportFragmentController. + */ +public class FragmentController { + + private FragmentScenario scenario; + + public FragmentController(Class clazz) { + scenario = FragmentScenario.launch(clazz); + } + + public synchronized T resume() { + final CompletableFuture fragmentFuture = new CompletableFuture<>(); + + scenario.onFragment(new FragmentScenario.FragmentAction() { + @Override + public void perform(@NonNull T fragment) { + fragmentFuture.complete(fragment); + } + }); + + try { + return fragmentFuture.get(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } + } + + public void reset() { + scenario.recreate(); + } + +} diff --git a/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestActivity.java b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestActivity.java new file mode 100644 index 00000000..cc1b14c0 --- /dev/null +++ b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestActivity.java @@ -0,0 +1,40 @@ +package pub.devrel.easypermissions.testhelper; + +import android.app.Activity; + +import java.util.List; + +import androidx.annotation.NonNull; +import pub.devrel.easypermissions.AfterPermissionGranted; +import pub.devrel.easypermissions.EasyPermissions; + +public class TestActivity extends Activity + implements EasyPermissions.PermissionCallbacks, EasyPermissions.RationaleCallbacks { + + public static final int REQUEST_CODE = 1; + + @Override + public void onPermissionsGranted(int requestCode, @NonNull List perms) { + + } + + @Override + public void onPermissionsDenied(int requestCode, @NonNull List perms) { + + } + + @AfterPermissionGranted(REQUEST_CODE) + public void afterPermissionGranted() { + + } + + @Override + public void onRationaleAccepted(int requestCode) { + + } + + @Override + public void onRationaleDenied(int requestCode) { + + } +} diff --git a/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestAppCompatActivity.java b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestAppCompatActivity.java new file mode 100644 index 00000000..3ca8accc --- /dev/null +++ b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestAppCompatActivity.java @@ -0,0 +1,50 @@ +package pub.devrel.easypermissions.testhelper; + +import android.os.Bundle; + +import java.util.List; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import pub.devrel.easypermissions.AfterPermissionGranted; +import pub.devrel.easypermissions.EasyPermissions; +import pub.devrel.easypermissions.R; + +public class TestAppCompatActivity extends AppCompatActivity + implements EasyPermissions.PermissionCallbacks, EasyPermissions.RationaleCallbacks { + + public static final int REQUEST_CODE = 3; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + getTheme().applyStyle(R.style.Theme_AppCompat, true); + super.onCreate(savedInstanceState); + } + + @Override + public void onPermissionsGranted(int requestCode, @NonNull List perms) { + + } + + @Override + public void onPermissionsDenied(int requestCode, @NonNull List perms) { + + } + + @AfterPermissionGranted(REQUEST_CODE) + public void afterPermissionGranted() { + + } + + @Override + public void onRationaleAccepted(int requestCode) { + + } + + @Override + public void onRationaleDenied(int requestCode) { + + } + +} diff --git a/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestFragment.java b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestFragment.java new file mode 100644 index 00000000..96dbbcbe --- /dev/null +++ b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestFragment.java @@ -0,0 +1,55 @@ +package pub.devrel.easypermissions.testhelper; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.util.List; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import pub.devrel.easypermissions.AfterPermissionGranted; +import pub.devrel.easypermissions.EasyPermissions; +import pub.devrel.easypermissions.R; + +public class TestFragment extends Fragment + implements EasyPermissions.PermissionCallbacks, EasyPermissions.RationaleCallbacks { + + public static final int REQUEST_CODE = 4; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + getContext().getTheme().applyStyle(R.style.Theme_AppCompat, true); + return super.onCreateView(inflater, container, savedInstanceState); + } + + @Override + public void onPermissionsGranted(int requestCode, @NonNull List perms) { + + } + + @Override + public void onPermissionsDenied(int requestCode, @NonNull List perms) { + + } + + @AfterPermissionGranted(REQUEST_CODE) + public void afterPermissionGranted() { + + } + + @Override + public void onRationaleAccepted(int requestCode) { + + } + + @Override + public void onRationaleDenied(int requestCode) { + + } +} diff --git a/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestSupportFragmentActivity.java b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestSupportFragmentActivity.java new file mode 100644 index 00000000..83187e00 --- /dev/null +++ b/android/easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestSupportFragmentActivity.java @@ -0,0 +1,47 @@ +package pub.devrel.easypermissions.testhelper; + +import android.os.Bundle; + +import java.util.List; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentActivity; +import pub.devrel.easypermissions.AfterPermissionGranted; +import pub.devrel.easypermissions.EasyPermissions; + +public class TestSupportFragmentActivity extends FragmentActivity + implements EasyPermissions.PermissionCallbacks, EasyPermissions.RationaleCallbacks { + + public static final int REQUEST_CODE = 5; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public void onPermissionsGranted(int requestCode, @NonNull List perms) { + + } + + @Override + public void onPermissionsDenied(int requestCode, @NonNull List perms) { + + } + + @AfterPermissionGranted(REQUEST_CODE) + public void afterPermissionGranted() { + + } + + @Override + public void onRationaleAccepted(int requestCode) { + + } + + @Override + public void onRationaleDenied(int requestCode) { + + } +} diff --git a/android/settings.gradle b/android/settings.gradle index 5a2f14fb..90238d2f 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,4 +1,4 @@ -include ':app' +include ':app', ':easypermissions' def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() diff --git a/assets/images/svgs/add-square.svg b/assets/images/svgs/add-square.svg new file mode 100644 index 00000000..6c6363f5 --- /dev/null +++ b/assets/images/svgs/add-square.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/svgs/audit.svg b/assets/images/svgs/audit.svg new file mode 100644 index 00000000..7d46a569 --- /dev/null +++ b/assets/images/svgs/audit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/svgs/delete.svg b/assets/images/svgs/delete.svg new file mode 100644 index 00000000..7cdd0f32 --- /dev/null +++ b/assets/images/svgs/delete.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/svgs/edit-icon.svg b/assets/images/svgs/edit-icon.svg new file mode 100644 index 00000000..8fdc3cba --- /dev/null +++ b/assets/images/svgs/edit-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/svgs/edit.svg b/assets/images/svgs/edit.svg new file mode 100644 index 00000000..586202aa --- /dev/null +++ b/assets/images/svgs/edit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/svgs/favorite.svg b/assets/images/svgs/favorite.svg new file mode 100644 index 00000000..c9ff828d --- /dev/null +++ b/assets/images/svgs/favorite.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svgs/favoriteadded.svg b/assets/images/svgs/favoriteadded.svg new file mode 100644 index 00000000..3b4577cf --- /dev/null +++ b/assets/images/svgs/favoriteadded.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svgs/information.svg b/assets/images/svgs/information.svg new file mode 100644 index 00000000..5ec862f2 --- /dev/null +++ b/assets/images/svgs/information.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/svgs/resolve.svg b/assets/images/svgs/resolve.svg new file mode 100644 index 00000000..51d064f3 --- /dev/null +++ b/assets/images/svgs/resolve.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/svgs/save_as_draft.svg b/assets/images/svgs/save_as_draft.svg new file mode 100644 index 00000000..a06e6b69 --- /dev/null +++ b/assets/images/svgs/save_as_draft.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/images/svgs/unavailable.svg b/assets/images/svgs/unavailable.svg new file mode 100644 index 00000000..7e692d97 --- /dev/null +++ b/assets/images/svgs/unavailable.svg @@ -0,0 +1,3 @@ + + + diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index f27854e0..f10a0117 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -196,7 +196,11 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, C21500C474806845DCE7C12A /* [CP] Embed Pods Frameworks */, +<<<<<<< HEAD 2F366CF6754687244D8F7616 /* [CP] Copy Pods Resources */, +======= + 294E280337160E3088FD37C0 /* [CP] Copy Pods Resources */, +>>>>>>> b8ae0cf7d0bab766e883756683c22cb5e7a6d396 ); buildRules = ( ); @@ -213,7 +217,8 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1500; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -257,7 +262,11 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ +<<<<<<< HEAD 2F366CF6754687244D8F7616 /* [CP] Copy Pods Resources */ = { +======= + 294E280337160E3088FD37C0 /* [CP] Copy Pods Resources */ = { +>>>>>>> b8ae0cf7d0bab766e883756683c22cb5e7a6d396 isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -484,6 +493,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -494,6 +504,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -502,7 +513,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -568,6 +579,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -578,6 +590,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -592,7 +605,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -624,6 +637,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -634,6 +648,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -642,10 +657,11 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; @@ -658,8 +674,46 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; +<<<<<<< HEAD CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = 1; +======= + CURRENT_PROJECT_VERSION = 4; + DEVELOPMENT_TEAM = 3A359E86ZF; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + MARKETING_VERSION = 1.3.99; + PRODUCT_BUNDLE_IDENTIFIER = com.hmg.hmgDr; + PRODUCT_NAME = Runner; + 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 = C8801C5E6B82B6CB497CA5C7 /* Pods-Runner.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements; + CURRENT_PROJECT_VERSION = 4; +>>>>>>> b8ae0cf7d0bab766e883756683c22cb5e7a6d396 DEVELOPMENT_TEAM = 3A359E86ZF; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( 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 00000000..f9b0d7c5 --- /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 index 4ba725f4..0b02bfc6 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + + + + PreviewsEnabled + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 8ebd4235..34cf8386 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -4,7 +4,7 @@ import OpenTok // Created by Mohammad Aljammal & Elham Rababah on 24/06/20. // Copyright © 2020 Cloud. All rights reserved. -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate ,ICallProtocol { var result: FlutterResult? diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/RunnerTests/RunnerTests.swift b/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/lib/client/base_app_client.dart b/lib/client/base_app_client.dart index 7c06836d..5747ccb4 100644 --- a/lib/client/base_app_client.dart +++ b/lib/client/base_app_client.dart @@ -8,6 +8,8 @@ import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; import 'package:doctor_app_flutter/core/service/NavigationService.dart'; import 'package:doctor_app_flutter/core/viewModel/authentication_view_model.dart'; import 'package:doctor_app_flutter/utils/dr_app_shared_pref.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/exception_report.dart'; import 'package:doctor_app_flutter/utils/utils.dart'; import 'package:flutter/cupertino.dart'; import 'package:http/http.dart' as http; @@ -23,11 +25,11 @@ class BaseAppClient { //TODO change the post fun to nun static when you change all service post(String endPoint, {Map? body, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - bool isAllowAny = false, - bool isLiveCare = false, - bool isFallLanguage = false}) async { + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + bool isAllowAny = false, + bool isLiveCare = false, + bool isFallLanguage = false}) async { String url; if (isLiveCare) url = BASE_URL_LIVE_CARE + endPoint; @@ -44,7 +46,9 @@ class BaseAppClient { if (body == null || body['DoctorID'] == null) { body!['DoctorID'] = doctorProfile.doctorID; } - if (body['DoctorID'] == "") body['DoctorID'] = null; + if (body['DoctorID'] == "") + body['DoctorID'] = doctorProfile + .doctorID; // changed from null; because create update episode not working if (body['EditedBy'] == null) body['EditedBy'] = doctorProfile.doctorID; if (body['ProjectID'] == null) { body['ProjectID'] = doctorProfile.projectID; @@ -60,8 +64,8 @@ class BaseAppClient { body['SetupID'] = body.containsKey('SetupID') ? body['SetupID'] != null - ? body['SetupID'] - : await sharedPref.getString(DOCTOR_SETUP_ID) + ? body['SetupID'] + : await sharedPref.getString(DOCTOR_SETUP_ID) : await sharedPref.getString(DOCTOR_SETUP_ID); if (body['EditedBy'] == '') { @@ -90,16 +94,21 @@ class BaseAppClient { body['IsLoginForDoctorApp'] = IS_LOGIN_FOR_DOCTOR_APP; body['PatientOutSA'] = body['PatientOutSA'] ?? 0; // PATIENT_OUT_SA; if (body['VidaAuthTokenID'] == null) { - body['VidaAuthTokenID'] = await sharedPref.getString(VIDA_AUTH_TOKEN_ID); + body['VidaAuthTokenID'] = + await sharedPref.getString(VIDA_AUTH_TOKEN_ID); } if (body['VidaRefreshTokenID'] == null) { - body['VidaRefreshTokenID'] = await sharedPref.getString(VIDA_REFRESH_TOKEN_ID); + body['VidaRefreshTokenID'] = + await sharedPref.getString(VIDA_REFRESH_TOKEN_ID); } int? projectID = await sharedPref.getInt(PROJECT_ID); if (projectID == 2 || projectID == 3) body['PatientOutSA'] = true; - else if ((body.containsKey('facilityId') && body['facilityId'] == 2 || body['facilityId'] == 3) || body['ProjectID'] == 2 || body['ProjectID'] == 3) + else if ((body.containsKey('facilityId') && body['facilityId'] == 2 || + body['facilityId'] == 3) || + body['ProjectID'] == 2 || + body['ProjectID'] == 3) body['PatientOutSA'] = true; else body['PatientOutSA'] = false; @@ -126,26 +135,48 @@ class BaseAppClient { var asd = json.encode(body); var asd2; if (await Utils.checkConnection()) { - final response = await http.post(Uri.parse(url), body: json.encode(body), headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}); + final response = await http.post(Uri.parse(url), + body: json.encode(body), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }); final int statusCode = response.statusCode; if (statusCode < 200 || statusCode >= 400) { onFailure(Utils.generateContactAdminMsg(), statusCode); + if (body['DoctorID'] != null) + postFailureResponse( + doctorId: body['DoctorID'], + url: url, + request: json.encode(body), + response: response.body, + exception: "$statusCode"); } else { var parsed = json.decode(response.body.toString()); if (parsed['ErrorType'] == 4) { - helpers.navigateToUpdatePage(parsed['ErrorEndUserMessage'], parsed['AndroidLink'], parsed['IOSLink']); + helpers.navigateToUpdatePage(parsed['ErrorEndUserMessage'], + parsed['AndroidLink'], parsed['IOSLink']); } if (parsed['IsAuthenticated'] != null && !parsed['IsAuthenticated']) { if (body['OTP_SendType'] != null) { - if(parsed['ErrorCode'] =='699'){ - onSuccess(parsed, statusCode); - }else { - onFailure(getError(parsed), statusCode); - } + if (parsed['ErrorCode'] == '699') { + onSuccess(parsed, statusCode); + } else { + if (body['DoctorID'] != null) + postFailureResponse( + doctorId: body['DoctorID'], + url: url, + request: json.encode(body), + response: response.body, + exception: getError(parsed)); + onFailure(getError(parsed), statusCode); + } } else if (!isAllowAny) { - await Provider.of(AppGlobal.CONTEX, listen: false).logout(); - + await Provider.of(AppGlobal.CONTEX, + listen: false) + .logout(); + //todo nofailure is placed here and but have to handle the response here as well Utils.showErrorToast('Your session expired Please login again'); locator().pushNamedAndRemoveUntil(ROOT); } @@ -153,15 +184,39 @@ class BaseAppClient { onFailure(getError(parsed), statusCode); } } else if (parsed['MessageStatus'] == 1) { - if (!parsed['IsAuthenticated']) + if (!parsed['IsAuthenticated']) { + if (body['DoctorID'] != null) + postFailureResponse( + doctorId: body['DoctorID'], + url: url, + request: json.encode(body), + response: response.body, + exception: getError(parsed)); onFailure(getError(parsed), statusCode); - else + } else onSuccess(parsed, statusCode); } else { - onFailure(getError(parsed), statusCode); + final validations = parsed['ValidationErrorsCSI']?['errors']?['Validations']; + + if (validations is List && validations.isNotEmpty) { + final error = validations.first['Error']; + if (error != null) { + onFailure(error, statusCode); + return; + } + } + if (body['DoctorID'] != null) { + postFailureResponse( + doctorId: body['DoctorID'], + url: url, + request: json.encode(body), + response: response.body, + exception: getError(parsed)); + } + onFailure(getError(parsed), statusCode); + } } - } - } else { + } else { onFailure('Please Check The Internet Connection', -1); } } catch (e) { @@ -170,187 +225,264 @@ class BaseAppClient { } } - postPatient(String endPoint, - {Map? body, - required Function(dynamic response, int statusCode) onSuccess, - required Function(String error, int statusCode) onFailure, - PatiantInformtion? patient, - bool isExternal = false}) async { + postPatient(String endPoint, + {Map? body, + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure, + PatiantInformtion? patient, + bool isExternal = false}) async { String url = BASE_URL + endPoint; try { - Map headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}; - - String? token = await sharedPref.getString(TOKEN); - Map? profile = await sharedPref.getObj(DOCTOR_PROFILE); - - if (profile != null) { - DoctorProfileModel doctorProfile = DoctorProfileModel.fromJson(profile); - if (body!['DoctorID'] == null) { - body['DoctorID'] = doctorProfile.doctorID; - } - } - if (body!['DoctorID'] == 0) { - body['DoctorID'] = null; - } - var languageID = await sharedPref.getStringWithDefaultValue(APP_Language, 'en'); - body['SetupID'] = body!.containsKey('SetupID') - ? body['SetupID'] != null - ? body['SetupID'] - : await sharedPref.getString(DOCTOR_SETUP_ID) - : await sharedPref.getString(DOCTOR_SETUP_ID); - - body['VersionID'] = VERSION_ID; - body['Channel'] = CHANNEL; - body['LanguageID'] = languageID == 'ar' ? 1 : 2; - - body['IPAdress'] = "10.20.10.20"; - body['generalid'] = GENERAL_ID; - body['PatientOutSA'] = body.containsKey('PatientOutSA') - ? body['PatientOutSA'] != null - ? body['PatientOutSA'] - : PATIENT_OUT_SA_PATIENT_REQ - : PATIENT_OUT_SA_PATIENT_REQ; - - if (body.containsKey('isDentalAllowedBackend')) { - body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend') - ? body['isDentalAllowedBackend'] != null - ? body['isDentalAllowedBackend'] - : IS_DENTAL_ALLOWED_BACKEND - : IS_DENTAL_ALLOWED_BACKEND; - } - - body['DeviceTypeID'] = Platform.isAndroid ? 1 : 2; - - body['PatientType'] = body.containsKey('PatientType') - ? body['PatientType'] != null - ? body['PatientType'] - : patient!.patientType != null - ? patient.patientType - : PATIENT_TYPE - : PATIENT_TYPE; - - body['PatientTypeID'] = body.containsKey('PatientTypeID') - ? body['PatientTypeID'] != null - ? body['PatientTypeID'] - : patient!.patientType != null - ? patient.patientType - : PATIENT_TYPE_ID - : PATIENT_TYPE_ID; - - body['TokenID'] = body.containsKey('TokenID') ? body['TokenID'] ?? token : token; - body['PatientID'] = body['PatientID'] != null ? body['PatientID'] : patient!.patientId ?? patient.patientMRN; - - body['PatientOutSA'] = 0; //user['OutSA']; //TODO change it - body['SessionID'] = SESSION_ID; //getSe - - int? projectID = await sharedPref.getInt(PROJECT_ID); - if (projectID == 2 || projectID == 3) - body['PatientOutSA'] = true; - else - body['PatientOutSA'] = false; - - // if(!body.containsKey('ProjectID')) { - // if (projectID != null) { - // body['ProjectID'] = 313; - // } else { - // body['ProjectID'] = 0; - // } - // } - - // body['DoctorID'] = 24; //3844083 - // body['TokenID'] = "@dm!n"; + Map headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }; + + String? token = await sharedPref.getString(TOKEN); + Map? profile = await sharedPref.getObj(DOCTOR_PROFILE); + + if (profile != null) { + DoctorProfileModel doctorProfile = DoctorProfileModel.fromJson(profile); + if (body!['DoctorID'] == null) { + body['DoctorID'] = doctorProfile.doctorID; + } + } + if (body!['DoctorID'] == 0) { + body['DoctorID'] = null; + } + var languageID = + await sharedPref.getStringWithDefaultValue(APP_Language, 'en'); + body['SetupID'] = body!.containsKey('SetupID') + ? body['SetupID'] != null + ? body['SetupID'] + : await sharedPref.getString(DOCTOR_SETUP_ID) + : await sharedPref.getString(DOCTOR_SETUP_ID); + + body['VersionID'] = VERSION_ID; + body['Channel'] = CHANNEL; + body['LanguageID'] = languageID == 'ar' ? 1 : 2; + + body['IPAdress'] = "10.20.10.20"; + body['generalid'] = GENERAL_ID; + body['PatientOutSA'] = body.containsKey('PatientOutSA') + ? body['PatientOutSA'] != null + ? body['PatientOutSA'] + : PATIENT_OUT_SA_PATIENT_REQ + : PATIENT_OUT_SA_PATIENT_REQ; + + if (body.containsKey('isDentalAllowedBackend')) { + body['isDentalAllowedBackend'] = + body.containsKey('isDentalAllowedBackend') + ? body['isDentalAllowedBackend'] != null + ? body['isDentalAllowedBackend'] + : IS_DENTAL_ALLOWED_BACKEND + : IS_DENTAL_ALLOWED_BACKEND; + } - print("URL : $url"); - print("Body : ${json.encode(body)}"); - var asd = json.encode(body); - var asd2; - if (await Utils.checkConnection()) { - final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers); - final int statusCode = response.statusCode; - print("statusCode :$statusCode"); - if (statusCode < 200 || statusCode >= 400 || json == null) { - onFailure('Error While Fetching data', statusCode); - } else { - // var parsed = json.decode(response.body.toString()); - var parsed = json.decode(utf8.decode(response.bodyBytes)); - if (parsed['Response_Message'] != null) { - onSuccess(parsed, statusCode); - } else { - if (parsed['ErrorType'] == 4) { - helpers.navigateToUpdatePage(parsed['ErrorEndUserMessage'], parsed['AndroidLink'], parsed['IOSLink']); - } - if (parsed['IsAuthenticated'] == null) { - if (parsed['isSMSSent'] == true) { - onSuccess(parsed, statusCode); - } else if (parsed['MessageStatus'] == 1) { - onSuccess(parsed, statusCode); - } else if (parsed['Result'] == 'OK') { - onSuccess(parsed, statusCode); - } else { - if (parsed != null) { - onSuccess(parsed, statusCode); - } else { - onFailure(getError(parsed), statusCode); - } - } - } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) { - onSuccess(parsed, statusCode); - } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) { - if (parsed['SameClinicApptList'] != null) { - onSuccess(parsed, statusCode); - } else { - if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { - if (parsed['ErrorSearchMsg'] == null) { - onFailure("Server Error found with no available message", statusCode); - } else { - onFailure(parsed['ErrorSearchMsg'], statusCode); - } - } else { - onFailure(parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); - } - } - } else { - if (parsed['SameClinicApptList'] != null) { - onSuccess(parsed, statusCode); - } else { - if (parsed['message'] != null) { - onFailure(parsed['message'] ?? parsed['message'], statusCode); - } else { - onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); - } - } - } - } - } - } else { - onFailure('Please Check The Internet Connection', -1); - } + body['DeviceTypeID'] = Platform.isAndroid ? 1 : 2; + + body['PatientType'] = body.containsKey('PatientType') + ? body['PatientType'] != null + ? body['PatientType'] + : patient!.patientType != null + ? patient.patientType + : PATIENT_TYPE + : PATIENT_TYPE; + + body['PatientTypeID'] = body.containsKey('PatientTypeID') + ? body['PatientTypeID'] != null + ? body['PatientTypeID'] + : patient!.patientType != null + ? patient.patientType + : PATIENT_TYPE_ID + : PATIENT_TYPE_ID; + + body['TokenID'] = + body.containsKey('TokenID') ? body['TokenID'] ?? token : token; + body['PatientID'] = body['PatientID'] != null + ? body['PatientID'] + : patient!.patientId ?? patient.patientMRN; + + body['PatientOutSA'] = 0; //user['OutSA']; //TODO change it + body['SessionID'] = SESSION_ID; //getSe + + int? projectID = await sharedPref.getInt(PROJECT_ID); + if (projectID == 2 || projectID == 3) + body['PatientOutSA'] = true; + else + body['PatientOutSA'] = false; + + // if(!body.containsKey('ProjectID')) { + // if (projectID != null) { + // body['ProjectID'] = 313; + // } else { + // body['ProjectID'] = 0; + // } + // } + + // body['DoctorID'] = 24; //3844083 + // body['TokenID'] = "@dm!n"; + + print("URL : $url"); + print("Body : ${json.encode(body)}"); + var asd = json.encode(body); + var asd2; + if (await Utils.checkConnection()) { + final response = await http.post(Uri.parse(url.trim()), + body: json.encode(body), headers: headers); + final int statusCode = response.statusCode; + print("statusCode :$statusCode"); + if (statusCode < 200 || statusCode >= 400 || json == null) { + onFailure('Error While Fetching data', statusCode); + } else { + // var parsed = json.decode(response.body.toString()); + var parsed = json.decode(utf8.decode(response.bodyBytes)); + if (parsed['Response_Message'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['ErrorType'] == 4) { + helpers.navigateToUpdatePage(parsed['ErrorEndUserMessage'], + parsed['AndroidLink'], parsed['IOSLink']); + } + if (parsed['IsAuthenticated'] == null) { + if (parsed['isSMSSent'] == true) { + onSuccess(parsed, statusCode); + } else if (parsed['MessageStatus'] == 1) { + onSuccess(parsed, statusCode); + } else if (parsed['Result'] == 'OK') { + onSuccess(parsed, statusCode); + } else { + if (parsed != null) { + onSuccess(parsed, statusCode); + } else { + if (body['DoctorID'] != null) + postFailureResponse( + doctorId: body['DoctorID'], + url: url, + request: json.encode(body), + response: response.body, + exception: getError(parsed)); + onFailure(getError(parsed), statusCode); + } + } + } else if (parsed['MessageStatus'] == 1 || + parsed['SMSLoginRequired'] == true) { + onSuccess(parsed, statusCode); + } else if (parsed['MessageStatus'] == 2 && + parsed['IsAuthenticated']) { + if (parsed['SameClinicApptList'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['message'] == null && + parsed['ErrorEndUserMessage'] == null) { + if (parsed['ErrorSearchMsg'] == null) { + if (body['DoctorID'] != null) + postFailureResponse( + doctorId: body['DoctorID'], + url: url, + request: json.encode(body), + response: response.body, + exception: + "Server Error found with no available message"); + + onFailure("Server Error found with no available message", + statusCode); + } else { + if (body['DoctorID'] != null) + postFailureResponse( + doctorId: body['DoctorID'], + url: url, + request: json.encode(body), + response: response.body, + exception: parsed['ErrorSearchMsg']); + onFailure(parsed['ErrorSearchMsg'], statusCode); + } + } else { + if (body['DoctorID'] != null) + postFailureResponse( + doctorId: body['DoctorID'], + url: url, + request: json.encode(body), + response: response.body, + exception: parsed['message'] ?? + parsed['ErrorEndUserMessage'] ?? + parsed['ErrorMessage']); + onFailure( + parsed['message'] ?? + parsed['ErrorEndUserMessage'] ?? + parsed['ErrorMessage'], + statusCode); + } + } + } else { + if (parsed['SameClinicApptList'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['message'] != null) { + if (body['DoctorID'] != null) + postFailureResponse( + doctorId: body['DoctorID'], + url: url, + request: json.encode(body), + response: response.body, + exception: parsed['message']); + + onFailure(parsed['message'] ?? parsed['message'], statusCode); + } else { + if (body['DoctorID'] != null) + postFailureResponse( + doctorId: body['DoctorID'], + url: url, + request: json.encode(body), + response: response.body, + exception: parsed['ErrorEndUserMessage'] ?? + parsed['ErrorMessage']); + + onFailure( + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode); + } + } + } + } + } + } else { + onFailure('Please Check The Internet Connection', -1); + } } catch (e) { - print(e); - onFailure(e.toString(), -1); + print(e); + onFailure(e.toString(), -1); + } } - } - String getError(parsed) { + String getError(parsed) { //TODO change this fun String? error = parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']; if (parsed["ValidationErrors"] != null) { - error = parsed["ValidationErrors"]["StatusMessage"].toString() + "\n"; - - if (parsed["ValidationErrors"]["ValidationErrors"] != null && parsed["ValidationErrors"]["ValidationErrors"].length != 0) { - for (var i = 0; i < parsed["ValidationErrors"]["ValidationErrors"].length; i++) { - error = error! + parsed["ValidationErrors"]["ValidationErrors"][i]["Messages"][0] + "\n"; - } - } + error = parsed["ValidationErrors"]["StatusMessage"].toString() + "\n"; + + if (parsed["ValidationErrors"]["ValidationErrors"] != null && + parsed["ValidationErrors"]["ValidationErrors"].length != 0) { + for (var i = 0; + i < parsed["ValidationErrors"]["ValidationErrors"].length; + i++) { + error = error! + + parsed["ValidationErrors"]["ValidationErrors"][i]["Messages"][0] + + "\n"; + } + } } if (error == null || error == "null" || error == "null\n") { - return Utils.generateContactAdminMsg(); + return Utils.generateContactAdminMsg(); } return error; - } + } - get({required String endPoint, required Function(dynamic response, int statusCode) onSuccess, required Function(String error, int statusCode) onFailure}) async { + get( + {required String endPoint, + required Function(dynamic response, int statusCode) onSuccess, + required Function(String error, int statusCode) onFailure}) async { String token = await sharedPref.getString(TOKEN); String url = DOCTOR_ROTATION + endPoint + '&token=' + token; print(url); @@ -358,10 +490,10 @@ class BaseAppClient { final int statusCode = response.statusCode; if (statusCode < 200 || statusCode >= 400) { - onFailure(Utils.generateContactAdminMsg(), statusCode); + onFailure(Utils.generateContactAdminMsg(), statusCode); } else { - var parsed = json.decode(response.body.toString()); - onSuccess(parsed, statusCode); + var parsed = json.decode(response.body.toString()); + onSuccess(parsed, statusCode); + } } } -} diff --git a/lib/config/config.dart b/lib/config/config.dart index b8c88b61..de76d5d1 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -12,6 +12,10 @@ const BASE_URL_LIVE_CARE = 'https://uat.hmgwebservices.com/'; // const BASE_URL = 'http://10.20.200.111:1010/'; const BASE_URL = 'https://uat.hmgwebservices.com/'; +// const BASE_URL = 'https://hmgwebservices.com/'; + +// const BASE_URL = 'https://uat.hmgwebservices.com/'; + // const BASE_URL = 'https://webservices.hmg.com/'; // const BASE_URL = 'https://vidauat.cloudsolutions.com.sa/'; //Vida Plus URL @@ -286,6 +290,88 @@ const DOCTOR_RADIOLOGY_CRITICAL_FINDINGS = "Services/DoctorApplication.svc/REST/ const ACKNOWLEDGE_RADIOLOGY_CRITICAL_FINDINGS = "Services/DoctorApplication.svc/REST/Acknowledgeradcriticalfindings"; + + /*vida plus API */ + +const PATIENT_ALLERGIES = 'Services/DoctorApplication.svc/REST/PatientAllergies'; + +const SEARCH_ALLERGIES = 'Services/DoctorApplication.svc/REST/SearchAllergies'; + +const POST_ALLERGIES = 'Services/DoctorApplication.svc/REST/PostAllergies'; + +const CREATE_HOPI = 'Services/DoctorApplication.svc/REST/CreateHOPI'; + +const HOPI_DETAILS = 'Services/DoctorApplication.svc/REST/DetailHOPI'; + +const POST_CHIEF_COMPLAINT_VP = 'Services/DoctorApplication.svc/REST/PostChiefcomplaint'; + +const SEARCH_CHIEF_COMPLAINT_VP = 'Services/DoctorApplication.svc/REST/SearchChiefcomplaint'; + +const RESOLVE_ALLERGIES = 'Services/DoctorApplication.svc/REST/ResolveAllergy'; + +const UPDATE_ALLERGIES = 'Services/DoctorApplication.svc/REST/UpdateAllergy'; + +const GET_CHIEF_COMPLAINT_VP = 'Services/DoctorApplication.svc/REST/ChiefComplaintDetails'; + +const SEARCH_DIAGNOSIS = 'Services/DoctorApplication.svc/REST/SearchDiagnosis'; + +const DIAGNOSIS_TYPE = 'Services/DoctorApplication.svc/REST/DiagnosisType'; + +const CONDITION_TYPE = 'Services/DoctorApplication.svc/REST/DiagnosisCondition'; + +const CREATE_DIAGNOSIS = 'Services/DoctorApplication.svc/REST/CreateDiagnosis'; + +const PREVIOUS_DIAGNOSIS = 'Services/DoctorApplication.svc/REST/DiagnosisPreviousDetails'; + +const AUDIT_DIAGNOSIS = 'Services/DoctorApplication.svc/REST/DiagnosisAudit'; + +const REMOVE_DIAGNOSIS = 'Services/DoctorApplication.svc/REST/DiagnosisRemove'; + +const FAVORITE_DIAGNOSIS = 'Services/DoctorApplication.svc/REST/DiagnosisGetFavourite'; + +const ADD_TO_FAVORITE_DIAGNOSIS = 'Services/DoctorApplication.svc/REST/DiagnosisAddFavourite'; + +const MAKE_PREVIOUS_AS_CURRENT_DIAGNOSIS = 'Services/DoctorApplication.svc/REST/ContinuePreviousEpisode'; + +const SEARCH_PHYSICAL_EXAMINATION = 'Services/DoctorApplication.svc/REST/SearchPhysicalExam'; + +const GET_GENERAL_SPECIALITY = 'Services/DoctorApplication.svc/REST/GetGeneralSpeciality'; + +const GET_SPECIALITY_DETAILS = 'Services/DoctorApplication.svc/REST/SearchGeneralSpeciality'; + +const POST_PHYSICAL_EXAMINATION = 'Services/DoctorApplication.svc/REST/PostPhysicalExam'; + +const GET_PROGRESS_NOTE_NEW = 'Services/DoctorApplication.svc/REST/GetProgressNote'; + +const GET_LIST_OF_DIAGNOSIS = 'Services/DoctorApplication.svc/REST/DiagnosisDetailsSearch'; + +const EDIT_DIAGNOSIS = 'Services/DoctorApplication.svc/REST/EditDiagnosis'; + +const RESOLVE_DIAGNOSIS = 'Services/DoctorApplication.svc/REST/DiagnosisResolve'; +const GET_CLINIC = 'Services/DoctorApplication.svc/REST/GetDoctorClinicsForVidaPlus'; + +const CONTINUE_EPISODE_VP = 'Services/DoctorApplication.svc/REST/ContinueEpisode'; + +const UPDATE_CHIEF_COMPLAINT = 'Services/DoctorApplication.svc/REST/UpdateChiefComplaint'; + +const EPISODE_BY_CHIEF_COMPLAINT = 'Services/DoctorApplication.svc/REST/EpisodeByChiefcomplaint'; + +const GET_EDIT_ALLERGIES = 'Services/DoctorApplication.svc/REST/GetAllergy'; + +const GET_HOME_MEDICATION = 'Services/DoctorApplication.svc/REST/GetHomeMedication'; + +const SEARCH_CURRENT_MEDICATION = 'Services/DoctorApplication.svc/REST/SearchFormulary'; + +const SEARCH_CURRENT_MEDICATION_DETAILS = 'Services/DoctorApplication.svc/REST/GetFormularyMaster'; + +const REMOVE_CURRENT_MEDICATION = 'Services/DoctorApplication.svc/REST/DeleteHomeMedication'; + +const ADD_CURRENT_MEDICATION = 'Services/DoctorApplication.svc/REST/AddHomeMedication'; + +const CREATE_PROGRESS_NOTE = 'Services/DoctorApplication.svc/REST/PostProgressNote'; + +const GET_PATIENT_CLINIC = 'Services/DoctorApplication.svc/REST/GetPatientConditionProgress'; + var selectedPatientType = 1; //*********change value to decode json from Dropdown ************ @@ -318,7 +404,7 @@ const TRANSACTION_NO = 0; const LANGUAGE_ID = 2; const STAMP = '2020-04-27T12:17:17.721Z'; const IP_ADDRESS = '9.9.9.9'; -const VERSION_ID = 8.9; +const VERSION_ID = 9.4; const CHANNEL = 9; const SESSION_ID = 'BlUSkYymTt'; const IS_LOGIN_FOR_DOCTOR_APP = true; diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index c31788f9..10f97042 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -254,6 +254,7 @@ const Map> localizedValues = { "beingBad": {"en": "being bad", "ar": "سيء"}, "beingGreat": {"en": "being great", "ar": "رائع"}, "cancel": {"en": "CANCEL", "ar": "الغاء"}, + "cancelSmall": {"en": "Cancel", "ar": "الغاء"}, "ok": {"en": "OK", "ar": "موافق"}, "done": {"en": "DONE", "ar": "تأكيد"}, "resumecall": {"en": "Resume call", "ar": "استئناف المكالمة"}, @@ -484,6 +485,7 @@ const Map> localizedValues = { "ar": "ملاحظات على نوع النظام الغذائي" }, "save": {"en": "SAVE", "ar": "حفظ"}, + "saveSmall": {"en": "Save", "ar": "حفظ"}, "postPlansEstimatedCost": { "en": "POST PLANS & ESTIMATED COST", "ar": "خطط ما بعد العملية والتكلفة المقدرة" @@ -677,6 +679,7 @@ const Map> localizedValues = { "progressNoteSOAP": {"en": "Progress Note", "ar": "ملاحظة التقدم"}, "addProgressNote": {"en": "Add Progress Note", "ar": "أضف ملاحظة التقدم"}, "createdBy": {"en": "Created By :", "ar": "أضيفت عن طريق: "}, + "createdOn": {"en": "Created On :", "ar": "تم إنشاؤه في: "}, "riskScore": {"en": "Risk Score :", "ar": "درجة المخاطر"}, "editedBy": {"en": "Edited By :", "ar": "عدلت من : "}, "currentMedications": {"en": "Current Medications", "ar": "الأدوية الحالية"}, @@ -1160,7 +1163,73 @@ const Map> localizedValues = { "afterOrderCreation": {"en": "After order created, you cannot modify the principal diagnosis, Do you want to continue?", "ar":"بعد إنشاء الطلب، لا يمكنك تعديل التشخيص الأساسي، هل تريد المتابعة؟"}, "principalCoveredOrNot": {"en": "Principal Diagnosis is not covered for this patient", "ar":"لا يتم تغطية التشخيص الرئيسي لهذا المريض"}, "complexDiagnosis": {"en": "Complex Diagnosis", "ar":"التشخيص المعقد"}, + "noComplaintsFound": {"en": "No Chief Complaints added, please add it from the button above", "ar":"لم تتم إضافة شكاوى رئيسية ، يرجى إضافتها من الزر أعلاه"}, + "noKnownAllergies": {"en": "No Known Allergies", "ar":"لا يوجد حساسية معروفة"}, + "addChiefComplaint": {"en": "Add Chief Complaints*", "ar":"إضافة الشكاوى الرئيسية*"}, + "myFavoriteList": {"en": "My Favourite List", "ar":"قائمتي المفضلة"}, + "generalList": {"en": "General list", "ar":"قائمة عامة"}, + "specialList": {"en": "Special List", "ar":"قائمة خاصة"}, + "enterChiefCompliants": {"en": "Enter Chief Compliants", "ar":"أدخل رئيس الامتثال"}, + "previousChiefCompaints": {"en": "Previous Chief Compaints", "ar":"رئيس الرسامين السابق"}, + "listOfActiveEpisodes": {"en": "List of active episodes , select one to procedd", "ar":"قائمة الحلقات النشطة ، حدد واحدة لتقديمها"}, + "select": {"en": "Select", "ar":"اختار"}, + "resolve": {"en": "Resolve", "ar":"حسم"}, + "audit": {"en": "Audit", "ar":"مراجعه الحسابات"}, + "delete": {"en": "Delete", "ar":"حذف"}, + "acute": {"en": "Acute", "ar":"شديد"}, + "chronic": {"en": "Acute", "ar":"مزمن"}, + "subAcute": {"en": "sub-acute", "ar":"شبه الحاد"}, + "addDiagnosis": {"en": "Add Diagnosis", "ar":"إضافة تشخيص"}, + "showAllDiagnosis": {"en": "Show all diagnosis", "ar":"عرض جميع التشخيصات"}, + "makeCurrentDiagnosis": {"en": "Make Current Diagnosis", "ar":"جعل التشخيص الحالي"}, + "mappedDiagnosis": {"en": "Mapped Diagnosis", "ar":"التشخيص المعين"}, + "previousDiagnosis": {"en": "Previous Diagnosis", "ar":"التشخيص السابق"}, + "addNewDiagnosis": {"en": "Add New Diagnosis", "ar":"إضافة تشخيص جديد"}, + "currentDiagnosis": {"en": "Current Diagnosis", "ar":"التشخيص الحالي"}, + "progressNoteType": {"en": "Progress Note Type", "ar":"نوع ملاحظة التقدم"}, + "doctorProgressNote": {"en": "Doctor Progress Note", "ar":"مذكرة تقدم الطبيب"}, + "addYourNote": {"en": "Add Your Note", "ar":"أضف ملاحظتك"}, + "saveAsDraft": {"en": "Save As Draft", "ar":"حفظ كمسودة"}, + "nurseNote": {"en": "Nurse Note", "ar":"ملاحظة الممرضة"}, + "patientCondition": {"en": "Patient Condition", "ar":"حالة المريض"}, + "examinationPart": {"en": "Examination Part", "ar":"جزء الامتحان"}, + "historyOfIllness": {"en": "History of Present Illness*", "ar":"تاريخ المرض الحالي*"}, + "historyTakenFrom": {"en": "History taken from", "ar":"التاريخ مأخوذ من"}, + "familySpecify": {"en": "Family, Specify", "ar":"العائلة، حدد"}, + "otherSpecify": {"en": "Other, Specify", "ar":"أخرى، حدد"}, + "physicalExamination": {"en": "Physical Examination", "ar":"الفحص البدني"}, + "addPhysicalExamination": {"en": "Add Physical Examination", "ar":"إضافة الفحص البدني"}, + "noPhysicalExamination": {"en": "No Physical Examination added, please add it from the button above", "ar":"لم يتم إضافة فحص بدني ، يرجى إضافته من الزر أعلاه"}, + "noProgressNote": {"en": "No Diagnosis added, please add it from the button above", "ar":"لم يتم إضافة تشخيص ، يرجى إضافته من الزر أعلاه"}, + "mild": {"en": "Mild", "ar":"خفيف"}, + "moderate": {"en": "Moderate", "ar":"معتدل"}, + "remarksCanNotBeEmpty": {"en": "Remarks Can Not Be Empty", "ar":"لا يمكن أن تكون الملاحظات فارغة"}, + "kindlySelectCategory": {"en": "Kindly Select Any Diagnosis Category", "ar":"يرجى اختيار أي فئة تشخيص"}, + "noRemarks": {"en": "No Remarks", "ar":"لا ملاحظات"}, + "event": {"en": "Event: ", "ar":"حدث: "}, + "editDiagnosis": {"en": "Edit Diagnosis ", "ar":"تحرير التشخيص"}, + "selectedDiagnosis": {"en": "Kindly Select Diagnosis", "ar":"يرجى اختيار التشخيص: "}, + "selectConditionFirst": {"en": "Kindly Select Diagnosis Condition", "ar":"يرجى اختيار حالة التشخيص: "}, + "deletedRemarks": {"en": "Deleted Remarks: ", "ar":"ملاحظات محذوفة: "}, + "newValue": {"en": "New Value: ", "ar":"قيمة جديدة: "}, + "fieldName": {"en": "Field Name: ", "ar":"اسم الحقل: "}, + "noChangeRecorded": {"en": "No Change Recorded Unable To Perform Edit", "ar":"لم يتم تسجيل أي تغيير، غير قادر على إجراء التحرير"}, + "oldValue": {"en": "Old Value: ", "ar":"القيمة القديمة: "}, + "favoriteDiagnosis": {"en": "Favorite Diagnosis", "ar":"التشخيص المفضل"}, + "addToFavorite": {"en": "Add To Favorite", "ar":"إضافة إلى المفضلة"}, + "noDiagnosisFound": {"en": "No Diagnosis added, please add it from the button above", "ar":"لم يتم إضافة تشخيص ، يرجى إضافته من الزر أعلاه"}, + "areYouSureYouWantToDeleteDiagnosis": { + "en": "Are you sure you want to delete diagnosis", + "ar": "هل أنت متأكد من أنك تريد حذف التشخيص" + }, + "activate": {"en": "Activate", "ar":"فعل"}, + "stable": {"en": "Stable", "ar":"مستقر"}, + "resolved": {"en": "Resolved", "ar":"تم الحل"}, + "diagnosisAlreadyDeleted": {"en": "Diagnosis Already Deleted", "ar":"تم حذف التشخيص بالفعل"}, + "diagnosisAlreadyResolved": {"en": "Diagnosis Already Resolved", "ar":"تم حل التشخيص بالفعل"}, + "selectReaction": {"en": "Select Reaction", "ar":"حدد رد الفعل"}, + "progressNoteCanNotBeEmpty": {"en": "Progress Note Can Not Be Empty", "ar":"ملاحظة التقدم لا يمكن أن تكون فارغة"}, }; diff --git a/lib/core/model/SOAP/allergy/get_allergies_list_vida_plus.dart b/lib/core/model/SOAP/allergy/get_allergies_list_vida_plus.dart new file mode 100644 index 00000000..09a4d3cc --- /dev/null +++ b/lib/core/model/SOAP/allergy/get_allergies_list_vida_plus.dart @@ -0,0 +1,130 @@ +class AllergiesListVidaPlus { + int? allergyID; + String? allergyName; + List? allergyReactionDTOs; + int? allergyRevisionID; + String? allergyTypeCode; + int? allergyTypeID; + String? allergyTypeName; + int? hospitalGroupID; + int? hospitalID; + bool? isActive; + bool? isSnowMedAllergy; + String? snowMedCode; + String? remark; + AllergiesListVidaPlus( + {this.allergyID, + this.allergyName, + this.allergyReactionDTOs, + this.allergyRevisionID, + this.allergyTypeCode, + this.allergyTypeID, + this.allergyTypeName, + this.hospitalGroupID, + this.hospitalID, + this.isActive, + this.isSnowMedAllergy, + this.snowMedCode, + this.remark + }); + + AllergiesListVidaPlus.fromJson(Map json) { + allergyID = json['allergyID']; + allergyName = json['allergyName']; + if (json['allergyReactionDTOs'] != null) { + allergyReactionDTOs = []; + json['allergyReactionDTOs'].forEach((v) { + allergyReactionDTOs!.add(new AllergyReactionDTOs.fromJson(v)); + }); + } + allergyRevisionID = json['allergyRevisionID']; + allergyTypeCode = json['allergyTypeCode']; + allergyTypeID = json['allergyTypeID']; + allergyTypeName = json['allergyTypeName']; + hospitalGroupID = json['hospitalGroupID']; + hospitalID = json['hospitalID']; + isActive = json['isActive']; + isSnowMedAllergy = json['isSnowMedAllergy']; + snowMedCode = json['snowMedCode']; + } + + Map toJson() { + final Map data = new Map(); + data['allergyID'] = this.allergyID; + data['allergyName'] = this.allergyName; + if (this.allergyReactionDTOs != null) { + data['allergyReactionDTOs'] = + this.allergyReactionDTOs!.map((v) => v.toJson()).toList(); + } + data['allergyRevisionID'] = this.allergyRevisionID; + data['allergyTypeCode'] = this.allergyTypeCode; + data['allergyTypeID'] = this.allergyTypeID; + data['allergyTypeName'] = this.allergyTypeName; + data['hospitalGroupID'] = this.hospitalGroupID; + data['hospitalID'] = this.hospitalID; + data['isActive'] = this.isActive; + data['isSnowMedAllergy'] = this.isSnowMedAllergy; + data['snowMedCode'] = this.snowMedCode; + return data; + } +} + +class AllergyReactionDTOs { + int? allergyReactionID; + String? allergyReactionName; + int? allergyReactionRevisionID; + dynamic? hospitalGroupID; + int? hospitalID; + bool? isActive; + bool? isSelected =false; + int? dbCRUDOperation =1; + int? pomrid; + int? patientID; + int? allergyReactionMappingID = 0; + int? severity =1; + AllergyReactionDTOs( + {this.allergyReactionID, + this.allergyReactionName, + this.allergyReactionRevisionID, + this.hospitalGroupID, + this.hospitalID, + this.isActive, + this.isSelected, + this.dbCRUDOperation, + this.pomrid, + this.patientID, + this.allergyReactionMappingID, + this.severity =1 + }); + + AllergyReactionDTOs.fromJson(Map json) { + allergyReactionID = json['allergyReactionID']; + allergyReactionName = json['allergyReactionName']; + allergyReactionRevisionID = json['allergyReactionRevisionID']; + hospitalGroupID = json['hospitalGroupID']; + hospitalID = json['hospitalID']; + isActive = json['isActive']; + dbCRUDOperation = json["DbCRUDOperation"]; + pomrid = json['pomrid']; + patientID = json['patientID']; + allergyReactionMappingID = json['allergyReactionMappingID']; + severity = json['severity']; + + } + + Map toJson() { + final Map data = new Map(); + data['allergyReactionID'] = this.allergyReactionID; + data['allergyReactionName'] = this.allergyReactionName; + data['allergyReactionRevisionID'] = this.allergyReactionRevisionID; + data['hospitalGroupID'] = this.hospitalGroupID; + data['hospitalID'] = this.hospitalID; + data['isActive'] = this.isActive; + data["DbCRUDOperation"] = this.dbCRUDOperation; + data['pomrid'] = this.pomrid; + data['patientID'] = patientID; + data['allergyReactionMappingID'] = this.allergyReactionMappingID; + data['severity'] = this.severity; + return data; + } +} diff --git a/lib/core/model/SOAP/allergy/get_patient_allergies_list_vida_plus.dart b/lib/core/model/SOAP/allergy/get_patient_allergies_list_vida_plus.dart new file mode 100644 index 00000000..ce84f58b --- /dev/null +++ b/lib/core/model/SOAP/allergy/get_patient_allergies_list_vida_plus.dart @@ -0,0 +1,128 @@ +class PatientAllergiesVidaPlus { + int? allergyID; + String? allergyName; + int? allergyTypeID; + String? allergyTypeName; + int? hospitalGroupID; + int? hospitalID; + bool? isActivePatientsAllergy; + int? patientID; + List? patientsAllergyReactionsDTOs; + int? patientsAllergyRevisionID; + int? pomrID; + String? remark; + + PatientAllergiesVidaPlus( + {this.allergyID, + this.allergyName, + this.allergyTypeID, + this.allergyTypeName, + this.hospitalGroupID, + this.hospitalID, + this.isActivePatientsAllergy, + this.patientID, + this.patientsAllergyReactionsDTOs, + this.patientsAllergyRevisionID, + this.pomrID, + this.remark}); + + PatientAllergiesVidaPlus.fromJson(Map json) { + allergyID = json['allergyID']; + allergyName = json['allergyName']; + allergyTypeID = json['allergyTypeID']; + allergyTypeName = json['allergyTypeName']; + hospitalGroupID = json['hospitalGroupID']; + hospitalID = json['hospitalID']; + isActivePatientsAllergy = json['isActivePatientsAllergy']; + patientID = json['patientID']; + if (json['patientsAllergyReactionsDTOs'] != null) { + patientsAllergyReactionsDTOs = []; + json['patientsAllergyReactionsDTOs'].forEach((v) { + patientsAllergyReactionsDTOs! + .add(new PatientsAllergyReactionsDTOs.fromJson(v)); + }); + } + patientsAllergyRevisionID = json['patientsAllergyRevisionID']; + pomrID = json['pomrID']; + remark = json['remark']; + } + + Map toJson() { + final Map data = new Map(); + data['allergyID'] = this.allergyID; + data['allergyName'] = this.allergyName; + data['allergyTypeID'] = this.allergyTypeID; + data['allergyTypeName'] = this.allergyTypeName; + data['hospitalGroupID'] = this.hospitalGroupID; + data['hospitalID'] = this.hospitalID; + data['isActivePatientsAllergy'] = this.isActivePatientsAllergy; + data['patientID'] = this.patientID; + if (this.patientsAllergyReactionsDTOs != null) { + data['patientsAllergyReactionsDTOs'] = + this.patientsAllergyReactionsDTOs!.map((v) => v.toJson()).toList(); + } + data['patientsAllergyRevisionID'] = this.patientsAllergyRevisionID; + data['pomrID'] = this.pomrID; + data['remark'] = this.remark; + return data; + } +} + +class PatientsAllergyReactionsDTOs { + int? allergyReactionID; + int? allergyReactionMappingID; + String? allergyReactionName; + int? hospitalGroupID; + int? hospitalID; + bool? isActive; + int? patientID; + int? patientsAllergyReactionRevisionID; + int? pomrId; + int? severity =1; + bool? isSelected =true; + String? reactionSelection =""; + PatientsAllergyReactionsDTOs( + {this.allergyReactionID, + this.allergyReactionMappingID, + this.allergyReactionName, + this.hospitalGroupID, + this.hospitalID, + this.isActive, + this.patientID, + this.patientsAllergyReactionRevisionID, + this.pomrId, + this.severity =1, + this.isSelected, + this.reactionSelection + }); + + PatientsAllergyReactionsDTOs.fromJson(Map json) { + allergyReactionID = json['allergyReactionID']; + allergyReactionMappingID = json['allergyReactionMappingID']; + allergyReactionName = json['allergyReactionName']; + hospitalGroupID = json['hospitalGroupID']; + hospitalID = json['hospitalID']; + isActive = json['isActive']; + patientID = json['patientID']; + patientsAllergyReactionRevisionID = + json['patientsAllergyReactionRevisionID']; + pomrId = json['pomrId']; + severity = json['severity']; + } + + Map toJson() { + final Map data = new Map(); + data['allergyReactionID'] = this.allergyReactionID; + data['allergyReactionMappingID'] = this.allergyReactionMappingID; + data['allergyReactionName'] = this.allergyReactionName; + data['hospitalGroupID'] = this.hospitalGroupID; + data['hospitalID'] = this.hospitalID; + data['isActive'] = this.isActive; + data['patientID'] = this.patientID; + data['patientsAllergyReactionRevisionID'] = + this.patientsAllergyReactionRevisionID; + data['pomrId'] = this.pomrId; + data['severity'] = this.severity; + return data; + } +} diff --git a/lib/core/model/SOAP/assessment/FavoriteDiseaseDetails.dart b/lib/core/model/SOAP/assessment/FavoriteDiseaseDetails.dart new file mode 100644 index 00000000..19614800 --- /dev/null +++ b/lib/core/model/SOAP/assessment/FavoriteDiseaseDetails.dart @@ -0,0 +1,92 @@ +class FavoriteDiseaseDetails { + String? categoryCode; + int? categoryId; + String? chapterCode; + String? codeRange; + String? createdBy; + String? diseaseType; + String? diseases; + String? diseasesCode; + int? diseasesId; + int? favoritesId; + int? hospitalGroupId; + int? hospitalId; + int? icdId; + String? icdSubVersion; + String? icdType; + String? icdVersion; + bool? isDeleted; + String? parentDiseasesCode; + String? problemCode; + String? problemDescription; + int? problemMasterId; + int? problemMasterRevisionId; + String? problemName; + String? problemType; + String? rowVersion; + String? sectionCode; + int? specificationId; + + FavoriteDiseaseDetails.fromJson(Map json) { + categoryCode = json['CategoryCode']; + categoryId = json['CategoryId']; + chapterCode = json['ChapterCode']; + codeRange = json['CodeRange']; + createdBy = json['CreatedBy']; + diseaseType = json['DiseaseType']; + diseases = json['Diseases']; + diseasesCode = json['DiseasesCode']; + diseasesId = json['DiseasesId']; + favoritesId = json['FavoritesId']; + hospitalGroupId = json['HospitalGroupID']; + hospitalId = json['HospitalID']; + icdId = json['IcdId']; + icdSubVersion = json['IcdSubVersion']; + icdType = json['IcdType']; + icdVersion = json['IcdVersion']; + isDeleted = json['IsDeleted']; + parentDiseasesCode = json['ParentDiseasesCode']; + problemCode = json['ProblemCode']; + problemDescription = json['ProblemDescription']; + problemMasterId = json['ProblemMasterID']; + problemMasterRevisionId = json['ProblemMasterRevisionID']; + problemName = json['ProblemName']; + problemType = json['ProblemType']; + rowVersion = json['RowVersion']; + sectionCode = json['SectionCode']; + specificationId = json['SpecificationId']; + } + + // toJson method + Map toJson() { + return { + 'CategoryCode': categoryCode, + 'CategoryId': categoryId, + 'ChapterCode': chapterCode, + 'CodeRange': codeRange, + 'CreatedBy': createdBy, + 'DiseaseType': diseaseType, + 'Diseases': diseases, + 'DiseasesCode': diseasesCode, + 'DiseasesId': diseasesId, + 'FavoritesId': favoritesId, + 'HospitalGroupID': hospitalGroupId, + 'HospitalID': hospitalId, + 'IcdId': icdId, + 'IcdSubVersion': icdSubVersion, + 'IcdType': icdType, + 'IcdVersion': icdVersion, + 'IsDeleted': isDeleted, + 'ParentDiseasesCode': parentDiseasesCode, + 'ProblemCode': problemCode, + 'ProblemDescription': problemDescription, + 'ProblemMasterID': problemMasterId, + 'ProblemMasterRevisionID': problemMasterRevisionId, + 'ProblemName': problemName, + 'ProblemType': problemType, + 'RowVersion': rowVersion, + 'SectionCode': sectionCode, + 'SpecificationId': specificationId, + }; + } +} \ No newline at end of file diff --git a/lib/core/model/SOAP/assessment/audit_diagnosis.dart b/lib/core/model/SOAP/assessment/audit_diagnosis.dart new file mode 100644 index 00000000..f98205dc --- /dev/null +++ b/lib/core/model/SOAP/assessment/audit_diagnosis.dart @@ -0,0 +1,39 @@ +class AuditDiagnosis { + String? approvedBy; + String? approvedOn; + String? createdBy; + String? createdOn; + String? deletedBy; + String? deletedOn; + String? deletedRemarks; + String? doctorName; + String? diagnosisType; + bool? isEventIdentifiedExternally; + bool? isResolved; + String? modifiedBy; + String? modifiedOn; + int? patientId; + int? patientProblemRevisionId; + String? remarks; + String? status; + + AuditDiagnosis.fromJson(Map json) { + approvedBy = json['approvedBy']; + approvedOn = json['approvedOn']; + createdBy = json['createdBy']; + createdOn = json['createdOn']; + deletedBy = json['deletedBy']; + deletedOn = json['deletedOn']; + doctorName = json['doctorName']; + deletedRemarks = json['deletedRemarks']; + diagnosisType = json['diagnosisType']; + isEventIdentifiedExternally = json['isEventIdentifiedExternally']; + isResolved = json['isResolved']; + modifiedBy = json['modifiedBy']; + modifiedOn = json['modifiedOn']; + patientId = json['patientId']; + patientProblemRevisionId = json['patientProblemRevisionId']; + remarks = json['remarks']; + status = json['status']; + } +} \ No newline at end of file diff --git a/lib/core/model/SOAP/assessment/diagnosis_type.dart b/lib/core/model/SOAP/assessment/diagnosis_type.dart new file mode 100644 index 00000000..549342d0 --- /dev/null +++ b/lib/core/model/SOAP/assessment/diagnosis_type.dart @@ -0,0 +1,10 @@ +class DiagnosisType { + String? diagnosisType; + String? name; + + + DiagnosisType.fromJson(Map json) { + diagnosisType = json['diagnosisType'] ?? ''; + name = json['name'] ?? ''; + } +} \ No newline at end of file diff --git a/lib/core/model/SOAP/assessment/patient_previous_diagnosis.dart b/lib/core/model/SOAP/assessment/patient_previous_diagnosis.dart new file mode 100644 index 00000000..99a50bf6 --- /dev/null +++ b/lib/core/model/SOAP/assessment/patient_previous_diagnosis.dart @@ -0,0 +1,287 @@ +class PatientPreviousDiagnosis { + bool? active; + int? admissionId; + int? admissionRequestId; + int? appointmentId; + String? approvedBy; + String? approvedOn; + int? assessmentId; + int? chiefComplainId; + int? clinicGroupId; + int? clinicId; + String? condition; + String? createdBy; + String? createdOn; + String? deletedBy; + String? deletedByDoctorName; + String? deletedOn; + String? deletedRemarks; + String? diagnosisType; + int? doctorId; + int? episodeId; + int? hospitalGroupId; + int? hospitalId; + dynamic icdCodeDetailsDto; + String? icdSubVersion; + String? icdType; + dynamic icdVersion; + String? location; + String? loginUserId; + String? modifiedBy; + String? modifiedOn; + String? module; + String? parentLocation; + int? patientId; + dynamic patientProblemChangeHistories; + int? patientProblemId; + int? patientProblemRevisionId; + int? pomrId; + bool? previousProblem; + int? problemId; + String? problemName; + String? remarks; + bool? resolved; + String? selectedCategoryCode; + String? selectedChapterCode; + String? selectedDisease; + String? selectedIcdCode; + String? selectedSectionCode; + String? status; + List? visitWisePatientDiagnoses; + bool? visitWiseSelected; + + PatientPreviousDiagnosis.fromJson(Map json) { + active = json['active']; + admissionId = json['admissionId']; + admissionRequestId = json['admissionRequestId']; + appointmentId = json['appointmentId']; + approvedBy = json['approvedBy']; + approvedOn = json['approvedOn']; + assessmentId = json['assessmentId']; + chiefComplainId = json['chiefComplainId']; + clinicGroupId = json['clinicGroupId']; + clinicId = json['clinicId']; + condition = json['condition']; + createdBy = json['createdBy']; + createdOn = json['createdOn']; + deletedBy = json['deletedBy']; + deletedByDoctorName = json['deletedByDoctorName']; + deletedOn = json['deletedOn']; + deletedRemarks = json['deletedRemarks']; + diagnosisType = json['diagnosisType']; + doctorId = json['doctorId']; + episodeId = json['episodeId']; + hospitalGroupId = json['hospitalGroupId']; + hospitalId = json['hospitalId']; + icdCodeDetailsDto = json['icdCodeDetailsDto']; + icdSubVersion = json['icdSubVersion']; + icdType = json['icdType']; + icdVersion = json['icdVersion']; + location = json['location']; + loginUserId = json['loginUserId']; + modifiedBy = json['modifiedBy']; + modifiedOn = json['modifiedOn']; + module = json['module']; + parentLocation = json['parentLocation']; + patientId = json['patientId']; + patientProblemChangeHistories = json['patientProblemChangeHistories']; + patientProblemId = json['patientProblemId']; + patientProblemRevisionId = json['patientProblemRevisionId']; + pomrId = json['pomrId']; + previousProblem = json['previousProblem']; + problemId = json['problemId']; + problemName = json['problemName']; + remarks = json['remarks']; + resolved = json['resolved']; + selectedCategoryCode = json['selectedCategoryCode']; + selectedChapterCode = json['selectedChapterCode']; + selectedDisease = json['selectedDisease']; + selectedIcdCode = json['selectedIcdCode']; + selectedSectionCode = json['selectedSectionCode']; + status = json['status']; + visitWiseSelected = json['visitWiseSelected']; + if (json['visitWisePatientDiagnoses'] != null) { + visitWisePatientDiagnoses = []; + json['visitWisePatientDiagnoses'].forEach((v) { + visitWisePatientDiagnoses!.add(VisitWisePatientDiagnosis.fromJson(v)); + }); + } + } + + Map toJson() { + return { + 'active': active, + 'admissionId': admissionId ?? 0, + 'admissionRequestId': admissionRequestId ?? 0, + 'appointmentId': appointmentId ?? 0, + 'approvedBy': approvedBy, + 'approvedOn': approvedOn, + 'assessmentId': assessmentId ?? 0, + 'chiefComplainId': chiefComplainId ?? 0, + 'clinicGroupId': clinicGroupId ?? 0, + 'clinicId': clinicId, + 'condition': condition, + 'createdBy': createdBy, + 'createdOn': createdOn, + 'deletedBy': deletedBy, + 'deletedByDoctorName': deletedByDoctorName, + 'deletedOn': deletedOn, + 'deletedRemarks': deletedRemarks, + 'diagnosisType': diagnosisType, + 'doctorId': doctorId, + 'episodeId': episodeId ?? 0, + 'hospitalGroupId': hospitalGroupId, + 'hospitalId': hospitalId, + 'icdCodeDetailsDto': icdCodeDetailsDto, + 'icdSubVersion': icdSubVersion, + 'icdType': icdType, + 'icdVersion': icdVersion, + 'location': location, + 'loginUserId': loginUserId, + 'modifiedBy': modifiedBy, + 'modifiedOn': modifiedOn, + 'module': module, + 'parentLocation': parentLocation, + 'patientId': patientId, + 'patientProblemChangeHistories': patientProblemChangeHistories, + 'patientProblemId': patientProblemId, + 'patientProblemRevisionId': patientProblemRevisionId, + 'pomrId': pomrId, + 'previousProblem': previousProblem, + 'problemId': problemId, + 'problemName': problemName, + 'remarks': remarks, + 'resolved': resolved, + 'selectedCategoryCode': selectedCategoryCode, + 'selectedChapterCode': selectedChapterCode, + 'selectedDisease': selectedDisease, + 'selectedIcdCode': selectedIcdCode, + 'selectedSectionCode': selectedSectionCode, + 'status': status, + 'visitWiseSelected': visitWiseSelected, + 'visitWisePatientDiagnoses': visitWisePatientDiagnoses?.map((v) => v.toJson()).toList(), + }; + } +} + +class VisitWisePatientDiagnosis { + bool? active; + int? admissionId; + int? appointmentId; + String? approvedBy; + String? approvedOn; + int? assessmentId; + int? clinicId; + String? condition; + String? createdBy; + String? createdOn; + String? deletedBy; + String? deletedOn; + String? deletedRemarks; + String? diagnosisType; + int? doctorId; + int? episodeId; + int? hospitalGroupId; + int? hospitalId; + String? icdSubVersion; + String? icdType; + dynamic icdVersion; + bool? isPreviousProblem; + String? location; + String? loginUserId; + String? modifiedBy; + String? modifiedOn; + int? patientDiagnosisId; + int? patientId; + int? patientProblemRevisionId; + int? pomrId; + String? problemName; + String? remarks; + bool? resolved; + bool? selected; + String? selectedDisease; + int? selectedDoctorId; + String? selectedIcdCode; + + VisitWisePatientDiagnosis.fromJson(Map json) { + active = json['active']; + admissionId = json['admissionId']; + appointmentId = json['appointmentId']; + approvedBy = json['approvedBy']; + approvedOn = json['approvedOn']; + assessmentId = json['assessmentId']; + clinicId = json['clinicId']; + condition = json['condition']; + createdBy = json['createdBy']; + createdOn = json['createdOn']; + deletedBy = json['deletedBy']; + deletedOn = json['deletedOn']; + deletedRemarks = json['deletedRemarks']; + diagnosisType = json['diagnosisType']; + doctorId = json['doctorId']; + episodeId = json['episodeId']; + hospitalGroupId = json['hospitalGroupId']; + hospitalId = json['hospitalId']; + icdSubVersion = json['icdSubVersion']; + icdType = json['icdType']; + icdVersion = json['icdVersion']; + isPreviousProblem = json['isPreviousProblem']; + location = json['location']; + loginUserId = json['loginUserId']; + modifiedBy = json['modifiedBy']; + modifiedOn = json['modifiedOn']; + patientDiagnosisId = json['patientDiagnosisId']; + patientId = json['patientId']; + patientProblemRevisionId = json['patientProblemRevisionId']; + pomrId = json['pomrId']; + problemName = json['problemName']; + remarks = json['remarks']; + resolved = json['resolved']; + selected = json['selected']; + selectedDisease = json['selectedDisease']; + selectedDoctorId = json['selectedDoctorId']; + selectedIcdCode = json['selectedIcdCode']; + } + + Map toJson() { + return { + 'active': active, + 'admissionId': admissionId, + 'appointmentId': appointmentId, + 'approvedBy': approvedBy, + 'approvedOn': approvedOn, + 'assessmentId': assessmentId, + 'clinicId': clinicId, + 'condition': condition, + 'createdBy': createdBy, + 'createdOn': createdOn, + 'deletedBy': deletedBy, + 'deletedOn': deletedOn, + 'deletedRemarks': deletedRemarks, + 'diagnosisType': diagnosisType, + 'doctorId': doctorId, + 'episodeId': episodeId, + 'hospitalGroupId': hospitalGroupId, + 'hospitalId': hospitalId, + 'icdSubVersion': icdSubVersion, + 'icdType': icdType, + 'icdVersion': icdVersion, + 'isPreviousProblem': isPreviousProblem, + 'location': location, + 'loginUserId': loginUserId, + 'modifiedBy': modifiedBy, + 'modifiedOn': modifiedOn, + 'patientDiagnosisId': patientDiagnosisId, + 'patientId': patientId, + 'patientProblemRevisionId': patientProblemRevisionId, + 'pomrId': pomrId, + 'problemName': problemName, + 'remarks': remarks, + 'resolved': resolved, + 'selected': selected, + 'selectedDisease': selectedDisease, + 'selectedDoctorId': selectedDoctorId, + 'selectedIcdCode': selectedIcdCode, + }; + } +} diff --git a/lib/core/model/SOAP/assessment/search_diagnosis.dart b/lib/core/model/SOAP/assessment/search_diagnosis.dart new file mode 100644 index 00000000..0a7ab2e7 --- /dev/null +++ b/lib/core/model/SOAP/assessment/search_diagnosis.dart @@ -0,0 +1,99 @@ +class SearchDiagnosis { + String? category; + String? categoryId; + String? codeRange; + String? diseaseType; + String? diseases; + String? diseasesBCode; + String? diseasesCode; + String? diseasesDataId; + String? diseasesId; + String? diseasesName; + int? hospitalGroupId; + int? hospitalId; + String? icdSubVersion; + String? icdType; + List? icdVersion; + String? icdVersionDisplay; + bool? isDeleted; + String? layerID; + String? parentDiseasesCode; + String? specification; + int? specificationId; + String? specificationNo; + String? selectedIcdCode; + String? selectedCategoryCode; + String? selectedSectionCode; + String? selectedChapterCode; + String? selectedNandaCode; + bool isFavorite = false; + + // Default constructor + SearchDiagnosis(); + + // fromJson constructor + SearchDiagnosis.fromJson(Map json) { + category = json['category']; + categoryId = json['categoryId']; + codeRange = json['codeRange']; + diseaseType = json['diseaseType']; + diseases = json['diseases']; + diseasesBCode = json['diseasesBCode']; + diseasesCode = json['diseasesCode']; + diseasesDataId = json['diseasesDataId']; + diseasesId = json['diseasesId']; + diseasesName = json['diseasesName']; + hospitalGroupId = json['hospitalGroupId']; + hospitalId = json['hospitalId']; + icdSubVersion = json['icdSubVersion']; + icdType = json['icdType']; + icdVersion = json['icdVersion'] != null + ? List.from(json['icdVersion']) + : null; + icdVersionDisplay = json['icdVersionDisplay']; + isDeleted = json['isDeleted'] == "True"; + layerID = json['layerID']; + parentDiseasesCode = json['parentDiseasesCode']; + specification = json['specification']; + specificationId = json['specificationId']; + specificationNo = json['specificationNo']; + selectedIcdCode = json['selectedIcdCode']; + selectedCategoryCode = json['selectedCategoryCode']; + selectedSectionCode = json['selectedSectionCode']; + selectedChapterCode = json['selectedChapterCode']; + selectedNandaCode = json['selectedNandaCode']; + } + + // toJson method + Map toJson() { + return { + 'category': category, + 'categoryId': categoryId, + 'codeRange': codeRange, + 'diseaseType': diseaseType, + 'diseases': diseases, + 'diseasesBCode': diseasesBCode, + 'diseasesCode': diseasesCode, + 'diseasesDataId': diseasesDataId, + 'diseasesId': diseasesId, + 'diseasesName': diseasesName, + 'hospitalGroupId': hospitalGroupId, + 'hospitalId': hospitalId, + 'icdSubVersion': icdSubVersion, + 'icdType': icdType, + 'icdVersion': icdVersion, + 'icdVersionDisplay': icdVersionDisplay, + 'isDeleted': isDeleted.toString(), + 'layerID': layerID, + 'parentDiseasesCode': parentDiseasesCode, + 'specification': specification, + 'specificationId': specificationId, + 'specificationNo': specificationNo, + 'selectedIcdCode': selectedIcdCode, + 'selectedCategoryCode': selectedCategoryCode, + 'selectedSectionCode': selectedSectionCode, + 'selectedChapterCode': selectedChapterCode, + 'selectedNandaCode': selectedNandaCode, + }; + } +} \ No newline at end of file diff --git a/lib/core/model/SOAP/chief_complaint/episode_by_chief_complaint_vidaplus.dart b/lib/core/model/SOAP/chief_complaint/episode_by_chief_complaint_vidaplus.dart new file mode 100644 index 00000000..13005c9e --- /dev/null +++ b/lib/core/model/SOAP/chief_complaint/episode_by_chief_complaint_vidaplus.dart @@ -0,0 +1,249 @@ +class EpisodeByChiefComplaintVidaPlus { + int? clinicId; + String? createdOn; + int? doctorId; + int? episodeStatus; + int? hospitalGroupId; + int? hospitalId; + String? modifiedOn; + int? patientEpisodeId; + int? patientId; + List? patientPomrs; + + EpisodeByChiefComplaintVidaPlus( + {this.clinicId, + this.createdOn, + this.doctorId, + this.episodeStatus, + this.hospitalGroupId, + this.hospitalId, + this.modifiedOn, + this.patientEpisodeId, + this.patientId, + this.patientPomrs}); + + EpisodeByChiefComplaintVidaPlus.fromJson(Map json) { + clinicId = json['clinicId']; + createdOn = json['createdOn']; + doctorId = json['doctorId']; + episodeStatus = json['episodeStatus']; + hospitalGroupId = json['hospitalGroupId']; + hospitalId = json['hospitalId']; + modifiedOn = json['modifiedOn']; + patientEpisodeId = json['patientEpisodeId']; + patientId = json['patientId']; + if (json['patientPomrs'] != null) { + patientPomrs = []; + json['patientPomrs'].forEach((v) { + patientPomrs!.add(new PatientPomrs.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['clinicId'] = this.clinicId; + data['createdOn'] = this.createdOn; + data['doctorId'] = this.doctorId; + data['episodeStatus'] = this.episodeStatus; + data['hospitalGroupId'] = this.hospitalGroupId; + data['hospitalId'] = this.hospitalId; + data['modifiedOn'] = this.modifiedOn; + data['patientEpisodeId'] = this.patientEpisodeId; + data['patientId'] = this.patientId; + if (this.patientPomrs != null) { + data['patientPomrs'] = this.patientPomrs!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class PatientPomrs { + int? appointmentId; + int? chiefComplainTemplateId; + List? chiefComplains; + int? clinicGroupId; + String? createdOn; + int? doctorId; + String? doctorName; + int? episodeId; + bool? fallowUp; + bool? fallowUpRequired; + bool? isReadOnly; + String? modifiedOn; + int? patientId; + int? patientPomrId; + String? pomrSingOn; + int? pomrStatus; + bool? readOnly; + String? seenAtStatus; + String? vprnSeenAtStatus; + + PatientPomrs( + {this.appointmentId, + this.chiefComplainTemplateId, + this.chiefComplains, + this.clinicGroupId, + this.createdOn, + this.doctorId, + this.doctorName, + this.episodeId, + this.fallowUp, + this.fallowUpRequired, + this.isReadOnly, + this.modifiedOn, + this.patientId, + this.patientPomrId, + this.pomrSingOn, + this.pomrStatus, + this.readOnly, + this.seenAtStatus, + this.vprnSeenAtStatus}); + + PatientPomrs.fromJson(Map json) { + appointmentId = json['appointmentId']; + chiefComplainTemplateId = json['chiefComplainTemplateId']; + if (json['chiefComplains'] != null) { + chiefComplains = []; + json['chiefComplains'].forEach((v) { + chiefComplains!.add(new ChiefComplains.fromJson(v)); + }); + } + clinicGroupId = json['clinicGroupId']; + createdOn = json['createdOn']; + doctorId = json['doctorId']; + doctorName = json['doctorName']; + episodeId = json['episodeId']; + fallowUp = json['fallowUp']; + fallowUpRequired = json['fallowUpRequired']; + isReadOnly = json['isReadOnly']; + modifiedOn = json['modifiedOn']; + patientId = json['patientId']; + patientPomrId = json['patientPomrId']; + pomrSingOn = json['pomrSingOn']; + pomrStatus = json['pomrStatus']; + readOnly = json['readOnly']; + seenAtStatus = json['seenAtStatus']; + vprnSeenAtStatus = json['vprnSeenAtStatus']; + } + + Map toJson() { + final Map data = new Map(); + data['appointmentId'] = this.appointmentId; + data['chiefComplainTemplateId'] = this.chiefComplainTemplateId; + if (this.chiefComplains != null) { + data['chiefComplains'] = + this.chiefComplains!.map((v) => v.toJson()).toList(); + } + data['clinicGroupId'] = this.clinicGroupId; + data['createdOn'] = this.createdOn; + data['doctorId'] = this.doctorId; + data['doctorName'] = this.doctorName; + data['episodeId'] = this.episodeId; + data['fallowUp'] = this.fallowUp; + data['fallowUpRequired'] = this.fallowUpRequired; + data['isReadOnly'] = this.isReadOnly; + data['modifiedOn'] = this.modifiedOn; + data['patientId'] = this.patientId; + data['patientPomrId'] = this.patientPomrId; + data['pomrSingOn'] = this.pomrSingOn; + data['pomrStatus'] = this.pomrStatus; + data['readOnly'] = this.readOnly; + data['seenAtStatus'] = this.seenAtStatus; + data['vprnSeenAtStatus'] = this.vprnSeenAtStatus; + return data; + } +} + +class ChiefComplains { + int? appointmentId; + String? chiefComplain; + int? chiefComplainId; + int? clinicId; + String? createdBy; + int? createdId; + String? createdOn; + int? doctorId; + String? doctorName; + int? episodeId; + int? hospitalGroupId; + int? hospitalId; + String? loginUserId; + String? modifiedBy; + Null? modifiedId; + String? modifiedOn; + int? patientId; + String? patientName; + int? patientPomrId; + int? chiefComplainTemplateId; + + + ChiefComplains( + {this.appointmentId, + this.chiefComplain, + this.chiefComplainId, + this.clinicId, + this.createdBy, + this.createdId, + this.createdOn, + this.doctorId, + this.doctorName, + this.episodeId, + this.hospitalGroupId, + this.hospitalId, + this.loginUserId, + this.modifiedBy, + this.modifiedId, + this.modifiedOn, + this.patientId, + this.patientName, + this.patientPomrId}); + + ChiefComplains.fromJson(Map json) { + appointmentId = json['appointmentId']; + chiefComplain = json['chiefComplain']; + chiefComplainTemplateId = json['chiefComplainTemplateId']; + chiefComplainId = json['chiefComplainId']; + clinicId = json['clinicId']; + createdBy = json['createdBy']; + createdId = json['createdId']; + createdOn = json['createdOn']; + doctorId = json['doctorId']; + doctorName = json['doctorName']; + episodeId = json['episodeId']; + hospitalGroupId = json['hospitalGroupId']; + hospitalId = json['hospitalId']; + loginUserId = json['loginUserId']; + modifiedBy = json['modifiedBy']; + modifiedId = json['modifiedId']; + modifiedOn = json['modifiedOn']; + patientId = json['patientId']; + patientName = json['patientName']; + patientPomrId = json['patientPomrId']; + } + + Map toJson() { + final Map data = new Map(); + data['appointmentId'] = this.appointmentId; + data['chiefComplain'] = this.chiefComplain; + data['chiefComplainId'] = this.chiefComplainId; + data['clinicId'] = this.clinicId; + data['createdBy'] = this.createdBy; + data['createdId'] = this.createdId; + data['createdOn'] = this.createdOn; + data['doctorId'] = this.doctorId; + data['doctorName'] = this.doctorName; + data['episodeId'] = this.episodeId; + data['hospitalGroupId'] = this.hospitalGroupId; + data['hospitalId'] = this.hospitalId; + data['loginUserId'] = this.loginUserId; + data['modifiedBy'] = this.modifiedBy; + data['chiefComplainTemplateId'] = this.chiefComplainTemplateId; + data['modifiedId'] = this.modifiedId; + data['modifiedOn'] = this.modifiedOn; + data['patientId'] = this.patientId; + data['patientName'] = this.patientName; + data['patientPomrId'] = this.patientPomrId; + return data; + } +} diff --git a/lib/core/model/SOAP/chief_complaint/get_chief_complaint_vida_plus.dart b/lib/core/model/SOAP/chief_complaint/get_chief_complaint_vida_plus.dart new file mode 100644 index 00000000..cf2c5f7b --- /dev/null +++ b/lib/core/model/SOAP/chief_complaint/get_chief_complaint_vida_plus.dart @@ -0,0 +1,68 @@ +class GetChiefComplaintVidaPlus { + int? appointmentId; + String? chiefComplain; + int? chiefComplainId; + int? chiefComplainTemplateId; + int? clinicGroupId; + int? clinicId; + int? doctorId; + String? doctorName; + int? episodeId; + int? hospitalGroupId; + int? hospitalId; + String? loginUserId; + int? patientId; + int? patientPomrId; + + GetChiefComplaintVidaPlus( + {this.appointmentId, + this.chiefComplain, + this.chiefComplainId, + this.chiefComplainTemplateId, + this.clinicGroupId, + this.clinicId, + this.doctorId, + this.doctorName, + this.episodeId, + this.hospitalGroupId, + this.hospitalId, + this.loginUserId, + this.patientId, + this.patientPomrId}); + + GetChiefComplaintVidaPlus.fromJson(Map json) { + appointmentId = json['appointmentId']; + chiefComplain = json['chiefComplain']; + chiefComplainId = json['chiefComplainId']; + chiefComplainTemplateId = json['chiefComplainTemplateId']; + clinicGroupId = json['clinicGroupId']; + clinicId = json['clinicId']; + doctorId = json['doctorId']; + doctorName = json['doctorName']; + episodeId = json['episodeId']; + hospitalGroupId = json['hospitalGroupId']; + hospitalId = json['hospitalId']; + loginUserId = json['loginUserId']; + patientId = json['patientId']; + patientPomrId = json['patientPomrId']; + } + + Map toJson() { + final Map data = new Map(); + data['appointmentId'] = this.appointmentId; + data['chiefComplain'] = this.chiefComplain; + data['chiefComplainId'] = this.chiefComplainId; + data['chiefComplainTemplateId'] = this.chiefComplainTemplateId; + data['clinicGroupId'] = this.clinicGroupId; + data['clinicId'] = this.clinicId; + data['doctorId'] = this.doctorId; + data['doctorName'] = this.doctorName; + data['episodeId'] = this.episodeId; + data['hospitalGroupId'] = this.hospitalGroupId; + data['hospitalId'] = this.hospitalId; + data['loginUserId'] = this.loginUserId; + data['patientId'] = this.patientId; + data['patientPomrId'] = this.patientPomrId; + return data; + } +} diff --git a/lib/core/model/SOAP/chief_complaint/search_chief_complaint_vidaplus.dart b/lib/core/model/SOAP/chief_complaint/search_chief_complaint_vidaplus.dart new file mode 100644 index 00000000..389cd99f --- /dev/null +++ b/lib/core/model/SOAP/chief_complaint/search_chief_complaint_vidaplus.dart @@ -0,0 +1,40 @@ +class SearchChiefComplaint { + String? chiefComplain; + String? chiefComplainCode; + int? chiefComplainId; + String? clinic; + int? hospitalGroupId; + int? hospitalId; + String? nursingGroup; + + SearchChiefComplaint( + {this.chiefComplain, + this.chiefComplainCode, + this.chiefComplainId, + this.clinic, + this.hospitalGroupId, + this.hospitalId, + this.nursingGroup}); + + SearchChiefComplaint.fromJson(Map json) { + chiefComplain = json['chiefComplain']; + chiefComplainCode = json['chiefComplainCode']; + chiefComplainId = json['chiefComplainId']; + clinic = json['clinic']; + hospitalGroupId = json['hospitalGroupId']; + hospitalId = json['hospitalId']; + nursingGroup = json['nursingGroup']; + } + + Map toJson() { + final Map data = new Map(); + data['chiefComplain'] = this.chiefComplain; + data['chiefComplainCode'] = this.chiefComplainCode; + data['chiefComplainId'] = this.chiefComplainId; + data['clinic'] = this.clinic; + data['hospitalGroupId'] = this.hospitalGroupId; + data['hospitalId'] = this.hospitalId; + data['nursingGroup'] = this.nursingGroup; + return data; + } +} diff --git a/lib/core/model/SOAP/get_hopi_details.dart b/lib/core/model/SOAP/get_hopi_details.dart new file mode 100644 index 00000000..eadf19ba --- /dev/null +++ b/lib/core/model/SOAP/get_hopi_details.dart @@ -0,0 +1,66 @@ +class GetHopiDetails { + int? clinicId; + int? doctorId; + int? hospitalGroupId; + int? hospitalId; + String? hpi; + int? hpiId; + bool? isHpiTakenFamily; + bool? isHpiTakenOther; + bool? isHpiTakenPatient; + String? hpiTakenFamilyText; + String? hpiTakenOtherText; + String? loginUserId; + int? patientId; + int? patientPomrId; + + GetHopiDetails( + {this.clinicId, + this.doctorId, + this.hospitalGroupId, + this.hospitalId, + this.hpi, + this.hpiId, + this.isHpiTakenFamily, + this.isHpiTakenOther, + this.isHpiTakenPatient, + this.loginUserId, + this.patientId, + this.patientPomrId}); + + GetHopiDetails.fromJson(Map json) { + clinicId = json['clinicId']; + doctorId = json['doctorId']; + hospitalGroupId = json['hospitalGroupId']; + hospitalId = json['hospitalId']; + hpi = json['hpi']; + hpiId = json['hpiId']; + isHpiTakenFamily = json['isHpiTakenFamily']; + isHpiTakenOther = json['isHpiTakenOther']; + isHpiTakenPatient = json['isHpiTakenPatient']; + loginUserId = json['loginUserId']; + patientId = json['patientId']; + patientPomrId = json['patientPomrId']; + hpiTakenFamilyText = json['hpiTakenFamilyText']; + hpiTakenOtherText = json['hpiTakenOtherText']; + } + + Map toJson() { + final Map data = new Map(); + data['clinicId'] = this.clinicId; + data['doctorId'] = this.doctorId; + data['hospitalGroupId'] = this.hospitalGroupId; + data['hospitalId'] = this.hospitalId; + data['hpi'] = this.hpi; + data['hpiId'] = this.hpiId; + data['isHpiTakenFamily'] = this.isHpiTakenFamily; + data['isHpiTakenOther'] = this.isHpiTakenOther; + data['isHpiTakenPatient'] = this.isHpiTakenPatient; + data['loginUserId'] = this.loginUserId; + data['patientId'] = this.patientId; + data['patientPomrId'] = this.patientPomrId; + data['hpiTakenFamilyText'] = this.hpiTakenFamilyText; + data['hpiTakenOtherText'] = this.hpiTakenOtherText; + return data; + } +} diff --git a/lib/core/model/SOAP/home_medication_vp/GetHomeMedication.dart b/lib/core/model/SOAP/home_medication_vp/GetHomeMedication.dart new file mode 100644 index 00000000..01d186c3 --- /dev/null +++ b/lib/core/model/SOAP/home_medication_vp/GetHomeMedication.dart @@ -0,0 +1,156 @@ +class GetHomeMedicationList { + List? personalizationEntity; + int? appointmentId; + int? clinicGroupId; + int? clinicId; + String? createdTime; + String? doseQuantity; + String? formularyName; + String? frequencyId; + String? frequencyString; + String? genericFormularyId; + String? homeMedFrom; + int? hospitalGroupId; + int? hospitalId; + String? id; + bool? isActive; + bool? isEHRIPReconciled; + bool? isEHROPReconciled; + bool? isERIPReconciled; + bool? isFreeText; + bool? isReconciled; + bool? isUnknownDetail; + String? lastUpdatedTime; + int? patientId; + int? patientPomrId; + String? prescribeTypeAlias; + int? prescribedItemId; + String? prescribedItemName; + String? remarks; + String? routeId; + String? routeString; + String? rowVersion; + String? sentence; + String? strengthId; + String? strengthString; + + GetHomeMedicationList( + {this.personalizationEntity, + this.appointmentId, + this.clinicGroupId, + this.clinicId, + this.createdTime, + this.doseQuantity, + this.formularyName, + this.frequencyId, + this.frequencyString, + this.genericFormularyId, + this.homeMedFrom, + this.hospitalGroupId, + this.hospitalId, + this.id, + this.isActive, + this.isEHRIPReconciled, + this.isEHROPReconciled, + this.isERIPReconciled, + this.isFreeText, + this.isReconciled, + this.isUnknownDetail, + this.lastUpdatedTime, + this.patientId, + this.patientPomrId, + this.prescribeTypeAlias, + this.prescribedItemId, + this.prescribedItemName, + this.remarks, + this.routeId, + this.routeString, + this.rowVersion, + this.sentence, + this.strengthId, + this.strengthString}); + + GetHomeMedicationList.fromJson(Map json) { + if (json['PersonalizationEntity'] != null) { + personalizationEntity = []; + json['PersonalizationEntity'].forEach((v) { + personalizationEntity!.add( v.fromJson(v)); + }); + } + appointmentId = json['appointmentId']; + clinicGroupId = json['clinicGroupId']; + clinicId = json['clinicId']; + createdTime = json['createdTime']; + doseQuantity = json['doseQuantity']; + formularyName = json['formularyName']; + frequencyId = json['frequencyId']; + frequencyString = json['frequencyString']; + genericFormularyId = json['genericFormularyId']; + homeMedFrom = json['homeMedFrom']; + hospitalGroupId = json['hospitalGroupId']; + hospitalId = json['hospitalId']; + id = json['id']; + isActive = json['isActive']; + isEHRIPReconciled = json['isEHRIPReconciled']; + isEHROPReconciled = json['isEHROPReconciled']; + isERIPReconciled = json['isERIPReconciled']; + isFreeText = json['isFreeText']; + isReconciled = json['isReconciled']; + isUnknownDetail = json['isUnknownDetail']; + lastUpdatedTime = json['lastUpdatedTime']; + patientId = json['patientId']; + patientPomrId = json['patientPomrId']; + prescribeTypeAlias = json['prescribeTypeAlias']; + prescribedItemId = json['prescribedItemId']; + prescribedItemName = json['prescribedItemName']; + remarks = json['remarks']; + routeId = json['routeId']; + routeString = json['routeString']; + rowVersion = json['rowVersion']; + sentence = json['sentence']; + strengthId = json['strengthId']; + strengthString = json['strengthString']; + } + + Map toJson() { + final Map data = new Map(); + if (this.personalizationEntity != null) { + data['PersonalizationEntity'] = + this.personalizationEntity!.map((v) => v.toJson()).toList(); + } + data['appointmentId'] = this.appointmentId; + data['clinicGroupId'] = this.clinicGroupId; + data['clinicId'] = this.clinicId; + data['createdTime'] = this.createdTime; + data['doseQuantity'] = this.doseQuantity; + data['formularyName'] = this.formularyName; + data['frequencyId'] = this.frequencyId; + data['frequencyString'] = this.frequencyString; + data['genericFormularyId'] = this.genericFormularyId; + data['homeMedFrom'] = this.homeMedFrom; + data['hospitalGroupId'] = this.hospitalGroupId; + data['hospitalId'] = this.hospitalId; + data['id'] = this.id; + data['isActive'] = this.isActive; + data['isEHRIPReconciled'] = this.isEHRIPReconciled; + data['isEHROPReconciled'] = this.isEHROPReconciled; + data['isERIPReconciled'] = this.isERIPReconciled; + data['isFreeText'] = this.isFreeText; + data['isReconciled'] = this.isReconciled; + data['isUnknownDetail'] = this.isUnknownDetail; + data['lastUpdatedTime'] = this.lastUpdatedTime; + data['patientId'] = this.patientId; + data['patientPomrId'] = this.patientPomrId; + data['prescribeTypeAlias'] = this.prescribeTypeAlias; + data['prescribedItemId'] = this.prescribedItemId; + data['prescribedItemName'] = this.prescribedItemName; + data['remarks'] = this.remarks; + data['routeId'] = this.routeId; + data['routeString'] = this.routeString; + data['rowVersion'] = this.rowVersion; + data['sentence'] = this.sentence; + data['strengthId'] = this.strengthId; + data['strengthString'] = this.strengthString; + return data; + } +} diff --git a/lib/core/model/SOAP/home_medication_vp/GetSearchCurrentMedication.dart b/lib/core/model/SOAP/home_medication_vp/GetSearchCurrentMedication.dart new file mode 100644 index 00000000..fd94d9cf --- /dev/null +++ b/lib/core/model/SOAP/home_medication_vp/GetSearchCurrentMedication.dart @@ -0,0 +1,40 @@ +class GetSearchCurrentMedication { + String? formularyName; + String? genericFormularyCode; + String? genericFormularyId; + int? hospitalGroupId; + int? hospitalId; + String? itemType; + bool? outOfStock; + + GetSearchCurrentMedication( + {this.formularyName, + this.genericFormularyCode, + this.genericFormularyId, + this.hospitalGroupId, + this.hospitalId, + this.itemType, + this.outOfStock}); + + GetSearchCurrentMedication.fromJson(Map json) { + formularyName = json['formularyName']; + genericFormularyCode = json['genericFormularyCode']; + genericFormularyId = json['genericFormularyId']; + hospitalGroupId = json['hospitalGroupId']; + hospitalId = json['hospitalId']; + itemType = json['itemType']; + outOfStock = json['outOfStock']; + } + + Map toJson() { + final Map data = new Map(); + data['formularyName'] = this.formularyName; + data['genericFormularyCode'] = this.genericFormularyCode; + data['genericFormularyId'] = this.genericFormularyId; + data['hospitalGroupId'] = this.hospitalGroupId; + data['hospitalId'] = this.hospitalId; + data['itemType'] = this.itemType; + data['outOfStock'] = this.outOfStock; + return data; + } +} diff --git a/lib/core/model/SOAP/home_medication_vp/GetSearchCurrentMedicationDetails.dart b/lib/core/model/SOAP/home_medication_vp/GetSearchCurrentMedicationDetails.dart new file mode 100644 index 00000000..0cdd9ada --- /dev/null +++ b/lib/core/model/SOAP/home_medication_vp/GetSearchCurrentMedicationDetails.dart @@ -0,0 +1,108 @@ +class GetSearchCurrentMedicationDetails { + List? genericItemFrequencyDetailsEntity; + List? genericItemRouteDetailsEntity; + List? itemStrengthDetailsDto; + int? patientTypeId; + + GetSearchCurrentMedicationDetails({this.genericItemFrequencyDetailsEntity, this.genericItemRouteDetailsEntity, this.itemStrengthDetailsDto, this.patientTypeId}); + + GetSearchCurrentMedicationDetails.fromJson(Map json) { + if (json['genericItemFrequencyDetailsEntity'] != null) { + genericItemFrequencyDetailsEntity = []; + json['genericItemFrequencyDetailsEntity'].forEach((v) { genericItemFrequencyDetailsEntity!.add(new GenericItemFrequencyDetailsEntity.fromJson(v)); }); + } + if (json['genericItemRouteDetailsEntity'] != null) { + genericItemRouteDetailsEntity = []; + json['genericItemRouteDetailsEntity'].forEach((v) { genericItemRouteDetailsEntity!.add(new GenericItemRouteDetailsEntity.fromJson(v)); }); + } + if (json['itemStrengthDetailsDto'] != null) { + itemStrengthDetailsDto = []; + json['itemStrengthDetailsDto'].forEach((v) { itemStrengthDetailsDto!.add(new ItemStrengthDetailsDto.fromJson(v)); }); + } + patientTypeId = json['patientTypeId']; + } + + Map toJson() { + final Map data = new Map(); + if (this.genericItemFrequencyDetailsEntity != null) { + data['genericItemFrequencyDetailsEntity'] = this.genericItemFrequencyDetailsEntity!.map((v) => v.toJson()).toList(); + } + if (this.genericItemRouteDetailsEntity != null) { + data['genericItemRouteDetailsEntity'] = this.genericItemRouteDetailsEntity!.map((v) => v.toJson()).toList(); + } + if (this.itemStrengthDetailsDto != null) { + data['itemStrengthDetailsDto'] = this.itemStrengthDetailsDto!.map((v) => v.toJson()).toList(); + } + data['patientTypeId'] = this.patientTypeId; + return data; + } +} + +class GenericItemFrequencyDetailsEntity { + bool? Default; + String? frequency; + int? frequencyId; + int? interval; + + GenericItemFrequencyDetailsEntity({this.Default, this.frequency, this.frequencyId, this.interval}); + +GenericItemFrequencyDetailsEntity.fromJson(Map json) { +Default = json['Default']; +frequency = json['Frequency']; +frequencyId = json['FrequencyId']; +interval = json['Interval']; +} + +Map toJson() { +final Map data = new Map(); +data['Default'] = this.Default; +data['Frequency'] = this.frequency; +data['FrequencyId'] = this.frequencyId; +data['Interval'] = this.interval; +return data; +} +} + +class GenericItemRouteDetailsEntity { +bool? Default; +String? route; +int? routeId; + +GenericItemRouteDetailsEntity({this.Default, this.route, this.routeId}); + +GenericItemRouteDetailsEntity.fromJson(Map json) { +Default = json['default']; +route = json['route']; +routeId = json['routeId']; +} + +Map toJson() { +final Map data = new Map(); +data['default'] = this.Default; +data['route'] = this.route; +data['routeId'] = this.routeId; +return data; +} +} + +class ItemStrengthDetailsDto { +bool? Default; +String? strength; +int? strengthId; + +ItemStrengthDetailsDto({this.Default, this.strength, this.strengthId}); + +ItemStrengthDetailsDto.fromJson(Map json) { +Default = json['default']; +strength = json['strength']; +strengthId = json['strengthId']; +} + +Map toJson() { +final Map data = new Map(); +data['default'] = this.Default; +data['strength'] = this.strength; +data['strengthId'] = this.strengthId; +return data; +} +} diff --git a/lib/core/model/SOAP/physical_exam/Category.dart b/lib/core/model/SOAP/physical_exam/Category.dart new file mode 100644 index 00000000..26542d27 --- /dev/null +++ b/lib/core/model/SOAP/physical_exam/Category.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; + +class Condition { + String? conditionCode; + String? conditionName; + + Condition(); + + Condition.fromJson(Map json) { + conditionCode = json['conditionCode']; + conditionName = json['conditionName']; + } + + Map toJson() { + return { + 'conditionCode': conditionCode, + 'conditionName': conditionName, + }; + } +} + +class Category { + int? categoryId; + String? code; + String? codeAlias; + List? conditionsList; + String? description; + String? descriptionAlias; + int? id; + bool? isActive; + bool? isBuiltin; + String? languageCode; + String? name; + String? nameAlias; + int? rowVersion; + int? specialityId; + String? specialityName; + List? translationValues; + bool isSelected = false; + TextEditingController remarksController = TextEditingController(); + int selectedCondition = -1; + String selectedConditionName = ""; + String? pomrId; + int? paitientId; + int? userID; + bool isExpanded = false; + + Category(); + + Category.fromJson(Map json,int? specialityId, String specialityName, String? pomrId, int paitientId, int userID) { + categoryId = json['categoryId']; + code = json['code']; + codeAlias = json['codeAlias']; + if (json['conditionsList'] != null) { + conditionsList = []; + json['conditionsList'].forEach((v) { + conditionsList!.add(Condition.fromJson(v)); + }); + } + if(conditionsList?.isNotEmpty == true) selectedCondition = int.parse(conditionsList?.first.conditionName ??'-1'); + description = json['description']; + descriptionAlias = json['descriptionAlias']; + id = json['id']; + isActive = json['isActive']; + isBuiltin = json['isBuiltin']; + languageCode = json['languageCode']; + name = json['name']; + nameAlias = json['nameAlias']; + rowVersion = json['rowVersion']; + translationValues = json['translationValues']; + this.specialityName = specialityName; + this.specialityId = specialityId; + this.pomrId = pomrId; + this.paitientId = paitientId; + this.userID = userID; + } + + Map toJson() { + return { + 'categoryId': categoryId, + 'code': code, + 'codeAlias': codeAlias, + 'conditionsList': conditionsList?.map((v) => v.toJson()).toList(), + 'description': description, + 'descriptionAlias': descriptionAlias, + 'id': id, + 'isActive': isActive, + 'isBuiltin': isBuiltin, + 'languageCode': languageCode, + 'name': name, + 'nameAlias': nameAlias, + 'rowVersion': rowVersion, + 'translationValues': translationValues, + }; + } +} \ No newline at end of file diff --git a/lib/core/model/SOAP/physical_exam/CreatePhysicalExamination.dart b/lib/core/model/SOAP/physical_exam/CreatePhysicalExamination.dart new file mode 100644 index 00000000..7a60cd06 --- /dev/null +++ b/lib/core/model/SOAP/physical_exam/CreatePhysicalExamination.dart @@ -0,0 +1,74 @@ +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/Category.dart'; + +class CreatePhysicalExamination { + bool? isChecked; // it will be told + bool? selected; // same as above + String? pomrid; // paitient + int? patientID; // paitint + bool? isClinicPhysicalExamination; // it will be told + dynamic? physicalExaminationSystemID; // category id + String? physicalExaminationDescription; // name of the category + int? specialityID; // id of the specialitiy id + dynamic selectedOptions; // it will also be told but it could be sent as null + bool? isMandatory; // it will also be checked default value is false + String? specialityDescription; // name of the speciality + int? physicalExaminationCondition; // condition selected + String? loginUserId; // doctor id + String? remark; + + CreatePhysicalExamination(); + + CreatePhysicalExamination.fromJson(Map json) { + isChecked = json['isChecked']; + selected = json['selected']; + pomrid = json['pomrid']; + patientID = json['patientID']; + isClinicPhysicalExamination = json['isClinicPhysicalExamination']; + physicalExaminationSystemID = json['physicalExaminationSystemID']; + physicalExaminationDescription = json['physicalExaminationDescription']; + specialityID = json['specialityID']; + selectedOptions = json['selectedOptions']; + isMandatory = json['isMandatory']; + specialityDescription = json['specialityDescription']; + physicalExaminationCondition = json['physicalExaminationCondition']; + loginUserId = json['loginUserId']; + remark = json['remark']; + } + + Map toJson() { + return { + 'isChecked': isChecked, + 'selected': selected, + 'pomrid': pomrid, + 'patientID': patientID, + 'isClinicPhysicalExamination': isClinicPhysicalExamination, + 'physicalExaminationSystemID': physicalExaminationSystemID, + 'physicalExaminationDescription': physicalExaminationDescription, + 'specialityID': specialityID, + 'selectedOptions': selectedOptions, + 'isMandatory': isMandatory, + 'specialityDescription': specialityDescription, + 'physicalExaminationCondition': physicalExaminationCondition, + 'loginUserId': loginUserId, + 'remark': remark, + }; + } +} + +extension ConvertCategoryToCreatePhysicalExamination on Category { + CreatePhysicalExamination createPhysicalExaminationFromCategory() => + CreatePhysicalExamination() + ..isChecked = true + ..physicalExaminationDescription = this.name + ..physicalExaminationSystemID = this.id + ..physicalExaminationCondition = this.selectedCondition + ..remark = this.remarksController.text + ..selected = false + ..specialityID = this.specialityId + ..patientID = this.paitientId + ..pomrid = this.pomrId + ..loginUserId = this.userID?.toString() + ..isMandatory = false + ..specialityDescription = this.specialityName + ..isClinicPhysicalExamination = true; +} diff --git a/lib/core/model/SOAP/physical_exam/GeneralSpeciality.dart b/lib/core/model/SOAP/physical_exam/GeneralSpeciality.dart new file mode 100644 index 00000000..7428f6a2 --- /dev/null +++ b/lib/core/model/SOAP/physical_exam/GeneralSpeciality.dart @@ -0,0 +1,24 @@ +class GeneralSpeciality { + int? id; + bool? isActive; + String? name; + int? rowVersion; + bool isSelected = false; + + GeneralSpeciality(); + + GeneralSpeciality.fromJson(Map json) { + id = json['id']; + isActive = json['isActive']; + name = json['name']; + rowVersion = json['rowVersion']; + } + Map toJson() { + return { + 'id': id, + 'isActive': isActive, + 'name': name, + 'rowVersion': rowVersion, + }; + } +} diff --git a/lib/core/model/SOAP/physical_exam/patient_physical_examination.dart b/lib/core/model/SOAP/physical_exam/patient_physical_examination.dart new file mode 100644 index 00000000..ec4253a6 --- /dev/null +++ b/lib/core/model/SOAP/physical_exam/patient_physical_examination.dart @@ -0,0 +1,97 @@ +class PatientPhysicalExamination { + int? patientPhysicalExaminationRevisionID; + int? patientPhysicalExaminationID; + int? patientID; + int? physicalExaminationSystemID; + String? physicalExaminationDescription; + int? physicalExaminationCondition; + String? remark; + int? assessmentId; + String? userType; + int? specialtyID; + String? specialityDescription; + String? loginUserId; + bool? isMandatory; + String? examinationType; + dynamic additionalParams; // Use dynamic for null or varied types + int? hospitalGroupID; + int? hospitalID; + int? dbCRUDOperation; + bool? isActive; + int? createdBy; + String? createdOn; + int? modifiedBy; + String? modifiedOn; + int? approvedBy; + String? approvedOn; + String? rowVersion; + String? pomrid; + + // Default constructor + PatientPhysicalExamination(); + + // fromJson constructor + PatientPhysicalExamination.fromJson(Map json) { + patientPhysicalExaminationRevisionID = + json['patientPhysicalExaminationRevisionID']; + patientPhysicalExaminationID = json['patientPhysicalExaminationID']; + patientID = json['patientID']; + physicalExaminationSystemID = json['physicalExaminationSystemID']; + physicalExaminationDescription = json['physicalExaminationDescription']; + physicalExaminationCondition = json['physicalExaminationCondition']; + remark = json['remark']; + assessmentId = json['assessmentId']; + userType = json['userType']; + specialtyID = json['specialtyID']; + specialityDescription = json['specialityDescription']; + loginUserId = json['loginUserId']; + isMandatory = json['isMandatory']; + examinationType = json['examinationType']; + additionalParams = json['additionalParams']; + hospitalGroupID = json['hospitalGroupID']; + hospitalID = json['hospitalID']; + dbCRUDOperation = json['dbCRUDOperation']; + isActive = json['isActive']; + createdBy = json['createdBy']; + createdOn = json['createdOn']; + modifiedBy = json['modifiedBy']; + modifiedOn = json['modifiedOn']; + approvedBy = json['approvedBy']; + approvedOn = json['approvedOn']; + rowVersion = json['rowVersion']; + pomrid = json['pomrid']; + } + + // toJson method + Map toJson() { + return { + 'patientPhysicalExaminationRevisionID': patientPhysicalExaminationRevisionID, + 'patientPhysicalExaminationID': patientPhysicalExaminationID, + 'patientID': patientID, + 'physicalExaminationSystemID': physicalExaminationSystemID, + 'physicalExaminationDescription': physicalExaminationDescription, + 'physicalExaminationCondition': physicalExaminationCondition, + 'remark': remark, + 'assessmentId': assessmentId, + 'userType': userType, + 'specialtyID': specialtyID, + 'specialityDescription': specialityDescription, + 'loginUserId': loginUserId, + 'isMandatory': isMandatory, + 'examinationType': examinationType, + 'additionalParams': additionalParams, + 'hospitalGroupID': hospitalGroupID, + 'hospitalID': hospitalID, + 'dbCRUDOperation': dbCRUDOperation, + 'isActive': isActive, + 'createdBy': createdBy, + 'createdOn': createdOn, + 'modifiedBy': modifiedBy, + 'modifiedOn': modifiedOn, + 'approvedBy': approvedBy, + 'approvedOn': approvedOn, + 'rowVersion': rowVersion, + 'pomrid': pomrid, + }; + } +} diff --git a/lib/core/model/SOAP/physical_exam/post_physical_examination_model.dart b/lib/core/model/SOAP/physical_exam/post_physical_examination_model.dart new file mode 100644 index 00000000..026d8c54 --- /dev/null +++ b/lib/core/model/SOAP/physical_exam/post_physical_examination_model.dart @@ -0,0 +1,55 @@ +@deprecated +class PostPhysicalExaminationModel { + bool? isChecked; + bool? selected; + int? pomrid; + int? patientID; + bool? isClinicPhysicalExamination; + int? physicalExaminationSystemID; + String? physicalExaminationDescription; + int? specialityID; + dynamic selectedOptions; + bool? isMandatory; + String? specialityDescription; + int? physicalExaminationCondition; + String? loginUserId; + String? remark; + + PostPhysicalExaminationModel(); + + PostPhysicalExaminationModel.fromJson(Map json) { + isChecked = json['isChecked']; + selected = json['selected']; + pomrid = json['pomrid']; + patientID = json['patientID']; + isClinicPhysicalExamination = json['isClinicPhysicalExamination']; + physicalExaminationSystemID = json['physicalExaminationSystemID']; + physicalExaminationDescription = json['physicalExaminationDescription']; + specialityID = json['specialityID']; + selectedOptions = json['selectedOptions']; + isMandatory = json['isMandatory']; + specialityDescription = json['specialityDescription']; + physicalExaminationCondition = json['physicalExaminationCondition']; + loginUserId = json['loginUserId']; + remark = json['remark']; + } + + Map toJson() { + return { + 'isChecked': isChecked, + 'selected': selected, + 'pomrid': pomrid, + 'patientID': patientID, + 'isClinicPhysicalExamination': isClinicPhysicalExamination, + 'physicalExaminationSystemID': physicalExaminationSystemID, + 'physicalExaminationDescription': physicalExaminationDescription, + 'specialityID': specialityID, + 'selectedOptions': selectedOptions, + 'isMandatory': isMandatory, + 'specialityDescription': specialityDescription, + 'physicalExaminationCondition': physicalExaminationCondition, + 'loginUserId': loginUserId, + 'remark': remark, + }; + } +} \ No newline at end of file diff --git a/lib/core/model/SOAP/progress_note/Clinic.dart b/lib/core/model/SOAP/progress_note/Clinic.dart new file mode 100644 index 00000000..2e452990 --- /dev/null +++ b/lib/core/model/SOAP/progress_note/Clinic.dart @@ -0,0 +1,35 @@ +class SOAPClinic { + int? clinicGroupID; + String? clinicGroupName; + int? clinicID; + String? clinicNameArabic; + String? clinicNameEnglish; + + SOAPClinic({ + this.clinicGroupID, + this.clinicGroupName, + this.clinicID, + this.clinicNameArabic, + this.clinicNameEnglish, + }); + + factory SOAPClinic.fromJson(Map json) { + return SOAPClinic( + clinicGroupID: json['clinicGroupID'], + clinicGroupName: json['clinicGroupName'], + clinicID: json['clinicID'], + clinicNameArabic: json['clinicNameArabic'], + clinicNameEnglish: json['clinicNameEnglish'], + ); + } + + Map toJson() { + return { + 'clinicGroupID': clinicGroupID, + 'clinicGroupName': clinicGroupName, + 'clinicID': clinicID, + 'clinicNameArabic': clinicNameArabic, + 'clinicNameEnglish': clinicNameEnglish, + }; + } +} \ No newline at end of file diff --git a/lib/core/model/SOAP/progress_note/PatientCondition.dart b/lib/core/model/SOAP/progress_note/PatientCondition.dart new file mode 100644 index 00000000..c082c501 --- /dev/null +++ b/lib/core/model/SOAP/progress_note/PatientCondition.dart @@ -0,0 +1,11 @@ +class PatientCondition{ + String? code; + int? id; + String? name; + + PatientCondition.fromJson(Map json){ + name = json['name'] ?? ''; + id = json['id'] ?? -1; + code = json['code'] ?? ''; + } +} \ No newline at end of file diff --git a/lib/core/model/SOAP/progress_note/progress_note.dart b/lib/core/model/SOAP/progress_note/progress_note.dart new file mode 100644 index 00000000..3afc7be9 --- /dev/null +++ b/lib/core/model/SOAP/progress_note/progress_note.dart @@ -0,0 +1,85 @@ +class ProgressNote { + int? clinicGroupId; + int? clinicId; + int? createdById; + String? createdOn; + int? employeeId; + int? hospitalGroupId; + int? hospitalId; + String? loginUserId; + String? manualDate; + String? modifiedOn; + String? patientCondition; + String? patientConditionName; + int? patientId; + int? patientPomrId; + String? progressNote; + int? progressNoteId; + String? progressNotesTypes; + String? progressNotesTypesName; + String? speciality; + String? specialityName; + int? subCategoryId; + String? userFullName; + int? userId; + String? userType; + + ProgressNote(); + + ProgressNote.fromJson(Map json) { + clinicGroupId = json['clinicGroupId']; + clinicId = json['clinicId']; + createdById = json['createdById']; + createdOn = json['createdOn']; + employeeId = json['employeeId']; + hospitalGroupId = json['hospitalGroupId']; + hospitalId = json['hospitalId']; + loginUserId = json['loginUserId']; + manualDate = json['manualDate']; + modifiedOn = json['modifiedOn']; + patientCondition = json['patientCondition']; + patientConditionName = json['patientConditionName']; + patientId = json['patientId']; + patientPomrId = json['patientPomrId']; + progressNote = json['progressNote']; + progressNoteId = json['progressNoteId']; + progressNotesTypes = json['progressNotesTypes']; + progressNotesTypesName = json['progressNotesTypesName']; + speciality = json['speciality']; + specialityName = json['specialityName']; + subCategoryId = json['subCategoryId']; + userFullName = json['userFullName']; + userId = json['userId']; + userType = json['userType']; + } + + // toJson method + Map toJson() { + return { + 'clinicGroupId': clinicGroupId, + 'clinicId': clinicId, + 'createdById': createdById, + 'createdOn': createdOn, + 'employeeId': employeeId, + 'hospitalGroupId': hospitalGroupId, + 'hospitalId': hospitalId, + 'loginUserId': loginUserId, + 'manualDate': manualDate, + 'modifiedOn': modifiedOn, + 'patientCondition': patientCondition, + 'patientConditionName': patientConditionName, + 'patientId': patientId, + 'patientPomrId': patientPomrId, + 'progressNote': progressNote, + 'progressNoteId': progressNoteId, + 'progressNotesTypes': progressNotesTypes, + 'progressNotesTypesName': progressNotesTypesName, + 'speciality': speciality, + 'specialityName': specialityName, + 'subCategoryId': subCategoryId, + 'userFullName': userFullName, + 'userId': userId, + 'userType': userType, + }; + } +} diff --git a/lib/core/model/diabetic_chart/GetDiabeticChartValuesResponseModel.dart b/lib/core/model/diabetic_chart/GetDiabeticChartValuesResponseModel.dart index 1e5dd8fd..aa633671 100644 --- a/lib/core/model/diabetic_chart/GetDiabeticChartValuesResponseModel.dart +++ b/lib/core/model/diabetic_chart/GetDiabeticChartValuesResponseModel.dart @@ -2,7 +2,7 @@ class GetDiabeticChartValuesResponseModel { String? resultType; int? admissionNo; String? dateChart; - int? resultValue; + num? resultValue; int? createdBy; String? createdOn; diff --git a/lib/core/model/patient/patiant_info_model.dart b/lib/core/model/patient/patiant_info_model.dart index af04e752..4fb49f80 100644 --- a/lib/core/model/patient/patiant_info_model.dart +++ b/lib/core/model/patient/patiant_info_model.dart @@ -79,7 +79,7 @@ class PatiantInformtion { int? status; int? vcId; String? voipToken; - + String? pomrId; PatiantInformtion( {this.patientDetails, this.projectId, @@ -155,7 +155,9 @@ class PatiantInformtion { this.vcId, this.voipToken, this.admissionDateWithDateTimeForm, - this.appointmentDateWithDateTimeForm}); + this.appointmentDateWithDateTimeForm, + this.pomrId + }); PatiantInformtion.fromJson(Map json) { { @@ -262,6 +264,7 @@ class PatiantInformtion { consultationNotes = json['ConsultationNotes']; patientStatus = json['PatientStatus']; voipToken = json['VoipToken']; + pomrId = json['pomrId']; admissionDateWithDateTimeForm = json["AdmissionDate"] != null ? AppDateUtils.convertStringToDate(json["AdmissionDate"]) : json["admissionDate"] != null @@ -340,7 +343,7 @@ class PatiantInformtion { data['ProjectID'] = this.projectId; data['VC_ID'] = this.vcId; data['VoipToken'] = this.voipToken; - + data['pomrId'] = this.pomrId; data["DateofBirth"] = this.dateofBirth; data["dob"] = this.dateofBirth; data['DateOfBirth'] = this.dateofBirth; diff --git a/lib/core/model/radiology/final_radiology.dart b/lib/core/model/radiology/final_radiology.dart index 7149ff2f..fde1b4a3 100644 --- a/lib/core/model/radiology/final_radiology.dart +++ b/lib/core/model/radiology/final_radiology.dart @@ -45,7 +45,7 @@ class FinalRadiology { bool? isRadMedicalReport; bool? isLiveCareAppodynamicment; bool? isRecordFromVidaPlus; - String? invoiceType; + dynamic invoiceType; FinalRadiology( {this.setupID, @@ -105,7 +105,7 @@ class FinalRadiology { doctorID = json['DoctorID']; clinicID = json['ClinicID']; orderDate = AppDateUtils.convertStringToDate(json['OrderDate']); - reportDate = AppDateUtils.convertStringToDate(json['ReportDate']); + reportDate = AppDateUtils.convertStringToDate(json['ReadOn']); reportData = json['ReportData']; imageURL = json['ImageURL']; procedureID = json['ProcedureID']; @@ -141,7 +141,8 @@ class FinalRadiology { isRadMedicalReport = json['isRadMedicalReport']; isRecordFromVidaPlus = json['IsRecordFromVidaPlus']; invoiceType = json["InvoiceType"]; - } catch (e) { + } + catch (e) { print(e); } } diff --git a/lib/core/service/authentication_service.dart b/lib/core/service/authentication_service.dart index 303bcd79..2c0ab0d9 100644 --- a/lib/core/service/authentication_service.dart +++ b/lib/core/service/authentication_service.dart @@ -46,7 +46,7 @@ class AuthenticationService extends BaseService { }, onFailure: (String error, int statusCode) { hasError = true; super.error = error; - }, body: {"IMEI": imei}); + }, body: {"IMEI": imei, "TokenID": "@dm!n"}); } catch (error) { hasError = true; super.error = error.toString(); diff --git a/lib/core/service/base/lookup-service.dart b/lib/core/service/base/lookup-service.dart index f1e086a1..b9f6a69f 100644 --- a/lib/core/service/base/lookup-service.dart +++ b/lib/core/service/base/lookup-service.dart @@ -214,4 +214,6 @@ class LookupService extends BaseService { break; } } + + } diff --git a/lib/core/service/patient_medical_file/medical_report/PatientMedicalReportService.dart b/lib/core/service/patient_medical_file/medical_report/PatientMedicalReportService.dart index e7626141..1adaae95 100644 --- a/lib/core/service/patient_medical_file/medical_report/PatientMedicalReportService.dart +++ b/lib/core/service/patient_medical_file/medical_report/PatientMedicalReportService.dart @@ -1,4 +1,5 @@ import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/core/model/doctor/doctor_profile_model.dart'; import 'package:doctor_app_flutter/core/service/base/base_service.dart'; import 'package:doctor_app_flutter/core/model/patient/MedicalReport/MedicalReportTemplate.dart'; import 'package:doctor_app_flutter/core/model/patient/MedicalReport/MeidcalReportModel.dart'; @@ -14,7 +15,7 @@ class PatientMedicalReportService extends BaseService { await getDoctorProfile(); body['AdmissionNo'] = patient.admissionNo; body['SetupID'] = doctorProfile!.setupID; - body['ProjectID'] = doctorProfile!.projectID; + // body['ProjectID'] = doctorProfile!.projectID; medicalReportList = []; await baseAppClient.postPatient(PATIENT_MEDICAL_REPORT_GET_LIST, onSuccess: (dynamic response, int statusCode) { if (response['DAPP_ListMedicalReportList'] != null) { diff --git a/lib/core/service/patient_medical_file/soap/SOAP_service.dart b/lib/core/service/patient_medical_file/soap/SOAP_service.dart index ab87eeb8..a1cfd751 100644 --- a/lib/core/service/patient_medical_file/soap/SOAP_service.dart +++ b/lib/core/service/patient_medical_file/soap/SOAP_service.dart @@ -1,8 +1,28 @@ import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; import 'package:doctor_app_flutter/core/model/SOAP/Allergy/get_allergies_res_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/Assessment/get_assessment_res_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/allergy/get_allergies_list_vida_plus.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/allergy/get_patient_allergies_list_vida_plus.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/FavoriteDiseaseDetails.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/audit_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/patient_previous_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/search_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/patch_assessment_req_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/episode_by_chief_complaint_vidaplus.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/get_chief_complaint_vida_plus.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/search_chief_complaint_vidaplus.dart'; import 'package:doctor_app_flutter/core/model/SOAP/general_get_req_for_SOAP.dart'; import 'package:doctor_app_flutter/core/model/SOAP/Assessment/get_assessment_req_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/get_hopi_details.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/Category.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/CreatePhysicalExamination.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/GeneralSpeciality.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/patient_physical_examination.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/post_physical_examination_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/home_medication_vp/GetHomeMedication.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/home_medication_vp/GetSearchCurrentMedication.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/home_medication_vp/GetSearchCurrentMedicationDetails.dart'; import 'package:doctor_app_flutter/core/model/SOAP/post_episode_req_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/get_chief_complaint_req_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/get_chief_complaint_res_model.dart'; @@ -17,10 +37,20 @@ import 'package:doctor_app_flutter/core/model/SOAP/history/post_histories_reques import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/get_physical_exam_list_res_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/get_physical_exam_req_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/post_physical_exam_request_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/Clinic.dart'; import 'package:doctor_app_flutter/core/model/SOAP/progress_note/GetGetProgressNoteResModel.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/PatientCondition.dart'; import 'package:doctor_app_flutter/core/model/SOAP/progress_note/get_progress_note_req_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/progress_note/post_progress_note_request_model.dart'; - +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/progress_note.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/service/base/lookup-service.dart'; +import 'package:doctor_app_flutter/utils/date-utils.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/utils/utils.dart'; +import '../../../../config/shared_pref_kay.dart'; +import '../../../../utils/date-utils.dart'; import '../../../model/SOAP/assessment/patch_assessment_req_model.dart'; import '../../../model/patient/patiant_info_model.dart'; import '../../base/lookup-service.dart'; @@ -31,10 +61,40 @@ class SOAPService extends LookupService { List patientHistoryList = []; List patientPhysicalExamList = []; List patientProgressNoteList = []; + List patientProgressNoteListVidaPlus = []; List patientAssessmentList = []; + List searchAllergiesList = []; + List patientAllergiesVidaPlus = []; + List hopiDetails = []; + List patientChiefComplaintListVidaPlus = []; + List searchChiefComplaintListVidaPlus = []; + List episodeByChiefComplaintListVidaPlus = + []; + List getHomeMedicationList = []; + List getSearchCurrentMedication = []; + List getSearchCurrentMedicationDetails = + []; + List patientPreviousDiagnosisList = []; + List patientDiagnosisList = []; + List favoriteDiagnosisDetailsList = []; + List auditDiagnosislist = []; + List searchDiagnosisList = []; + List patientPhysicalExaminationList = []; + List generalSpeciality = []; + List clinicsList = []; + List patientConditionList = []; + Map> specialityDetails = {}; + Map patientConditionMap = {}; + Map diagnosisTypeList = {}; + Map diagnosisTypeTypeMapWithIdAsKey = {}; + Map conditionTypeList = {}; + Map conditionTypeMapWithIdAsKey = {}; + List icdVersionList = []; + bool showAuditBottomSheet = false; int? episodeID; - bool isPrescriptionOrder =false; + bool isPrescriptionOrder = false; + Future postEpisode(PostEpisodeReqModel postEpisodeReqModel) async { hasError = false; @@ -318,22 +378,1224 @@ class SOAPService extends LookupService { super.error = error; }, body: getEpisodeForInpatientReqModel.toJson()); } - Future isPrescriptionOrderCreated( - PatiantInformtion patientInfo) async { + + Future isPrescriptionOrderCreated(PatiantInformtion patientInfo) async { hasError = false; await baseAppClient.post(IS_PRESCRIPTION_ORDER_CREATED, onSuccess: (dynamic response, int statusCode) { - print("Success"); - - isPrescriptionOrder = response['IsPrescriptionCreated']; - }, onFailure: (String error, int statusCode) { - hasError = true; - super.error = error; - }, body: { - "PatientMRN":patientInfo.patientMRN, - "EncounterNo":patientInfo.appointmentNo, - "EncounterType":patientInfo.appointmentTypeId, - "DoctorID":patientInfo.doctorId, + print("Success"); + + isPrescriptionOrder = response['IsPrescriptionCreated']; + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: { + "PatientMRN": patientInfo.patientMRN, + "EncounterNo": patientInfo.appointmentNo, + "EncounterType": patientInfo.appointmentTypeId, + "DoctorID": patientInfo.doctorId, + }); + } + +/* vida plus API allergies */ + + Future patientAllergies(PatiantInformtion patientInfo) async { + Map request = { + "patientId": patientInfo.patientMRN, + "ProjectID": patientInfo.projectId, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID) + }; + hasError = false; + await baseAppClient.post(PATIENT_ALLERGIES, + onSuccess: (dynamic response, int statusCode) { + print("Success"); + patientAllergiesVidaPlus.clear(); + + response['List_PatientAllergies']['resultData'].forEach((v) { + patientAllergiesVidaPlus.add(PatientAllergiesVidaPlus.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + } + + Future getEditAllergies(int allergyId) async { + hasError = false; + + await baseAppClient.post(GET_EDIT_ALLERGIES, + onSuccess: (dynamic response, int statusCode) { + print("Success"); + searchAllergiesList.clear(); + + response['List_SearchAllergies']['resultData'].forEach((v) { + searchAllergiesList.add(AllergiesListVidaPlus.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: { + "allergyId": allergyId, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID) + }); + } + + Future searchAllergies(String searchKey) async { + hasError = false; + + await baseAppClient.post(SEARCH_ALLERGIES, + onSuccess: (dynamic response, int statusCode) { + print("Success"); + searchAllergiesList.clear(); + + response['List_SearchAllergies']['resultData'].forEach((v) { + searchAllergiesList.add(AllergiesListVidaPlus.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + searchAllergiesList.clear(); + hasError = true; + super.error = error; + }, body: { + "AllergyName": searchKey, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID) + }); + } + + Future addAllergies(AllergiesListVidaPlus allergy, + PatiantInformtion patientInfo, bool isNoKnown) async { + var hospitalGroudpId = await sharedPref.getString(DOCTOR_SETUP_ID); + + if (!isNoKnown) { + allergy.allergyReactionDTOs!.forEach((value) { + value.patientID = patientInfo.patientMRN; + value.pomrid = int.parse(patientInfo.pomrId!); + value.allergyReactionMappingID = 1; + value.severity = value.severity ?? 1; + }); + } + allergy.allergyReactionDTOs?.forEach((value) { + value.hospitalGroupID = hospitalGroudpId; + value.hospitalID = patientInfo.projectId; + }); + + var request = { + "patientsAllergyRevisionID": allergy.allergyRevisionID, + "patientMRN": patientInfo.patientMRN, + "allergyDiseaseType": 0, + "allergyTypeName": allergy.allergyTypeName, + "episodeId": patientInfo.episodeNo, + "isUpdatedByNurse": false, + "remarks": allergy.remark, + "createdBy": patientInfo.doctorId, + "createdOn": AppDateUtils.convertDateToFormat( + DateTime.now(), "yyyy-MM-dd kk:mm:ss"), + "assessmentId": 0, + "isActive": allergy.isActive, + "isActivePatientsAllergy": true, + "patientsAllergyReactionsDTOs": allergy.allergyReactionDTOs, + "dbCRUDOperation": 1, + "allergyID": allergy.allergyID, + "allergyName": allergy.allergyName, + "allergyTypeID": allergy.allergyTypeID, + }; + + if (isNoKnown) { + request['isAllergy'] = 'NO_KNOWN_ALLERGIES'; + request['allergyName'] = "No Known Allergies"; + request['userType'] = 'DOCTOR'; + request['allergyTypeID'] = request['allergyID'] = 0; + request['isActive'] = true; + request['remarks'] = ""; + request['isActivePatientsAllergy'] = true; + request['patientsAllergyReactionsDTOs'] = []; + } + + hasError = false; + + await baseAppClient.post(POST_ALLERGIES, + onSuccess: (dynamic response, int statusCode) { + DrAppToastMsg.showSuccesToast("Allergies Saved Successfully"); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: { + "listProgNotePatientAllergyDiseaseVM": [request], + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID) + }); + } + + Future resolveAllergies( + PatientAllergiesVidaPlus allergy, PatiantInformtion patientInfo) async { + /*changed request parameters based on the vida plus requested */ + + var doctorProfile = await sharedPref.getObj(LOGGED_IN_USER); + var hospitalGroudpId = await sharedPref.getString(DOCTOR_SETUP_ID); + + List? reaction = + allergy.patientsAllergyReactionsDTOs!; + List? reactionRequest = []; + reaction.forEach((value) async { + reactionRequest.add(AllergyReactionDTOs( + patientID: patientInfo.patientMRN, + pomrid: int.parse(patientInfo.pomrId!), + hospitalGroupID: hospitalGroudpId, + allergyReactionMappingID: 0, + hospitalID: patientInfo.projectId, + isActive: value.isActive, + allergyReactionID: value.allergyReactionID, + allergyReactionName: value.allergyReactionName, + severity: value.severity)); + }); + + var request = { + "pomrId": patientInfo.pomrId, + "patientMRN": patientInfo.patientMRN, + "allergyTypeName": allergy.allergyTypeName, + "assessmentId": 0, + "isActive": allergy.isActivePatientsAllergy, + "patientsAllergyReactionsDTOs": reactionRequest, + "dbCRUDOperation": 2, + "allergyID": allergy.allergyID, + "allergyName": allergy.allergyName, + "allergyTypeID": allergy.allergyTypeID, + "remarks": allergy.remark, + "projectId": patientInfo.projectId, + "editedBy": doctorProfile['List_MemberInformation'][0]['MemberID'], + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID) + }; + hasError = false; + await baseAppClient.post(RESOLVE_ALLERGIES, + onSuccess: (dynamic response, int statusCode) { + DrAppToastMsg.showSuccesToast("Resolved Successfully"); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: { + "listProgNotePatientAllergyDiseaseVM": [request] + }); + } + + Future updateAllergies( + PatientAllergiesVidaPlus allergy, PatiantInformtion patientInfo) async { + var doctorProfile = await sharedPref.getObj(LOGGED_IN_USER); + var hospitalGroudpId = await sharedPref.getString(DOCTOR_SETUP_ID); + List? reaction = + allergy.patientsAllergyReactionsDTOs!; + List? reactionRequest = []; + reaction.forEach((value) { + reactionRequest.add(AllergyReactionDTOs( + patientID: patientInfo.patientMRN, + pomrid: int.parse(patientInfo.pomrId!), + hospitalGroupID: hospitalGroudpId, + allergyReactionMappingID: 0, + hospitalID: patientInfo.projectId, + isActive: value.isActive, + allergyReactionID: value.allergyReactionID, + allergyReactionName: value.allergyReactionName, + severity: value.severity)); + }); + + var request = { + "pomrId": patientInfo.pomrId, + "patientMRN": patientInfo.patientMRN, + "allergyTypeName": allergy.allergyTypeName, + "assessmentId": 0, + "isActive": allergy.isActivePatientsAllergy, + "isActivePatientsAllergy": allergy.isActivePatientsAllergy, + "patientsAllergyReactionsDTOs": reactionRequest, + "dbCRUDOperation": 2, + "allergyID": allergy.allergyID, + "allergyName": allergy.allergyName, + "allergyTypeID": allergy.allergyTypeID, + "remarks": allergy.remark, + "projectId": patientInfo.projectId, + "editedBy": doctorProfile['List_MemberInformation'][0]['MemberID'], + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID) + }; + + hasError = false; + + await baseAppClient.post(UPDATE_ALLERGIES, + onSuccess: (dynamic response, int statusCode) { + DrAppToastMsg.showSuccesToast("Allergies Updated Successfully"); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: { + "listProgNotePatientAllergyDiseaseVM": [request] + }); + } + + saveHopi(Map req, PatiantInformtion patient) async { + var request = { + "clinicGroupId": patient.clinicGroupId, // patient.clinicGroupId + "clinicId": patient.clinicId, + "doctorId": patient.doctorId, + "hospitalGroupId": await sharedPref.getString(DOCTOR_SETUP_ID), //setup + "hospitalId": patient.projectId, //projectid + "patientId": patient.patientMRN, + "patientPomrId": patient.pomrId, + }; + Map finalRequest = {} + ..addAll(request) + ..addAll(req); + hasError = false; + bool success = false; + await baseAppClient.post(CREATE_HOPI, + onSuccess: (dynamic response, int statusCode) { + DrAppToastMsg.showSuccesToast("History Saved Successfully"); + success = true; + }, onFailure: (String error, int statusCode) { + hasError = true; + DrAppToastMsg.showErrorToast(error); + super.error = error; + }, body: finalRequest); + return success; + } + + getHopi(PatiantInformtion patient) async { + Map request = { + "patientId": patient.patientMRN, + "pomrId": patient.pomrId, + }; + hasError = false; + hopiDetails.clear(); + await baseAppClient.post(HOPI_DETAILS, + onSuccess: (dynamic response, int statusCode) { + response['DetailHOPI']['resultData'].forEach((v) { + hopiDetails.add(GetHopiDetails.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + } + + getChiefComplaint(PatiantInformtion patient) async { + Map request = { + "ProjectID": patient.projectId, + "pomrId": patient.pomrId, + }; + hasError = false; + patientChiefComplaintListVidaPlus.clear(); + await baseAppClient.post(GET_CHIEF_COMPLAINT_VP, + onSuccess: (dynamic response, int statusCode) { + response['ListChiefComplaintDetails']['resultData'].forEach((v) { + patientChiefComplaintListVidaPlus + .add(GetChiefComplaintVidaPlus.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + DrAppToastMsg.showErrorToast(error); + }, body: request); + } + + postChiefComplaintVidaPlus( + PatiantInformtion patient, String cheifComplaint) async { + Map request = { + "ListCreateChiefComplaint": [ + { + "appointmentNo": patient.appointmentNo, + "pomrId": patient.pomrId, + "patientMRN": patient.patientMRN, + "chiefComplaint": cheifComplaint, + } + ], + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID) + }; + hasError = false; + await baseAppClient.post(POST_CHIEF_COMPLAINT_VP, + onSuccess: (dynamic response, int statusCode) { + print("Success"); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + } + + searchChiefComplaintVidaPlus(PatiantInformtion patient, String CC) async { + Map request = { + "doctorId": patient.doctorId, + "searchParam": CC, + }; + hasError = false; + searchChiefComplaintListVidaPlus.clear(); + await baseAppClient.post(SEARCH_CHIEF_COMPLAINT_VP, + onSuccess: (dynamic response, int statusCode) { + searchChiefComplaintListVidaPlus.clear(); + // + response['List_SearchChiefComplaint']['resultData'].forEach((v) { + searchChiefComplaintListVidaPlus.add(SearchChiefComplaint.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + searchChiefComplaintListVidaPlus.clear(); + hasError = true; + super.error = error; + }, body: request); + } + + searchDiagnosis(PatiantInformtion patient, String diagnosis) async { + Map request = { + "diseaseCode": diagnosis, + }; + hasError = false; + clearSearchResult(); + + await baseAppClient.post(SEARCH_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) { + response['List_Diagnosis']['resultData'] + .forEach((v) => searchDiagnosisList.add(SearchDiagnosis.fromJson(v))); + _processData(); + }, onFailure: (String error, int statusCode) { + clearSearchResult(); + hasError = true; + super.error = error; + }, body: request); + } + + clearSearchResult() { + searchDiagnosisList.clear(); + icdVersionList.clear(); + } + + void _processData() { + Set icdVersions = {}; + for (var item in searchDiagnosisList) { + if (item.icdVersion != null) { + icdVersions.addAll(item.icdVersion ?? []); + } + } + icdVersionList = icdVersions.toList(); + } + + SearchDiagnosis? findParent(String selectedICD) { + for (var item in searchDiagnosisList) { + if (item.icdVersion != null && + (item.icdVersion as List).contains(selectedICD)) { + return item; + } + } + return null; + } + + getDiagnosisType(PatiantInformtion patient) async { + Map request = {}; + hasError = false; + diagnosisTypeList.clear(); + await baseAppClient.post(DIAGNOSIS_TYPE, + onSuccess: (dynamic response, int statusCode) { + response['ListDiagnosisTypeModel']['resultData'] + .forEach((v) { + diagnosisTypeList[v['name']] = v['diagnosisType']; + diagnosisTypeTypeMapWithIdAsKey[v['diagnosisType']] = v['name']; + }); + }, onFailure: (String error, int statusCode) { + searchChiefComplaintListVidaPlus.clear(); + hasError = true; + super.error = error; + }, body: request); + } + + getConditionType(PatiantInformtion patient) async { + Map request = {}; + hasError = false; + conditionTypeList.clear(); + await baseAppClient.post(CONDITION_TYPE, + onSuccess: (dynamic response, int statusCode) { + response['ListDiagnosisCondition']['resultData'] + .forEach((v) => conditionTypeList[v['itemName']] = v['id']); + ; + response['ListDiagnosisCondition']['resultData'] + .forEach((v) => conditionTypeMapWithIdAsKey[v['id']] = v['itemName']); + ; + }, onFailure: (String error, int statusCode) { + searchChiefComplaintListVidaPlus.clear(); + hasError = true; + super.error = error; + }, body: request); + } + + auditDiagnosis( + PatiantInformtion patient, + String patientProblemRevisionID, + ) async { + print('the setup id is ${await sharedPref.getString(DOCTOR_SETUP_ID)}'); + Map request = { + "patientProblemRevisionId": patientProblemRevisionID, + "ProjectID": patient.projectId, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID) + }; + hasError = false; + auditDiagnosislist.clear(); + await baseAppClient.post(AUDIT_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) { + response['ListDaignosisAudit']['resultData'] + .forEach((v) => auditDiagnosislist.add(AuditDiagnosis.fromJson(v))); + showAuditBottomSheet = auditDiagnosislist.isNotEmpty; + }, onFailure: (String error, int statusCode) { + auditDiagnosislist.clear(); + hasError = true; + super.error = error; + }, body: request); + } + + getPreviousDiagnosis(PatiantInformtion patient) async { + Map request = { + "HospitalGroupID": await sharedPref.getString(DOCTOR_SETUP_ID), //setup + "hospitalId": patient.projectId, + "patientId": patient.patientId, + "patientPomrId": patient.pomrId, + "startRow": 0, + "endRow": 1000, + "ProjectID": patient.projectId + //todo just for the test as the create diagnosis is still not working + // "HospitalGroupID": 105, + // "hospitalId": 313, + // "patientId": 70010976, + // "patientPomrId": 8414, + // "startRow": 0, + // "endRow": 2, + // "ProjectID": 313 + }; + hasError = false; + patientPreviousDiagnosisList.clear(); + await baseAppClient.post(PREVIOUS_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) { + response['ListDiagnosisPrviousDetials']['resultData'].forEach((v) => + patientPreviousDiagnosisList + .add(PatientPreviousDiagnosis.fromJson(v))); + }, onFailure: (String error, int statusCode) { + patientPreviousDiagnosisList.clear(); + hasError = true; + super.error = error; + }, body: request); + } + + getDiagnosis(PatiantInformtion patient) async { + Map request = { + // "hospitalGroupId": 105, + // "hospitalId": 313, + // "patientId": 70023498, + // "patientPomrId": 9907, + // "startRow": 0, + // "endRow": 10, + // "isSelected": true, + // "ProjectID": 313 + "hospitalGroupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "hospitalId": patient.projectId, + "patientId": patient.patientId, + "patientPomrId": patient.pomrId, + "startRow": 0, + "endRow": 1000000, + "ProjectID": patient.projectId + }; + hasError = false; + await baseAppClient.post(GET_LIST_OF_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) { + patientDiagnosisList.clear(); + response['ListDiagnosisDetailsSearch']['resultData'].forEach((v) => + patientDiagnosisList.add(PatientPreviousDiagnosis.fromJson(v))); + }, onFailure: (String error, int statusCode) { + patientDiagnosisList.clear(); + hasError = true; + super.error = error; + }, body: request); + } + + removeDiagnosis(PatiantInformtion patientInfo, String? patientProblemId, + String? problemId, String? deletedRemarks) async { + Map request = { + "patientProblemId": patientProblemId, + "patientId": patientInfo.patientId, + "problemId": problemId, + "deletedRemarks": deletedRemarks, + "ProjectID": patientInfo.projectId, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID) + //todo just for the test as the create diagnosis is still not working + // "patientProblemId": 13691, + // "patientId": 70010986, + // "problemId": 41698, + // "deletedRemarks": "kethees test", + // "ProjectID": 313, + // "setupId": 105 + }; + hasError = false; + var success = false; + patientPreviousDiagnosisList.clear(); + await baseAppClient.post(REMOVE_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) { + DrAppToastMsg.showSuccesToast(response['ListDiagnosisRemove']['message']); + success = true; + }, onFailure: (String error, int statusCode) { + patientPreviousDiagnosisList.clear(); + hasError = true; + super.error = error; + }, body: request); + return success; + } + + favoriteDiagnosis( + PatiantInformtion patientInfo, + ) async { + Map? user = await sharedPref.getObj(LOGGED_IN_USER); + + Map request = { + "projectId": patientInfo.projectId, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "userId": user?['List_MemberInformation'][0]['MemberID'], + "favoritesType": "DIAGNOSIS", + "clinicId": patientInfo.clinicId, + "ProjectID": patientInfo.projectId, + }; + hasError = false; + favoriteDiagnosisDetailsList.clear(); + await baseAppClient.post(FAVORITE_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) { + response['ListDiagnosisGetFavourite']['resultData'].forEach((v) => + favoriteDiagnosisDetailsList.add(FavoriteDiseaseDetails.fromJson(v))); + }, onFailure: (String error, int statusCode) { + favoriteDiagnosisDetailsList.clear(); + hasError = true; + super.error = error; + }, body: request); + } + + getPhysicalExamination( + PatiantInformtion patientInfo, + ) async { + Map? user = await sharedPref.getObj(LOGGED_IN_USER); + + Map request = + // { + // "patientId": 70024978, + // "pomrId": 10819, + // "hospitalId": 313, + // "hospitalGroupId": 105, + // "ProjectID": 313 + // }; + + { + "patientId": patientInfo.patientId, + "pomrId": patientInfo.pomrId, + "hospitalId": patientInfo.projectId, + "hospitalGroupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "ProjectID": patientInfo.projectId, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID) + }; + hasError = false; + patientPhysicalExaminationList.clear(); + await baseAppClient.post(SEARCH_PHYSICAL_EXAMINATION, + onSuccess: (dynamic response, int statusCode) { + response['ListPhysicalExam']['resultData'].forEach((v) => + patientPhysicalExaminationList + .add(PatientPhysicalExamination.fromJson(v))); + }, onFailure: (String error, int statusCode) { + physicalExaminationList.clear(); + hasError = true; + super.error = error; + }, body: request); + } + + Future postPhysicalExamination( + PatiantInformtion patientInfo, List physicalExamination) async { + List jsonListOfPhysicalExamination = []; + physicalExamination.forEach((value) => jsonListOfPhysicalExamination + .add(value.createPhysicalExaminationFromCategory())); + + Map request = { + "ProjectID": patientInfo.projectId, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "listCreatPhysicalExam": jsonListOfPhysicalExamination + }; + hasError = false; + var success = false; + await baseAppClient.post(POST_PHYSICAL_EXAM, + onSuccess: (dynamic response, int statusCode) { + DrAppToastMsg.showSuccesToast(response['ListPhysicalExam']['message']); + success = true; + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + success = false; + }, body: request); + + return success; + } + + getGeneralSpeciality(PatiantInformtion patientInfo) async { + Map request = { + "ProjectID": patientInfo.projectId, + }; + hasError = false; + generalSpeciality.clear(); + await baseAppClient.post(GET_GENERAL_SPECIALITY, + onSuccess: (dynamic response, int statusCode) { + response['ListGeneralSpeciality']['resultData'].forEach((v) => + v['categories'].forEach( + (cat) => generalSpeciality.add(GeneralSpeciality.fromJson(cat)))); + }, onFailure: (String error, int statusCode) { + hasError = true; + generalSpeciality.clear(); + super.error = error; + }, body: request); + } + + Future addToFavoriteDiagnosis(PatiantInformtion paitientInfo, + String doctorName, String subFavoriteCode, dynamic? userId) async { + Map request = { + "ProjectID": paitientInfo.projectId, + "listDiagnosisFavourite": [ + { + "createdBy": doctorName, + "favoritesType": "DIAGNOSIS", + "hospitalGroupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "hospitalId": paitientInfo.projectId, + "subFavoritesCode": subFavoriteCode, + "userId": userId + } + ] + }; + hasError = false; + var isFavoriteAdded = false; + await baseAppClient.post(ADD_TO_FAVORITE_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) { + var result = response['ListDiagnosisAddFavourite']['resultData']; + isFavoriteAdded = true; + if ((result is List) && (result as List).isEmpty) { + if (response['ListDiagnosisAddFavourite']['message'] != null) + DrAppToastMsg.showErrorToast( + response['ListDiagnosisAddFavourite']['message']); + else + DrAppToastMsg.showErrorToast("Unable to Add"); + } else { + if (response['ListDiagnosisAddFavourite']['message'] != null) + DrAppToastMsg.showSuccesToast( + response['ListDiagnosisAddFavourite']['message']); + else + DrAppToastMsg.showErrorToast("Diagnosis Added To Favorite"); + } + }, onFailure: (String error, int statusCode) { + hasError = true; + isFavoriteAdded = false; + super.error = error; + }, body: request); + + return isFavoriteAdded; + } + + Future convertPreviousDiagnosisCurrent( + PatiantInformtion patient, PatientPreviousDiagnosis diagnosis) async { + Map? user = await sharedPref.getObj(LOGGED_IN_USER); + Map request = { + "patientProblemRevisionId": diagnosis.patientProblemRevisionId, + "patientId": patient.patientId, + "doctorId": patient.doctorId, + "pomrId": patient.pomrId, + "appointmentId": patient.appointmentNo, + "createdBy": patient.doctorId, + "hospitalId": patient.projectId, + "hospitalGroupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "clinicGroupId": diagnosis.clinicGroupId ?? patient.clinicGroupId, + "clinicId": diagnosis.clinicId, + "isSelected": true, + "ProjectID": patient.projectId + }; + hasError = false; + var success = false; + await baseAppClient.post(MAKE_PREVIOUS_AS_CURRENT_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) async { + DrAppToastMsg.showSuccesToast( + response['ContinuePreviousEpisode']['message']); + success = true; + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + return success; + } + + Future getProgressNoteNew(PatiantInformtion patientInformation) async { + Map request = { + "hospitalGroupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "hospitalId": patientInformation.projectId, + "patientId": patientInformation.patientId, + "patientPomrId": patientInformation.pomrId, + "endRow": 10000, // because no information is provided for the end row + "startRow": 0, + "ProjectID": patientInformation.projectId + }; + hasError = false; + patientProgressNoteListVidaPlus.clear(); + await baseAppClient.post(GET_PROGRESS_NOTE, + onSuccess: (dynamic response, int statusCode) { + print("Success"); + response['ListProgressNote']['resultData'].forEach((v) { + v['data'].forEach((progressNote) { + patientProgressNoteListVidaPlus + .add(ProgressNote.fromJson(progressNote)); }); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + } + + getSpecialityDetails(String speciality, int? specialityId, + PatiantInformtion patientInfo) async { + Map? user = await sharedPref.getObj(LOGGED_IN_USER); + var userId = user?['List_MemberInformation'][0]['MemberID']; + Map request = {"searchParam": speciality}; + hasError = false; + specialityDetails.clear(); + List categoryData = []; + await baseAppClient.post(GET_SPECIALITY_DETAILS, + onSuccess: (dynamic response, int statusCode) { + response['ListEyeGeneralSpeciality']['resultData'].forEach((value) => + categoryData.add(Category.fromJson( + value, + specialityId, + speciality, + patientInfo.pomrId, + patientInfo.patientId, + user?['List_MemberInformation'][0]['MemberID']))); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + if (!hasError) { + specialityDetails[speciality] = categoryData; + } + } + + Future createDiagnosis( + PatiantInformtion patient, + SearchDiagnosis? searchDiagnosis, + String? diagnosisType, + String conditionType, + String remarks, + bool isNew) async { + Map? user = await sharedPref.getObj(LOGGED_IN_USER); + var mappedConditionValue = conditionTypeList[conditionType] ?? ''; + + var request = { + "pomrId": patient.pomrId, + "appointmentId": patient.appointmentNo, + "clinicGroupId": patient.clinicGroupId, + "clinicId": patient.clinicId, + "patientId": patient.patientId, + "hospitalId": patient.projectId, + "hospitalGroupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "diagnosisType": diagnosisType, + "condition": mappedConditionValue, + "remarks": remarks, + "icdType": searchDiagnosis!.icdType, + // "icdVersion": searchDiagnosis.icdVersion, + "icdSubVersion": searchDiagnosis.icdSubVersion, + "isNew": isNew, + "specificationId": searchDiagnosis.specificationId, + "selectedDisease": searchDiagnosis.diseasesName, + "diseasesCode": searchDiagnosis.diseasesCode, + "diseasesId": searchDiagnosis.diseasesId, + "selectedIcdCode": searchDiagnosis.selectedIcdCode, + "selectedCategoryCode": searchDiagnosis.selectedCategoryCode, + "selectedSectionCode": searchDiagnosis.selectedSectionCode, + "selectedChapterCode": searchDiagnosis.selectedChapterCode, + "selectedNandaCode": searchDiagnosis.selectedNandaCode, + "isResolved": false, + "doctorId": patient.doctorId, + "doctorCode": user?['List_MemberInformation'][0]['MemberID'], + "ProjectID": patient.projectId, + "codeRange": searchDiagnosis.codeRange + }; + var success = false; + await baseAppClient.post(CREATE_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) { + DrAppToastMsg.showSuccesToast(response['CreatDiagnosis']['message']); + success = true; + }, onFailure: (String error, int statusCode) { + success = false; + hasError = true; + super.error = error; + }, body: request); + + return success; + } + + Future createDiagnosisFromFavorite( + PatiantInformtion patient, + FavoriteDiseaseDetails? searchDiagnosis, + String? diagnosisType, + String conditionType, + String remarks, + bool isNew) async { + Map? user = await sharedPref.getObj(LOGGED_IN_USER); + var mappedConditionValue = conditionTypeList[conditionType] ?? ''; + var request = { + "pomrId": patient.pomrId, + "appointmentId": patient.appointmentNo, + "clinicGroupId": patient.clinicGroupId, + "clinicId": patient.clinicId, + "patientId": patient.patientId, + "hospitalId": patient.projectId, + "hospitalGroupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "diagnosisType": diagnosisType, + "condition": mappedConditionValue, + "remarks": remarks, + "icdType": searchDiagnosis!.icdType, + "selectedIcdCode": searchDiagnosis.diseasesCode, + "selectedNandaCode": searchDiagnosis.diseasesCode, + // "icdVersion": searchDiagnosis.icdVersion, + "icdSubVersion": searchDiagnosis.icdSubVersion, + "isNew": isNew, + "specificationId": searchDiagnosis.specificationId, + "selectedDisease": searchDiagnosis.diseases, + "diseasesCode": searchDiagnosis.diseasesCode, + "diseasesId": searchDiagnosis.diseasesId, + // "selectedIcdCode": searchDiagnosis.icdId, + "selectedCategoryCode": searchDiagnosis.categoryCode, + "selectedSectionCode": searchDiagnosis.sectionCode, + "selectedChapterCode": searchDiagnosis.chapterCode, + // "selectedNandaCode": searchDiagnosis.selectedNandaCode, + "isResolved": false, + "doctorId": patient.doctorId, + "doctorCode": user?['List_MemberInformation'][0]['MemberID'], + "ProjectID": patient.projectId, + "codeRange": searchDiagnosis.codeRange + }; + var success = false; + await baseAppClient.post(CREATE_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) { + DrAppToastMsg.showSuccesToast(response['CreatDiagnosis']['message']); + success = true; + }, onFailure: (String error, int statusCode) { + success = false; + hasError = true; + super.error = error; + }, body: request); + + return success; + } + + Future createProgressNote( + PatiantInformtion patient, + String? clinicID, + String conditionType, + String note, + ) async { + Map request = { + "planNote": note, + "PatientMRN": patient.patientMRN, + "EpisodeID": patient.pomrId, + "CreatedByName": patient.doctorName, + "CreatedBy": patient.doctorId, + "Speciality": clinicID, + "ProgressNotesTypes": "DOCTOR_NOTE", + "PatientCondition": conditionType, + "ProjectID": patient.projectId + }; + var success = false; + await baseAppClient.post(CREATE_PROGRESS_NOTE, + onSuccess: (dynamic response, int statusCode) { + if (response['ListCreateProgressNote'] != null) { + DrAppToastMsg.showSuccesToast( + response['ListCreateProgressNote']['message']); + success = true; + } + }, onFailure: (String error, int statusCode) { + success = false; + hasError = true; + super.error = error; + }, body: request); + + return success; + } + + Future editDiagnosis(PatientPreviousDiagnosis diagnosis) async { + var request = diagnosis.toJson(); + var success = false; + await baseAppClient.post(EDIT_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) { + if (response['ListVisitWisePatientDiagnosis']['resultData'] != null && + (response['ListVisitWisePatientDiagnosis']['resultData'] as List) + .isNotEmpty) { + success = true; + return; + } + success = false; + }, onFailure: (String error, int statusCode) { + success = false; + hasError = true; + super.error = error; + }, body: request); + + return success; + } + + Future resolveDiagnosis(PatientPreviousDiagnosis diagnosis) async { + var request = { + "patientProblemRevisionId": diagnosis.patientProblemRevisionId, + "patientProblemId": diagnosis.patientProblemId, + "patientId": diagnosis.patientId, + "doctorId": diagnosis.doctorId, + "pomrId": diagnosis.pomrId, + "appointmentId": diagnosis.appointmentId ?? 0, + "problemId": diagnosis.problemId, + "diagnosisType": diagnosis.diagnosisType, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID) + }; + var success = false; + await baseAppClient.post(RESOLVE_DIAGNOSIS, + onSuccess: (dynamic response, int statusCode) { + if (response['ListDiagnosisResolve'] != null && + response['ListDiagnosisResolve']['resultData'] != null && + (response['ListDiagnosisResolve']['resultData'] as List).isNotEmpty) { + success = true; + } + }, onFailure: (String error, int statusCode) { + success = false; + DrAppToastMsg.showErrorToast(error); + + hasError = true; + super.error = error; + }, body: request); + + return success; + } + + Future getClinic() async { + Map request = {}; + var success = false; + await baseAppClient.post(GET_CLINIC, + onSuccess: (dynamic response, int statusCode) { + response['ListDoctorClinics'] + .forEach((v) => clinicsList.add(SOAPClinic.fromJson(v))); + success = false; + }, onFailure: (String error, int statusCode) { + success = false; + hasError = true; + super.error = error; + }, body: request); + + return success; + } + + Future getPatientCondition() async { + Map request = {}; + var success = false; + patientConditionList.clear(); + patientConditionMap.clear(); + await baseAppClient.post(GET_PATIENT_CLINIC, + onSuccess: (dynamic response, int statusCode) { + response['ListPatientConditionProgress']['resultData'].forEach((v) => + v['PATIENT_CONDITION'].forEach((item) { + patientConditionList.add(PatientCondition.fromJson(item)); + patientConditionMap[item['code']]= item['name']; + })); + success = false; + }, onFailure: (String error, int statusCode) { + success = false; + hasError = true; + super.error = error; + }, body: request); + + return success; + } + + Future continueEpisodeVidaPlus( + PatiantInformtion patient, List chiefComplaint) async { + List> chiefComplaintList = []; + + chiefComplaint.forEach((action) { + action.chiefComplains!.forEach((action2) { + chiefComplaintList.add({ + "chiefComplain": action2.chiefComplain, + "chiefComplainTemplateId": action2.chiefComplainTemplateId ?? + action.chiefComplainTemplateId ?? + '' + }); + }); + }); + bool success = false; + Map request = { + "appointmentId": patient.appointmentNo, + "projectId": patient.projectId, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "chiefComplain": chiefComplaintList, + 'EpisodeID': chiefComplaint.first.episodeId, + 'pomrId': patient.pomrId, + 'doctorId': patient.doctorId, + 'patientId': patient.patientId + }; + hasError = false; + await baseAppClient.post(CONTINUE_EPISODE_VP, + onSuccess: (dynamic response, int statusCode) { + if ((response['ContinueEpisode']['resultData'] != null && + (response['ContinueEpisode']['resultData'] as List).isNotEmpty)) { + success = true; + } + }, onFailure: (String error, int statusCode) { + hasError = true; + DrAppToastMsg.showErrorToast(error); + super.error = error; + }, body: request); + return success; + } + + continueEpisodeVidaPlusFromPrevious(PatiantInformtion patient, + ChiefComplains chiefComplaint, String chiefComplainTemplateId) async { + List> chiefComplaintList = []; + var listofComplain = { + chiefComplaint.chiefComplain: chiefComplainTemplateId + }; + + Map request = { + "appointmentId": patient.appointmentNo, + "projectId": patient.projectId, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "chiefComplain": listofComplain, + }; + hasError = false; + await baseAppClient.post(CONTINUE_EPISODE_VP, + onSuccess: (dynamic response, int statusCode) { + print("Success"); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + } + + updateChiefComplaintVidaPlus(PatiantInformtion patient, + GetChiefComplaintVidaPlus chiefComplaint) async { + Map request = { + "AppointmentNo": patient.appointmentNo, + "pomrId": patient.pomrId, + "PatientMRN": patient.patientMRN, + "PatientName": patient.firstName! + ' ' + patient.lastName!, + "addedChiefComplaintCreateDtos": [], + "removedChiefComplaintIds": [chiefComplaint.chiefComplainId], + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID), + }; + hasError = false; + await baseAppClient.post(UPDATE_CHIEF_COMPLAINT, + onSuccess: (dynamic response, int statusCode) { + print("Success"); + DrAppToastMsg.showErrorToast( + response['List_UpdateChiefComplaint']['message']); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + } + + episodeByChiefComplaint(PatiantInformtion patient) async { + Map request = { + "patientId": patient.patientId, + "clinicId": patient.clinicId, + "setupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "pomrId": patient.pomrId + }; + hasError = false; + await baseAppClient.post(EPISODE_BY_CHIEF_COMPLAINT, + onSuccess: (dynamic response, int statusCode) { + episodeByChiefComplaintListVidaPlus.clear(); + + response['EpisodeByChiefcomplaint']['resultData'].forEach((v) { + episodeByChiefComplaintListVidaPlus + .add(EpisodeByChiefComplaintVidaPlus.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + } + + getHomeMedication(PatiantInformtion patient) async { + Map request = { + "patientId": patient.patientId, + }; + hasError = false; + await baseAppClient.post(GET_HOME_MEDICATION, + onSuccess: (dynamic response, int statusCode) { + getHomeMedicationList.clear(); + response['ListHomeMedication']['resultData'].forEach((v) { + getHomeMedicationList.add(GetHomeMedicationList.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + } + + searchCurrentMedication(String query) async { + Map request = {"SearchKey": query}; + hasError = false; + await baseAppClient.post(SEARCH_CURRENT_MEDICATION, + onSuccess: (dynamic response, int statusCode) { + getSearchCurrentMedication.clear(); + response['ListFormulatorySearch']['resultData'].forEach((v) { + getSearchCurrentMedication.add(GetSearchCurrentMedication.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + } + + getCurrentMedicationDetails(String id) async { + Map request = {"genericFormularyId": id}; + hasError = false; + await baseAppClient.post(SEARCH_CURRENT_MEDICATION_DETAILS, + onSuccess: (dynamic response, int statusCode) { + getSearchCurrentMedicationDetails.clear(); + response['ListFormularyMaster']['resultData'].forEach((v) { + getSearchCurrentMedicationDetails + .add(GetSearchCurrentMedicationDetails.fromJson(v)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + } + + removeCurrentMedicationVidaPlus(String medicationID) async { + Map request = {"homeMedicationId": medicationID}; + hasError = false; + await baseAppClient.post(REMOVE_CURRENT_MEDICATION, + onSuccess: (dynamic response, int statusCode) { + print("Success"); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: request); + } + + addCurrentMedicationVidaPlus( + Map request, PatiantInformtion patientInfo) async { + var doctorProfile = await sharedPref.getObj(LOGGED_IN_USER); + + Map genericRequest = { + "patientId": patientInfo.patientId, + "patientPomrId": patientInfo.pomrId, + "hospitalId": patientInfo.projectId, + "hospitalGroupId": await sharedPref.getString(DOCTOR_SETUP_ID), + "clinicGroupId": patientInfo.clinicGroupId, + "clinicId": patientInfo.clinicId, + "appointmentId": patientInfo.appointmentNo, + "created_by": patientInfo.doctorId, + "loginUserId": doctorProfile['List_MemberInformation'][0]['MemberID'], + }; + + Map finalRequest = {} + ..addAll(request) + ..addAll(genericRequest); + hasError = false; + await baseAppClient.post(ADD_CURRENT_MEDICATION, + onSuccess: (dynamic response, int statusCode) {}, + onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: finalRequest); } } diff --git a/lib/core/viewModel/SOAP_view_model.dart b/lib/core/viewModel/SOAP_view_model.dart index 90efa658..aaf137ad 100644 --- a/lib/core/viewModel/SOAP_view_model.dart +++ b/lib/core/viewModel/SOAP_view_model.dart @@ -1,3 +1,4 @@ +import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; import 'package:doctor_app_flutter/core/enum/master_lookup_key.dart'; import 'package:doctor_app_flutter/core/enum/view_state.dart'; import 'package:doctor_app_flutter/core/model/SOAP/Allergy/get_allergies_res_model.dart'; @@ -5,23 +6,40 @@ import 'package:doctor_app_flutter/core/model/SOAP/Allergy/post_allergy_request_ import 'package:doctor_app_flutter/core/model/SOAP/Assessment/get_assessment_req_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/Assessment/get_assessment_res_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/Assessment/post_assessment_request_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/allergy/get_allergies_list_vida_plus.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/FavoriteDiseaseDetails.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/audit_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/patient_previous_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/search_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/episode_by_chief_complaint_vidaplus.dart'; import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/get_chief_complaint_req_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/get_chief_complaint_res_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/get_chief_complaint_vida_plus.dart'; import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/post_chief_complaint_request_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/search_chief_complaint_vidaplus.dart'; import 'package:doctor_app_flutter/core/model/SOAP/general_get_req_for_SOAP.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/get_hopi_details.dart'; import 'package:doctor_app_flutter/core/model/SOAP/history/get_history_req_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/history/get_history_res_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/history/post_histories_request_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/home_medication_vp/GetHomeMedication.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/home_medication_vp/GetSearchCurrentMedication.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/home_medication_vp/GetSearchCurrentMedicationDetails.dart'; import 'package:doctor_app_flutter/core/model/SOAP/in_patient/get_episode_for_inpatient_req_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/in_patient/post_episode_for_Inpatient_request_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/Category.dart'; import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/get_physical_exam_list_res_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/get_physical_exam_req_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/patient_physical_examination.dart'; import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/post_physical_exam_request_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/post_episode_req_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/Clinic.dart'; import 'package:doctor_app_flutter/core/model/SOAP/progress_note/GetGetProgressNoteResModel.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/PatientCondition.dart'; import 'package:doctor_app_flutter/core/model/SOAP/progress_note/get_progress_note_req_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/progress_note/post_progress_note_request_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/progress_note.dart'; import 'package:doctor_app_flutter/core/model/search_drug/get_medication_response_model.dart'; import 'package:doctor_app_flutter/core/service/patient_medical_file/prescription/prescription_service.dart'; import 'package:doctor_app_flutter/core/service/patient_medical_file/soap/SOAP_service.dart'; @@ -32,60 +50,141 @@ import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; import 'package:doctor_app_flutter/screens/patients/profile/soap_update/assessment/assessment_call_back.dart'; import 'package:doctor_app_flutter/screens/patients/profile/soap_update/objective/objective_call_back.dart'; import 'package:doctor_app_flutter/screens/patients/profile/soap_update/plan/plan_call_back.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/subjective/cheif_complaints/update_Chief_complaints.dart'; import 'package:doctor_app_flutter/screens/patients/profile/soap_update/subjective/subjective_call_back.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; import '../../locator.dart'; +import '../model/SOAP/allergy/get_patient_allergies_list_vida_plus.dart'; import '../model/SOAP/assessment/patch_assessment_req_model.dart'; +import '../model/SOAP/physical_exam/GeneralSpeciality.dart'; import 'base_view_model.dart'; class SOAPViewModel extends BaseViewModel { SOAPService _SOAPService = locator(); + PrescriptionService _prescriptionService = locator(); List get allergiesList => _SOAPService.allergiesList; - List get allergySeverityList => _SOAPService.allergySeverityList; + List get allergySeverityList => + _SOAPService.allergySeverityList; List get historyFamilyList => _SOAPService.historyFamilyList; - List get historyMedicalList => _SOAPService.historyMedicalList; + List get historyMedicalList => + _SOAPService.historyMedicalList; List get historySportList => _SOAPService.historySportList; List get historySocialList => _SOAPService.historySocialList; - List get historySurgicalList => _SOAPService.historySurgicalList; + List get historySurgicalList => + _SOAPService.historySurgicalList; - List get mergeHistorySurgicalWithHistorySportList => [...historySurgicalList, ...historySportList]; + List get mergeHistorySurgicalWithHistorySportList => + [...historySurgicalList, ...historySportList]; - List get physicalExaminationList => _SOAPService.physicalExaminationList; + List get physicalExaminationList => + _SOAPService.physicalExaminationList; - List get listOfDiagnosisType => _SOAPService.listOfDiagnosisType; + List get listOfDiagnosisType => + _SOAPService.listOfDiagnosisType; - List get listOfDiagnosisCondition => _SOAPService.listOfDiagnosisCondition; + List get listOfDiagnosisCondition => + _SOAPService.listOfDiagnosisCondition; List get listOfICD10 => _SOAPService.listOfICD10; - List get patientChiefComplaintList => _SOAPService.patientChiefComplaintList; + List get patientChiefComplaintList => + _SOAPService.patientChiefComplaintList; + + List get patientAllergiesList => + _SOAPService.patientAllergiesList; + + List get patientHistoryList => + _SOAPService.patientHistoryList; + + List get patientPhysicalExamList => + _SOAPService.patientPhysicalExamList; + + List get patientProgressNoteList => + _SOAPService.patientProgressNoteList; + + List get patientAssessmentList => + _SOAPService.patientAssessmentList; + + List get searchAllergiesVidaPlus => + _SOAPService.searchAllergiesList; + + List get patientAllergiesVidaPlus => + _SOAPService.patientAllergiesVidaPlus; + + List get getHopiDetails => _SOAPService.hopiDetails; + + List get searchChiefComplaintList => + _SOAPService.searchChiefComplaintListVidaPlus; + + List get searchDiagnosisList => + _SOAPService.searchDiagnosisList; + + List get icdVersionList => _SOAPService.icdVersionList; + + List get patientPreviousDiagnosis => + _SOAPService.patientPreviousDiagnosisList; + + List get diagnosisList => + _SOAPService.patientDiagnosisList; - List get patientAllergiesList => _SOAPService.patientAllergiesList; + List get favoriteDiagnosisDetails => + _SOAPService.favoriteDiagnosisDetailsList; - List get patientHistoryList => _SOAPService.patientHistoryList; + Map get diagnosisTypeList => _SOAPService.diagnosisTypeList; - List get patientPhysicalExamList => _SOAPService.patientPhysicalExamList; + Map get conditionTypeMap => _SOAPService.conditionTypeList; - List get patientProgressNoteList => _SOAPService.patientProgressNoteList; + List get conditionTypeList => + _SOAPService.conditionTypeList.keys.toList(); - List get patientAssessmentList => _SOAPService.patientAssessmentList; + List get getChiefComplaintListVidaPlus => + _SOAPService.patientChiefComplaintListVidaPlus; + + List + get episodeByChiefComplaintListVidaPlus => + _SOAPService.episodeByChiefComplaintListVidaPlus; + + List get patientPhysicalExaminationList => + _SOAPService.patientPhysicalExaminationList; + + List get auditDiagnosislist => + _SOAPService.auditDiagnosislist; + + List get patientConditionList => + _SOAPService.patientConditionList; + + List? mainSpecialityList = null; + List speciality = []; + + List get progressNote => + _SOAPService.patientProgressNoteListVidaPlus; + + List get clinics => _SOAPService.clinicsList; + + Map> get specialityDetails => + _SOAPService.specialityDetails; int? get episodeID => _SOAPService.episodeID; - bool get isPrescriptionOrder => _SOAPService.isPrescriptionOrder; + + bool get showAudit => _SOAPService.showAuditBottomSheet; + + bool get isPrescriptionOrder => _SOAPService.isPrescriptionOrder; bool isAddProgress = true; bool isAddExamInProgress = true; String progressNoteText = ""; String complaintsControllerError = ''; String medicationControllerError = ''; String illnessControllerError = ''; + String selectedIcd = ''; get medicationStrengthList => _SOAPService.medicationStrengthListWithModel; @@ -95,7 +194,18 @@ class SOAPViewModel extends BaseViewModel { get medicationFrequencyList => _SOAPService.medicationFrequencyListWithModel; - List? get allMedicationList => _prescriptionService.allMedicationList; + List? get allMedicationList => + _prescriptionService.allMedicationList; + + List? get getHomeMedicationList => + _SOAPService.getHomeMedicationList; + + List? get getMedicationListVP => + _SOAPService.getSearchCurrentMedication; + + List? + get getSearchCurrentMedicationDetails => + _SOAPService.getSearchCurrentMedicationDetails; late SubjectiveCallBack subjectiveCallBack; @@ -137,7 +247,10 @@ class SOAPViewModel extends BaseViewModel { planCallBack.nextFunction(model); } - Future getMasterLookup(MasterKeysService masterKeys, {bool isBusyLocal = false, String searchKey = "", bool allowSetState = false}) async { + Future getMasterLookup(MasterKeysService masterKeys, + {bool isBusyLocal = false, + String searchKey = "", + bool allowSetState = false}) async { if (isBusyLocal) { setState(ViewState.Busy); } else @@ -160,9 +273,12 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - Future postEpisodeForInPatient(PostEpisodeForInpatientRequestModel postEpisodeForInpatientRequestModel) async { + Future postEpisodeForInPatient( + PostEpisodeForInpatientRequestModel + postEpisodeForInpatientRequestModel) async { setState(ViewState.BusyLocal); - await _SOAPService.postEpisodeForInPatient(postEpisodeForInpatientRequestModel); + await _SOAPService.postEpisodeForInPatient( + postEpisodeForInpatientRequestModel); if (_SOAPService.hasError) { error = _SOAPService.error; setState(ViewState.ErrorLocal); @@ -170,7 +286,8 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - Future postPhysicalExam(PostPhysicalExamRequestModel postPhysicalExamRequestModel) async { + Future postPhysicalExam( + PostPhysicalExamRequestModel postPhysicalExamRequestModel) async { setState(ViewState.BusyLocal); await _SOAPService.postPhysicalExam(postPhysicalExamRequestModel); if (_SOAPService.hasError) { @@ -180,7 +297,8 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - Future postProgressNote(PostProgressNoteRequestModel postProgressNoteRequestModel) async { + Future postProgressNote( + PostProgressNoteRequestModel postProgressNoteRequestModel) async { setState(ViewState.BusyLocal); await _SOAPService.postProgressNote(postProgressNoteRequestModel); if (_SOAPService.hasError) { @@ -190,7 +308,8 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - Future postAssessment(PostAssessmentRequestModel postAssessmentRequestModel) async { + Future postAssessment( + PostAssessmentRequestModel postAssessmentRequestModel) async { setState(ViewState.BusyLocal); await _SOAPService.postAssessment(postAssessmentRequestModel); if (_SOAPService.hasError) { @@ -200,7 +319,8 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - Future patchPhysicalExam(PostPhysicalExamRequestModel patchPhysicalExamRequestModel) async { + Future patchPhysicalExam( + PostPhysicalExamRequestModel patchPhysicalExamRequestModel) async { setState(ViewState.BusyLocal); await _SOAPService.patchPhysicalExam(patchPhysicalExamRequestModel); if (_SOAPService.hasError) { @@ -210,7 +330,8 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - Future patchProgressNote(PostProgressNoteRequestModel patchProgressNoteRequestModel) async { + Future patchProgressNote( + PostProgressNoteRequestModel patchProgressNoteRequestModel) async { setState(ViewState.BusyLocal); await _SOAPService.patchProgressNote(patchProgressNoteRequestModel); if (_SOAPService.hasError) { @@ -220,7 +341,8 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - Future patchAssessment(PostAssessmentRequestUpdateModel patchAssessmentRequestModel) async { + Future patchAssessment( + PostAssessmentRequestUpdateModel patchAssessmentRequestModel) async { setState(ViewState.BusyLocal); await _SOAPService.patchAssessment(patchAssessmentRequestModel!); if (_SOAPService.hasError) { @@ -230,7 +352,8 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - Future getPatientAllergy(GeneralGetReqForSOAP generalGetReqForSOAP, {isLocalBusy = false}) async { + Future getPatientAllergy(GeneralGetReqForSOAP generalGetReqForSOAP, + {isLocalBusy = false}) async { if (isLocalBusy) { setState(ViewState.BusyLocal); } else @@ -249,8 +372,14 @@ class SOAPViewModel extends BaseViewModel { String getAllergicNames(isArabic) { String allergiesString = ''; patientAllergiesList.forEach((element) { - MasterKeyModel? selectedAllergy = getOneMasterKey(masterKeys: MasterKeysService.Allergies, id: element.allergyDiseaseId, typeId: element.allergyDiseaseType!); - if (selectedAllergy != null && element.isChecked!) allergiesString += ((isArabic ? selectedAllergy.nameAr : selectedAllergy.nameEn)! + ' , '); + MasterKeyModel? selectedAllergy = getOneMasterKey( + masterKeys: MasterKeysService.Allergies, + id: element.allergyDiseaseId, + typeId: element.allergyDiseaseType!); + if (selectedAllergy != null && element.isChecked!) + allergiesString += + ((isArabic ? selectedAllergy.nameAr : selectedAllergy.nameEn)! + + ' , '); }); return allergiesString; } @@ -258,7 +387,9 @@ class SOAPViewModel extends BaseViewModel { Future getPatientPhysicalExam(PatiantInformtion patientInfo) async { GetPhysicalExamReqModel getPhysicalExamReqModel = GetPhysicalExamReqModel( patientMRN: patientInfo.patientMRN, - episodeID: patientInfo.episodeNo == null ? "0" : patientInfo.episodeNo.toString(), + episodeID: patientInfo.episodeNo == null + ? "0" + : patientInfo.episodeNo.toString(), appointmentNo: patientInfo.appointmentNo == null ? 0 : int.parse( @@ -278,7 +409,8 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - Future getPatientProgressNote(GetProgressNoteReqModel getGetProgressNoteReqModel) async { + Future getPatientProgressNote( + GetProgressNoteReqModel getGetProgressNoteReqModel) async { setState(ViewState.Busy); await _SOAPService.getPatientProgressNote(getGetProgressNoteReqModel); if (_SOAPService.hasError) { @@ -300,7 +432,11 @@ class SOAPViewModel extends BaseViewModel { Future getEpisodeForInpatient(PatiantInformtion patient) async { setState(ViewState.BusyLocal); - GetEpisodeForInpatientReqModel getEpisodeForInpatientReqModel = GetEpisodeForInpatientReqModel(patientID: patient.patientId, admissionNo: int.parse(patient.admissionNo!), patientTypeID: 1); + GetEpisodeForInpatientReqModel getEpisodeForInpatientReqModel = + GetEpisodeForInpatientReqModel( + patientID: patient.patientId, + admissionNo: int.parse(patient.admissionNo!), + patientTypeID: 1); await _SOAPService.getEpisodeForInpatient(getEpisodeForInpatientReqModel); if (_SOAPService.hasError) { error = _SOAPService.error; @@ -312,11 +448,13 @@ class SOAPViewModel extends BaseViewModel { } // ignore: missing_return - MasterKeyModel? getOneMasterKey({required MasterKeysService masterKeys, dynamic id, int? typeId}) { + MasterKeyModel? getOneMasterKey( + {required MasterKeysService masterKeys, dynamic id, int? typeId}) { switch (masterKeys) { case MasterKeysService.Allergies: List result = allergiesList.where((element) { - return element.id == id && element.typeId == masterKeys.getMasterKeyService(); + return element.id == id && + element.typeId == masterKeys.getMasterKeyService(); }).toList(); if (result.isNotEmpty) { return result.first; @@ -325,7 +463,8 @@ class SOAPViewModel extends BaseViewModel { case MasterKeysService.HistoryFamily: List result = historyFamilyList.where((element) { - return element.id == id && element.typeId == masterKeys.getMasterKeyService(); + return element.id == id && + element.typeId == masterKeys.getMasterKeyService(); }).toList(); if (result.isNotEmpty) { return result.first; @@ -333,7 +472,8 @@ class SOAPViewModel extends BaseViewModel { break; case MasterKeysService.HistoryMedical: List result = historyMedicalList.where((element) { - return element.id == id && element.typeId == masterKeys.getMasterKeyService(); + return element.id == id && + element.typeId == masterKeys.getMasterKeyService(); }).toList(); if (result.isNotEmpty) { return result.first; @@ -341,7 +481,8 @@ class SOAPViewModel extends BaseViewModel { break; case MasterKeysService.HistorySocial: List result = historySocialList.where((element) { - return element.id == id && element.typeId == masterKeys.getMasterKeyService(); + return element.id == id && + element.typeId == masterKeys.getMasterKeyService(); }).toList(); if (result.isNotEmpty) { return result.first; @@ -349,7 +490,8 @@ class SOAPViewModel extends BaseViewModel { break; case MasterKeysService.HistorySports: List result = historySocialList.where((element) { - return element.id == id && element.typeId == masterKeys.getMasterKeyService(); + return element.id == id && + element.typeId == masterKeys.getMasterKeyService(); }).toList(); if (result.isNotEmpty) { return result.first; @@ -365,7 +507,8 @@ class SOAPViewModel extends BaseViewModel { break; case MasterKeysService.PhysicalExamination: List result = physicalExaminationList.where((element) { - return element.id == id && element.typeId == masterKeys.getMasterKeyService(); + return element.id == id && + element.typeId == masterKeys.getMasterKeyService(); }).toList(); if (result.isNotEmpty) { return result.first; @@ -373,7 +516,8 @@ class SOAPViewModel extends BaseViewModel { break; case MasterKeysService.AllergySeverity: List result = allergySeverityList.where((element) { - return element.id == id && element.typeId == masterKeys.getMasterKeyService(); + return element.id == id && + element.typeId == masterKeys.getMasterKeyService(); }).toList(); if (result.isNotEmpty) { return result.first; @@ -381,7 +525,8 @@ class SOAPViewModel extends BaseViewModel { break; case MasterKeysService.DiagnosisType: List result = listOfDiagnosisType.where((element) { - return element.id == id && element.typeId == masterKeys.getMasterKeyService(); + return element.id == id && + element.typeId == masterKeys.getMasterKeyService(); }).toList(); if (result.isNotEmpty) { return result.first; @@ -389,7 +534,8 @@ class SOAPViewModel extends BaseViewModel { break; case MasterKeysService.DiagnosisCondition: List result = listOfDiagnosisCondition.where((element) { - return element.id == id && element.typeId == masterKeys.getMasterKeyService(); + return element.id == id && + element.typeId == masterKeys.getMasterKeyService(); }).toList(); if (result.isNotEmpty) { return result.first; @@ -428,8 +574,10 @@ class SOAPViewModel extends BaseViewModel { } } - int getFirstIndexForOldExamination(List mySelectedExamination) { - Iterable examList = mySelectedExamination.where((element) => !element.isLocal); + int getFirstIndexForOldExamination( + List mySelectedExamination) { + Iterable examList = + mySelectedExamination.where((element) => !element.isLocal); if (examList.length > 0) { return mySelectedExamination.indexOf(examList.first); @@ -438,25 +586,44 @@ class SOAPViewModel extends BaseViewModel { } onUpdateSubjectStepStart(PatiantInformtion patientInfo) async { - GetChiefComplaintReqModel getChiefComplaintReqModel = GetChiefComplaintReqModel( - admissionNo: patientInfo.admissionNo != null ? int.parse(patientInfo.admissionNo!) : null, - patientMRN: patientInfo.patientMRN, - appointmentNo: patientInfo.appointmentNo != null ? int.parse(patientInfo.appointmentNo.toString()) : null, - episodeId: patientInfo.episodeNo, - episodeID: patientInfo.episodeNo, - doctorID: ''); - var services = [await _SOAPService.getPatientChiefComplaint(getChiefComplaintReqModel)]; + GetChiefComplaintReqModel getChiefComplaintReqModel = + GetChiefComplaintReqModel( + admissionNo: + patientInfo + .admissionNo != + null + ? int.parse(patientInfo.admissionNo!) + : null, + patientMRN: patientInfo.patientMRN, + appointmentNo: patientInfo.appointmentNo != null + ? int.parse(patientInfo.appointmentNo.toString()) + : null, + episodeId: patientInfo.episodeNo, + episodeID: patientInfo.episodeNo, + doctorID: ''); + var services = [ + await _SOAPService.getPatientChiefComplaint(getChiefComplaintReqModel) + ]; if (patientInfo.admissionNo == null) { complaintsControllerError = ''; medicationControllerError = ''; illnessControllerError = ''; GetHistoryReqModel getHistoryReqModel = GetHistoryReqModel( - patientMRN: patientInfo.patientMRN, episodeID: patientInfo.episodeNo.toString(), appointmentNo: int.parse(patientInfo.appointmentNo.toString()), doctorID: '', editedBy: ''); - services.add(await _SOAPService.getPatientHistories(getHistoryReqModel, isFirst: true)); - - GeneralGetReqForSOAP generalGetReqForSOAP = - GeneralGetReqForSOAP(patientMRN: patientInfo.patientMRN, episodeId: patientInfo.episodeNo, appointmentNo: int.parse(patientInfo.appointmentNo.toString()), doctorID: '', editedBy: ''); + patientMRN: patientInfo.patientMRN, + episodeID: patientInfo.episodeNo.toString(), + appointmentNo: int.parse(patientInfo.appointmentNo.toString()), + doctorID: '', + editedBy: ''); + services.add(await _SOAPService.getPatientHistories(getHistoryReqModel, + isFirst: true)); + + GeneralGetReqForSOAP generalGetReqForSOAP = GeneralGetReqForSOAP( + patientMRN: patientInfo.patientMRN, + episodeId: patientInfo.episodeNo, + appointmentNo: int.parse(patientInfo.appointmentNo.toString()), + doctorID: '', + editedBy: ''); services.add(await _SOAPService.getPatientAllergy(generalGetReqForSOAP)); } @@ -470,41 +637,61 @@ class SOAPViewModel extends BaseViewModel { if (patientHistoryList.isNotEmpty) { if (historyFamilyList.isEmpty) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.HistoryFamily)]; + services = [ + await _SOAPService.getMasterLookup(MasterKeysService.HistoryFamily) + ]; } else { - services.add(await _SOAPService.getMasterLookup(MasterKeysService.HistoryFamily)); + services.add(await _SOAPService.getMasterLookup( + MasterKeysService.HistoryFamily)); } } if (historyMedicalList.isEmpty) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.HistoryMedical)]; + services = [ + await _SOAPService.getMasterLookup(MasterKeysService.HistoryMedical) + ]; } else - services.add(await _SOAPService.getMasterLookup(MasterKeysService.HistoryMedical)); + services.add(await _SOAPService.getMasterLookup( + MasterKeysService.HistoryMedical)); } if (historySurgicalList.length == 0) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.HistorySurgical)]; + services = [ + await _SOAPService.getMasterLookup( + MasterKeysService.HistorySurgical) + ]; } else - services.add(await _SOAPService.getMasterLookup(MasterKeysService.HistorySurgical)); + services.add(await _SOAPService.getMasterLookup( + MasterKeysService.HistorySurgical)); } if (historySportList.length == 0) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.HistorySports)]; + services = [ + await _SOAPService.getMasterLookup(MasterKeysService.HistorySports) + ]; } else - services.add(await _SOAPService.getMasterLookup(MasterKeysService.HistorySports)); + services.add(await _SOAPService.getMasterLookup( + MasterKeysService.HistorySports)); } } if (patientAllergiesList.isNotEmpty) { if (allergiesList.isEmpty) if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.Allergies)]; + services = [ + await _SOAPService.getMasterLookup(MasterKeysService.Allergies) + ]; } else - services.add(await _SOAPService.getMasterLookup(MasterKeysService.Allergies)); + services.add( + await _SOAPService.getMasterLookup(MasterKeysService.Allergies)); if (allergySeverityList.isEmpty) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.AllergySeverity)]; + services = [ + await _SOAPService.getMasterLookup( + MasterKeysService.AllergySeverity) + ]; } else - services.add(await _SOAPService.getMasterLookup(MasterKeysService.AllergySeverity)); + services.add(await _SOAPService.getMasterLookup( + MasterKeysService.AllergySeverity)); } } @@ -522,30 +709,45 @@ class SOAPViewModel extends BaseViewModel { List services = []; if (medicationStrengthList.length == 0) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.MedicationStrength)]; + services = [ + await _SOAPService.getMasterLookup( + MasterKeysService.MedicationStrength) + ]; } else { - services.add(await _SOAPService.getMasterLookup(MasterKeysService.MedicationStrength)); + services.add(await _SOAPService.getMasterLookup( + MasterKeysService.MedicationStrength)); } } if (medicationFrequencyList.length == 0) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.MedicationFrequency)]; + services = [ + await _SOAPService.getMasterLookup( + MasterKeysService.MedicationFrequency) + ]; } else { - services.add(await _SOAPService.getMasterLookup(MasterKeysService.MedicationFrequency)); + services.add(await _SOAPService.getMasterLookup( + MasterKeysService.MedicationFrequency)); } } if (medicationDoseTimeList.length == 0) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.MedicationDoseTime)]; + services = [ + await _SOAPService.getMasterLookup( + MasterKeysService.MedicationDoseTime) + ]; } else { - services.add(await _SOAPService.getMasterLookup(MasterKeysService.MedicationDoseTime)); + services.add(await _SOAPService.getMasterLookup( + MasterKeysService.MedicationDoseTime)); } } if (medicationRouteList.length == 0) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.MedicationRoute)]; + services = [ + await _SOAPService.getMasterLookup(MasterKeysService.MedicationRoute) + ]; } else { - services.add(await _SOAPService.getMasterLookup(MasterKeysService.MedicationRoute)); + services.add(await _SOAPService.getMasterLookup( + MasterKeysService.MedicationRoute)); } } if (allMedicationList!.isEmpty) { @@ -559,7 +761,8 @@ class SOAPViewModel extends BaseViewModel { final results = services; if (_SOAPService.hasError || _prescriptionService.hasError) { - error = _SOAPService.error.toString() + _prescriptionService.error.toString(); + error = + _SOAPService.error.toString() + _prescriptionService.error.toString(); setState(ViewState.ErrorLocal); } else { setState( @@ -568,28 +771,40 @@ class SOAPViewModel extends BaseViewModel { } } - callAddAssessmentLookupsServices({String searchKey = "", bool allowSetState = true}) async { + callAddAssessmentLookupsServices( + {String searchKey = "", bool allowSetState = true}) async { if (allowSetState) setState(ViewState.Busy); List services = []; if (listOfDiagnosisCondition.isEmpty) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.DiagnosisCondition)]; + services = [ + await _SOAPService.getMasterLookup( + MasterKeysService.DiagnosisCondition) + ]; } else { - services.add(await _SOAPService.getMasterLookup(MasterKeysService.DiagnosisCondition)); + services.add(await _SOAPService.getMasterLookup( + MasterKeysService.DiagnosisCondition)); } } if (listOfDiagnosisType.length == 0) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.DiagnosisType)]; + services = [ + await _SOAPService.getMasterLookup(MasterKeysService.DiagnosisType) + ]; } else { - services.add(await _SOAPService.getMasterLookup(MasterKeysService.DiagnosisType)); + services.add(await _SOAPService.getMasterLookup( + MasterKeysService.DiagnosisType)); } } if (listOfICD10.length == 0) { if (services.isEmpty) { - services = [await _SOAPService.getMasterLookup(MasterKeysService.ICD10, searchKey: searchKey)]; + services = [ + await _SOAPService.getMasterLookup(MasterKeysService.ICD10, + searchKey: searchKey) + ]; } else { - services.add(await _SOAPService.getMasterLookup(MasterKeysService.ICD10, searchKey: searchKey)); + services.add(await _SOAPService.getMasterLookup(MasterKeysService.ICD10, + searchKey: searchKey)); } } @@ -605,9 +820,15 @@ class SOAPViewModel extends BaseViewModel { onUpdateAssessmentStepStart(PatiantInformtion patientInfo) async { GetAssessmentReqModel getAssessmentReqModel = GetAssessmentReqModel( - patientMRN: patientInfo.patientMRN, episodeID: patientInfo.episodeNo.toString(), editedBy: '', doctorID: '', appointmentNo: int.parse(patientInfo.appointmentNo.toString())); + patientMRN: patientInfo.patientMRN, + episodeID: patientInfo.episodeNo.toString(), + editedBy: '', + doctorID: '', + appointmentNo: int.parse(patientInfo.appointmentNo.toString())); - var services = [await _SOAPService.getPatientAssessment(getAssessmentReqModel)]; + var services = [ + await _SOAPService.getPatientAssessment(getAssessmentReqModel) + ]; final results = services; @@ -622,8 +843,7 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - - Future isPrescriptionOrderCreated(PatiantInformtion patientInfo) async{ + Future isPrescriptionOrderCreated(PatiantInformtion patientInfo) async { setState(ViewState.BusyLocal); await _SOAPService.isPrescriptionOrderCreated(patientInfo); if (_SOAPService.hasError) { @@ -633,32 +853,51 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - - postSubjectServices({patientInfo, String? complaintsText, String? medicationText, String? illnessText, List? myHistoryList, List? myAllergiesList}) async { + postSubjectServices( + {patientInfo, + String? complaintsText, + String? medicationText, + String? illnessText, + List? myHistoryList, + List? myAllergiesList}) async { List services = []; PostChiefComplaintRequestModel postChiefComplaintRequestModel = - createPostChiefComplaintRequestModel(patientInfo: patientInfo, illnessText: illnessText!, medicationText: medicationText!, complaintsText: complaintsText!); + createPostChiefComplaintRequestModel( + patientInfo: patientInfo, + illnessText: illnessText!, + medicationText: medicationText!, + complaintsText: complaintsText!); if (patientChiefComplaintList.isEmpty) { postChiefComplaintRequestModel.editedBy = ''; - services = [await _SOAPService.postChiefComplaint(postChiefComplaintRequestModel)]; + services = [ + await _SOAPService.postChiefComplaint(postChiefComplaintRequestModel) + ]; } else { postChiefComplaintRequestModel.editedBy = ''; - services = [await _SOAPService.patchChiefComplaint(postChiefComplaintRequestModel)]; + services = [ + await _SOAPService.patchChiefComplaint(postChiefComplaintRequestModel) + ]; } if (myHistoryList!.length != 0) { - PostHistoriesRequestModel postHistoriesRequestModel = createPostHistoriesRequestModel(patientInfo: patientInfo, myHistoryList: myHistoryList); + PostHistoriesRequestModel postHistoriesRequestModel = + createPostHistoriesRequestModel( + patientInfo: patientInfo, myHistoryList: myHistoryList); if (patientHistoryList.isEmpty) { - services.add(await _SOAPService.postHistories(postHistoriesRequestModel)); + services + .add(await _SOAPService.postHistories(postHistoriesRequestModel)); } else { - services.add(await _SOAPService.patchHistories(postHistoriesRequestModel)); + services + .add(await _SOAPService.patchHistories(postHistoriesRequestModel)); } } if (myAllergiesList!.length != 0) { - PostAllergyRequestModel postAllergyRequestModel = createPostAllergyRequestModel(myAllergiesList: myAllergiesList, patientInfo: patientInfo); + PostAllergyRequestModel postAllergyRequestModel = + createPostAllergyRequestModel( + myAllergiesList: myAllergiesList, patientInfo: patientInfo); if (patientAllergiesList.isEmpty) { services.add(await _SOAPService.postAllergy(postAllergyRequestModel)); } else { @@ -675,9 +914,15 @@ class SOAPViewModel extends BaseViewModel { setState(ViewState.Idle); } - PostChiefComplaintRequestModel createPostChiefComplaintRequestModel({patientInfo, String? complaintsText, String? medicationText, String? illnessText}) { + PostChiefComplaintRequestModel createPostChiefComplaintRequestModel( + {patientInfo, + String? complaintsText, + String? medicationText, + String? illnessText}) { return PostChiefComplaintRequestModel( - admissionNo: patientInfo.admissionNo != null ? int.parse(patientInfo.admissionNo) : null, + admissionNo: patientInfo.admissionNo != null + ? int.parse(patientInfo.admissionNo) + : null, patientMRN: patientInfo.patientMRN, episodeID: patientInfo.episodeNo ?? 0, appointmentNo: patientInfo.appointmentNo ?? 0, @@ -690,10 +935,13 @@ class SOAPViewModel extends BaseViewModel { numberOfWeeks: 0); } - PostHistoriesRequestModel createPostHistoriesRequestModel({patientInfo, List? myHistoryList}) { - PostHistoriesRequestModel postHistoriesRequestModel = new PostHistoriesRequestModel(doctorID: ''); + PostHistoriesRequestModel createPostHistoriesRequestModel( + {patientInfo, List? myHistoryList}) { + PostHistoriesRequestModel postHistoriesRequestModel = + new PostHistoriesRequestModel(doctorID: ''); myHistoryList!.forEach((history) { - if (postHistoriesRequestModel.listMedicalHistoryVM == null) postHistoriesRequestModel.listMedicalHistoryVM = []; + if (postHistoriesRequestModel.listMedicalHistoryVM == null) + postHistoriesRequestModel.listMedicalHistoryVM = []; postHistoriesRequestModel.listMedicalHistoryVM!.add(ListMedicalHistoryVM( patientMRN: patientInfo.patientMRN, episodeId: patientInfo.episodeNo, @@ -708,26 +956,648 @@ class SOAPViewModel extends BaseViewModel { return postHistoriesRequestModel; } - PostAllergyRequestModel createPostAllergyRequestModel({myAllergiesList, patientInfo}) { - PostAllergyRequestModel postAllergyRequestModel = new PostAllergyRequestModel(); + PostAllergyRequestModel createPostAllergyRequestModel( + {myAllergiesList, patientInfo}) { + PostAllergyRequestModel postAllergyRequestModel = + new PostAllergyRequestModel(); myAllergiesList.forEach((allergy) { - if (postAllergyRequestModel.listHisProgNotePatientAllergyDiseaseVM == null) postAllergyRequestModel.listHisProgNotePatientAllergyDiseaseVM = []; - postAllergyRequestModel.listHisProgNotePatientAllergyDiseaseVM!.add(ListHisProgNotePatientAllergyDiseaseVM( - allergyDiseaseId: allergy.selectedAllergy.id, - allergyDiseaseType: allergy.selectedAllergy.typeId, - patientMRN: patientInfo.patientMRN, - episodeId: patientInfo.episodeNo, - appointmentNo: patientInfo.appointmentNo, - severity: allergy.selectedAllergySeverity.id, - remarks: allergy.remark, - createdBy: allergy.createdBy ?? doctorProfile!.doctorID, - createdOn: DateTime.now().toIso8601String(), - editedBy: doctorProfile!.doctorID, - editedOn: DateTime.now().toIso8601String(), - isChecked: allergy.isChecked, - isUpdatedByNurse: false)); + if (postAllergyRequestModel.listHisProgNotePatientAllergyDiseaseVM == + null) + postAllergyRequestModel.listHisProgNotePatientAllergyDiseaseVM = []; + postAllergyRequestModel.listHisProgNotePatientAllergyDiseaseVM!.add( + ListHisProgNotePatientAllergyDiseaseVM( + allergyDiseaseId: allergy.selectedAllergy.id, + allergyDiseaseType: allergy.selectedAllergy.typeId, + patientMRN: patientInfo.patientMRN, + episodeId: patientInfo.episodeNo, + appointmentNo: patientInfo.appointmentNo, + severity: allergy.selectedAllergySeverity.id, + remarks: allergy.remark, + createdBy: allergy.createdBy ?? doctorProfile!.doctorID, + createdOn: DateTime.now().toIso8601String(), + editedBy: doctorProfile!.doctorID, + editedOn: DateTime.now().toIso8601String(), + isChecked: allergy.isChecked, + isUpdatedByNurse: false)); }); return postAllergyRequestModel; } + + /*vida plus */ + + getAllergiesVidaPlus(PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.patientAllergies(patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + getEditAllergiesVidaPlus(int AllergyID) async { + setState(ViewState.BusyLocal); + await _SOAPService.getEditAllergies(AllergyID); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + searchAllergies(String searchKey) async { + setState(ViewState.BusyLocal); + await _SOAPService.searchAllergies(searchKey); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + addAllergies( + AllergiesListVidaPlus request, PatiantInformtion patientInfo, {bool isNoKnown =false}) async { + setState(ViewState.BusyLocal); + await _SOAPService.addAllergies(request, patientInfo, isNoKnown); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + resolveAllergies( + PatientAllergiesVidaPlus request, PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.resolveAllergies(request, patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + updateAllergies( + PatientAllergiesVidaPlus request, PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.updateAllergies(request, patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + Future saveHopi( + Map req, PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + bool result = await _SOAPService.saveHopi(req, patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + + return result; + } + + getHopi(PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.getHopi(patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + getChiefComplaint(PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.getChiefComplaint(patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + searchChiefComplaint(PatiantInformtion patientInfo, String CC) async { + setState(ViewState.BusyLocal); + await _SOAPService.searchChiefComplaintVidaPlus(patientInfo, CC); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + saveChiefComplaint(PatiantInformtion patientInfo, String CC) async { + setState(ViewState.BusyLocal); + await _SOAPService.postChiefComplaintVidaPlus(patientInfo, CC); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + updateChiefComplaint( + PatiantInformtion patientInfo, GetChiefComplaintVidaPlus CC) async { + setState(ViewState.BusyLocal); + await _SOAPService.updateChiefComplaintVidaPlus(patientInfo, CC); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + episodeByChiefComplaint(PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.episodeByChiefComplaint(patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + Future createCCByEpisode( + PatiantInformtion patientInfo, List chiefComplaint) async { + setState(ViewState.BusyLocal); + var result = await _SOAPService.continueEpisodeVidaPlus(patientInfo, chiefComplaint); + if(result){ + await getChiefComplaint(patientInfo); + } + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + + return result; + } + + continueEpisodeVidaPlusFromPrevious( + PatiantInformtion patient, ChiefComplains chiefComplaint, String chiefComplainTemplateId) async { + setState(ViewState.BusyLocal); + await _SOAPService.continueEpisodeVidaPlusFromPrevious(patient, chiefComplaint,chiefComplainTemplateId ); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + getHomeMedication(PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.getHomeMedication(patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + searchCurrentMedication(String searchQuery) async { + setState(ViewState.BusyLocal); + await _SOAPService.searchCurrentMedication(searchQuery); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + getCurrentMedicationDetails(String id) async { + setState(ViewState.BusyLocal); + await _SOAPService.getCurrentMedicationDetails(id); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + removeCurrentMedication(String id) async { + setState(ViewState.BusyLocal); + await _SOAPService.removeCurrentMedicationVidaPlus(id); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + addCurrentMedication(request, PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.addCurrentMedicationVidaPlus(request, patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + searchDiagnosis(PatiantInformtion patientInfo, String searchQuery) async { + setState(ViewState.BusyLocal); + await _SOAPService.searchDiagnosis(patientInfo, searchQuery); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + clearSearchResult() { + _SOAPService.clearSearchResult(); + notifyListeners(); + } + + getConditionAndType(PatiantInformtion patientInfo) async { + clearSearchResult(); + setState(ViewState.BusyLocal); + await _SOAPService.getDiagnosisType(patientInfo); + await _SOAPService.getConditionType(patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + getType(PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + // await _SOAPService.getDiagnosisType(patientInfo); + await _SOAPService.getConditionType(patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + getPreviousPatientDetails(PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.getPreviousDiagnosis(patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + getCurrentDiagnosisList(PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.getDiagnosis(patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + getAuditOfDiagnosis( + PatiantInformtion patient, + String patientProblemRevisionID, + ) async { + setState(ViewState.BusyLocal); + await _SOAPService.auditDiagnosis(patient, patientProblemRevisionID); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + SearchDiagnosis? findTheDiagnosisItem(String icdVersion) { + selectedIcd = icdVersion; + return _SOAPService.findParent(icdVersion); + } + + void removeDiagnosis( + PatiantInformtion patientInfo, + PatientPreviousDiagnosis currentDiagnosisItem, + String remarks, + ) async { + setState(ViewState.BusyLocal); + var result = await _SOAPService.removeDiagnosis( + patientInfo, + currentDiagnosisItem.patientProblemId?.toString(), + currentDiagnosisItem.problemId?.toString(), + remarks); + if (result) { + await getCurrentDiagnosisList(patientInfo); + } + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + void favoriteDiagnosis( + PatiantInformtion patientInfo, { + String? patientProblemId, + String? problemId, + String? deletedRemarks, + }) async { + setState(ViewState.BusyLocal); + await _SOAPService.favoriteDiagnosis(patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + Future addToFavoriteDiagnosis(PatiantInformtion patientInfo, + {SearchDiagnosis? diagnosis}) async { + setState(ViewState.BusyLocal); + Map? profile = await sharedPref.getObj(DOCTOR_PROFILE); + Map? user = await sharedPref.getObj(LOGGED_IN_USER); + var userID = user?['List_MemberInformation'][0]['MemberID']; + bool result = await _SOAPService.addToFavoriteDiagnosis(patientInfo, + profile?['DoctorName'] ?? '', diagnosis?.diseasesBCode ?? '', userID); + + // if (diagnosis != null) { + diagnosis?.isFavorite = result; + // searchDiagnosisList[index] = diagnosis; + // } + + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + return diagnosis; + } + + void convertPreviousDiagnosisCurrent(PatiantInformtion paitientInfo, + PatientPreviousDiagnosis diagnosis) async { + setState(ViewState.BusyLocal); + var result = await _SOAPService.convertPreviousDiagnosisCurrent( + paitientInfo, diagnosis); + if (result) { + await getPreviousPatientDetails(paitientInfo); + await getCurrentDiagnosisList(paitientInfo); + } + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + void getPhysicalExamination(PatiantInformtion paitientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.getPhysicalExamination(paitientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + List getListOfSelectedCategory() { + List mappedItems = []; + for (List category in specialityDetails.values) { + var selectedCategory = + category.where((value) => value.isSelected == true); + mappedItems.addAll(selectedCategory); + } + return mappedItems; + } + + Future postPhysicalExamination(PatiantInformtion patientInfo, + List listOfSelectedCategory) async { + setState(ViewState.BusyLocal); + bool result = await _SOAPService.postPhysicalExamination( + patientInfo, listOfSelectedCategory); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + + return result; + } + + getGeneralSpeciality(PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.getGeneralSpeciality(patientInfo); + mainSpecialityList = _SOAPService.generalSpeciality; + speciality = mainSpecialityList ?? []; + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + getSpecialityDetails(String speciality, int? specialityId, + PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + await _SOAPService.getSpecialityDetails( + speciality, specialityId, patientInfo); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + void toggleShowBottomSheetValue(bool status) { + _SOAPService.showAuditBottomSheet = status; + } + + + getProgressNoteAndCondition(PatiantInformtion information) async{ + getPatientConditionList(); + getProgressNote(information); + } + getProgressNote(PatiantInformtion patientInformation) async { + setState(ViewState.BusyLocal); + await _SOAPService.getProgressNoteNew(patientInformation); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + Future createDiagnosis( + PatiantInformtion patientInformation, + SearchDiagnosis? searchDiagnosis, + String? diagnosisType, + String conditionType, + String remarks, + bool isNew) async { + setState(ViewState.BusyLocal); + bool result = await _SOAPService.createDiagnosis(patientInformation, + searchDiagnosis, diagnosisType, conditionType, remarks, isNew); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + + return result; + } + + Future createDiagnosisFromFavorite( + PatiantInformtion patientInformation, + FavoriteDiseaseDetails? searchDiagnosis, + String? diagnosisType, + String conditionType, + String remarks, + bool isNew) async { + setState(ViewState.BusyLocal); + bool result = await _SOAPService.createDiagnosisFromFavorite( + patientInformation, + searchDiagnosis, + diagnosisType, + conditionType, + remarks, + isNew); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + + return result; + } + + Future createProgressNote(PatiantInformtion patient, String? clinicID, + String conditionType, String note) async { + setState(ViewState.BusyLocal); + bool result = await _SOAPService.createProgressNote( + patient, clinicID, conditionType, note); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + + return result; + } + + Future editDiagnosis(PatientPreviousDiagnosis diagnosis) async { + setState(ViewState.BusyLocal); + bool result = await _SOAPService.editDiagnosis(diagnosis); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + return result; + } + + Future resolveDiagnosis( + PatientPreviousDiagnosis diagnosis, PatiantInformtion patientInfo) async { + setState(ViewState.BusyLocal); + bool result = await _SOAPService.resolveDiagnosis(diagnosis); + if (result) { + await getCurrentDiagnosisList(patientInfo); + } + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + return result; + } + + void changeCurrentCategorySelectedState( + GeneralSpeciality selectedExamination, bool status) { + final item = speciality.firstWhere( + (speciality) => speciality.id == selectedExamination.id, + orElse: () => throw Exception( + 'Speciality with ID ${selectedExamination.id} not found!'), + ); + item.isSelected = status; + notifyListeners(); + } + + void filterData(String query) { + if (query.isEmpty) { + speciality = mainSpecialityList ?? []; + } + var searchList = mainSpecialityList + ?.where((value) => + value.name?.toLowerCase().contains(query.toLowerCase()) == true) + .toList() ?? + []; + speciality = searchList; + notifyListeners(); + } + + getClinics() async { + setState(ViewState.BusyLocal); + await _SOAPService.getClinic(); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + getPatientConditionList() async { + setState(ViewState.BusyLocal); + await _SOAPService.getPatientCondition(); + if (_SOAPService.hasError) { + error = _SOAPService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } + + /** + * function that checks if all the mandatory data is obtained from the subjective + * page + * @return [true] if the data is correctly inserted [false] if the data is incomplete + */ + bool isSubjectiveAssesmentCompleted() { + return getChiefComplaintListVidaPlus.isNotEmpty && + getHopiDetails.isNotEmpty && + patientAllergiesVidaPlus.isNotEmpty; + } + + bool isPhysicalExaminationAdded() { + return patientPhysicalExaminationList.isNotEmpty; + } + + bool isDiagnosticsAdded() { + return diagnosisList.isNotEmpty; + } + + bool isProgressAdded() { + return progressNote.isNotEmpty; + } + + void clearAllergy() { + _SOAPService.searchAllergiesList.clear(); + notifyListeners(); + } + + String? getConditionValue(String key){ + print('the value is ${_SOAPService.conditionTypeMapWithIdAsKey[key.trim()]}'); + return _SOAPService.conditionTypeMapWithIdAsKey[key.trim()]; + } + + String? getDiagnosisTypeValue(String key){ + return _SOAPService.diagnosisTypeTypeMapWithIdAsKey[key.trim()]; + } + String? getConditionID(String key){ + print('the value is ${_SOAPService.conditionTypeMapWithIdAsKey[key.trim()]}'); + return _SOAPService.conditionTypeList[key.trim()]; + } + + String? getPatientConditionValue(String key){ + + return _SOAPService.patientConditionMap[key.trim()]; + } } diff --git a/lib/core/viewModel/authentication_view_model.dart b/lib/core/viewModel/authentication_view_model.dart index 28279db7..cdb2bbf7 100644 --- a/lib/core/viewModel/authentication_view_model.dart +++ b/lib/core/viewModel/authentication_view_model.dart @@ -101,7 +101,7 @@ class AuthenticationViewModel extends BaseViewModel { insertIMEIDetailsModel.vidaAuthTokenID = await sharedPref.getString(VIDA_AUTH_TOKEN_ID); insertIMEIDetailsModel.vidaRefreshTokenID = await sharedPref.getString(VIDA_REFRESH_TOKEN_ID); insertIMEIDetailsModel.password = userInfo.password; - insertIMEIDetailsModel.loginDoctorID = loggedUser != null ? loggedUser!.listMemberInformation![0].employeeID : user!.doctorID; + insertIMEIDetailsModel.loginDoctorID = loggedUser != null ? loggedUser!.listMemberInformation![0].employeeID : user!.editedBy; await _authService.insertDeviceImei(insertIMEIDetailsModel); if (_authService.hasError) { @@ -363,8 +363,8 @@ class AuthenticationViewModel extends BaseViewModel { if (_authService.dashboardItemsList.length > 0) { user = _authService.dashboardItemsList[0]; sharedPref.setObj(LAST_LOGIN_USER, _authService.dashboardItemsList[0]); - await sharedPref.setString(VIDA_REFRESH_TOKEN_ID, user!.vidaRefreshTokenID!); - await sharedPref.setString(VIDA_AUTH_TOKEN_ID, user!.vidaAuthTokenID!); + // await sharedPref.setString(VIDA_REFRESH_TOKEN_ID, user!.vidaRefreshTokenID!); + // await sharedPref.setString(VIDA_AUTH_TOKEN_ID, user!.vidaAuthTokenID!); this.unverified = true; } setState(ViewState.Idle); diff --git a/lib/core/viewModel/project_view_model.dart b/lib/core/viewModel/project_view_model.dart index 123482d7..608dca2e 100644 --- a/lib/core/viewModel/project_view_model.dart +++ b/lib/core/viewModel/project_view_model.dart @@ -37,8 +37,12 @@ class ProjectViewModel with ChangeNotifier { List _vidaPlusProjectListModel = []; + List _vidaPlusInPatientsProjectListModel = []; + List get vidaPlusProjectList => _vidaPlusProjectListModel; + List get vidaPlusInPatientsProjectListModel => _vidaPlusInPatientsProjectListModel; + ProjectViewModel() { loadSharedPrefLanguage(); @@ -63,6 +67,11 @@ class ProjectViewModel with ChangeNotifier { notifyListeners(); } + setVidaPlusInPatientProjectList(List vidaPlusInPatientProjectListModelInput) { + _vidaPlusInPatientsProjectListModel = vidaPlusInPatientProjectListModelInput; + notifyListeners(); + } + void loadSharedPrefLanguage() async { currentLanguage = await sharedPref.getString(APP_Language); _appLocale = Locale(currentLanguage ?? 'en'); @@ -117,6 +126,15 @@ class ProjectViewModel with ChangeNotifier { }); setVidaPlusProjectList(_vidaPlusProjectListModel); } + + _vidaPlusInPatientsProjectListModel.clear(); + if (response['ProjectListHMCForDoctorAppInPatient'].length != 0) { + response['ProjectListHMCForDoctorAppInPatient'].forEach((item) { + _vidaPlusInPatientsProjectListModel.add(VidaPlusProjectListModel.fromJson(item)); + }); + setVidaPlusInPatientProjectList(_vidaPlusInPatientsProjectListModel); + } + localRes = response; }, onFailure: (String error, int statusCode) { throw error; diff --git a/lib/main.dart b/lib/main.dart index a4aebd08..24ab7384 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -71,7 +71,8 @@ class MyApp extends StatelessWidget { //buttonColor: HexColor('#D02127'), fontFamily: 'Poppins', dividerColor: Colors.grey[350], - backgroundColor: Color.fromRGBO(255, 255, 255, 1), + + // backgroundColor: Color.fromRGBO(255, 255, 255, 1), useMaterial3: false), navigatorKey: locator().navigatorKey, navigatorObservers: [ diff --git a/lib/routes.dart b/lib/routes.dart index 0dbe8653..25dcf2a2 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -26,6 +26,8 @@ import 'package:doctor_app_flutter/screens/patients/profile/prescriptions/in_pat import 'package:doctor_app_flutter/screens/patients/profile/radiology/radiology_home_page.dart'; import 'package:doctor_app_flutter/screens/patients/profile/referral/refer_details/refer-patient-screen-in-patient.dart'; import 'package:doctor_app_flutter/screens/patients/profile/soap_update/update_soap_index.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/AddChiefComplaints.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/update_soap_index_vida_plus.dart'; import 'package:doctor_app_flutter/screens/patients/profile/vte_assessment/vte_assessment_screen.dart'; import 'package:doctor_app_flutter/screens/prescription/new_prescriptions_page.dart'; import 'package:doctor_app_flutter/screens/prescription/old_prescriptions_page.dart'; @@ -60,6 +62,7 @@ const String PATIENT_INSURANCE_APPROVALS_NEW = 'patients/patient_insurance_appro const String VITAL_SIGN_DETAILS = 'patients/vital-sign-details'; const String CREATE_EPISODE = 'patients/create-episode'; const String UPDATE_EPISODE = 'patients/update-episode'; +const String UPDATE_EPISODE_VIDA_PLUS = 'patients/update-episode-vida-plus'; const String PATIENT_ADMISSION_REQUEST = 'patients/admission-request'; const String PATIENT_ADMISSION_REQUEST_2 = 'patients/admission-request-second'; const String PATIENT_ADMISSION_REQUEST_3 = 'patients/admission-request-third'; @@ -123,6 +126,9 @@ var routes = { UPDATE_EPISODE: (_) => UpdateSoapIndex( isUpdate: true, ), + UPDATE_EPISODE_VIDA_PLUS: (_) => UpdateSoapIndexVidaPlus( + isUpdate: true, + ), IN_PATIENT_PRESCRIPTIONS_DETAILS: (_) => InpatientPrescriptionDetailsScreen(), ADD_SICKLEAVE: (_) => PatientSickLeaveScreen(), ORDER_PRESCRIPTION_OLD: (_) => OldPrescriptionsPage(), diff --git a/lib/screens/auth/verification_methods_screen.dart b/lib/screens/auth/verification_methods_screen.dart index e3c82850..d9bf516c 100644 --- a/lib/screens/auth/verification_methods_screen.dart +++ b/lib/screens/auth/verification_methods_screen.dart @@ -430,6 +430,7 @@ class _VerificationMethodsScreenState extends State { type, authenticationViewModel.loggedUser != null ? authenticationViewModel.loggedUser!.mobileNumber : authenticationViewModel.user!.mobile, (value) { + showDialog( context: context, builder: (BuildContext context) { diff --git a/lib/screens/doctor/doctor_replay/doctor_repaly_chat.dart b/lib/screens/doctor/doctor_replay/doctor_repaly_chat.dart index d6f15ebf..c2e1c274 100644 --- a/lib/screens/doctor/doctor_replay/doctor_repaly_chat.dart +++ b/lib/screens/doctor/doctor_replay/doctor_repaly_chat.dart @@ -337,7 +337,7 @@ class _DoctorReplayChatState extends State { child: Image.asset( widget .previousModel - .doctorProfile + .doctorProfile !.gender == 0 ? 'assets/images/male_avatar.png' diff --git a/lib/screens/home/home_screen.dart b/lib/screens/home/home_screen.dart index 364da5e8..d63ff247 100644 --- a/lib/screens/home/home_screen.dart +++ b/lib/screens/home/home_screen.dart @@ -313,7 +313,7 @@ class _HomeScreenState extends State { List homePatientsCardsWidget(DashboardViewModel model, projectsProvider) { colorIndex = 0; - List backgroundColors =[]; + List backgroundColors = []; backgroundColors.add(LinearGradient(begin: Alignment(-1.0, -2.0), end: Alignment(1.0, 2.0), colors: [ AppGlobal.appRedColor, Color(0xFFAD3B3B), @@ -325,9 +325,9 @@ class _HomeScreenState extends State { backgroundColors.add(LinearGradient(begin: Alignment.center, end: Alignment.center, colors: [Color(0xFF71787E), AppGlobal.appTextColor])); List backgroundIconColors = []; backgroundIconColors.add(Colors.white12); - backgroundIconColors.add( Colors.white38); + backgroundIconColors.add(Colors.white38); backgroundIconColors.add(Colors.white10); - List textColors =[]; + List textColors = []; textColors.add(Colors.white); textColors.add(Color(0xFF353E47)); textColors.add(Colors.white); @@ -388,24 +388,28 @@ class _HomeScreenState extends State { )); changeColorIndex(); - patientCards.add(HomePatientCard( - gradient: backgroundColors[colorIndex], - backgroundIconColor: backgroundIconColors[colorIndex], - cardIcon: DoctorApp.inpatient, - textColor: textColors[colorIndex], - text: TranslationBase.of(context).myInPatient, - onTap: () { - Navigator.push( - context, - FadePage( - page: InPatientScreen( - specialClinic: model.getSpecialClinic(clinicId ?? projectsProvider.doctorClinicsList[0].clinicID), + if (!Utils.isVidaPlusInPatientProject(projectsProvider, model.doctorProfile!.projectID!)) { + patientCards.add(HomePatientCard( + gradient: backgroundColors[colorIndex], + backgroundIconColor: backgroundIconColors[colorIndex], + cardIcon: DoctorApp.inpatient, + textColor: textColors[colorIndex], + text: TranslationBase + .of(context) + .myInPatient, + onTap: () { + Navigator.push( + context, + FadePage( + page: InPatientScreen( + specialClinic: model.getSpecialClinic(clinicId ?? projectsProvider.doctorClinicsList[0].clinicID), + ), ), - ), - ); - }, - )); - changeColorIndex(); + ); + }, + )); + changeColorIndex(); + } //TODO Keep commented // patientCards.add(HomePatientCard( // gradient: backgroundColors[colorIndex], diff --git a/lib/screens/live_care/panding_list.dart b/lib/screens/live_care/panding_list.dart index d14e1bb3..b5c6b914 100644 --- a/lib/screens/live_care/panding_list.dart +++ b/lib/screens/live_care/panding_list.dart @@ -59,7 +59,7 @@ class _LiveCarePandingListState extends State { ? Center( child: Text( _liveCareProvider.errorMsg, - style: TextStyle(color: Theme.of(context).errorColor), + style: TextStyle(color: Colors.red), ), ) : Column( diff --git a/lib/screens/patient-sick-leave/add_patient_sick_leave_screen.dart b/lib/screens/patient-sick-leave/add_patient_sick_leave_screen.dart index 0fb93724..9735fe2c 100644 --- a/lib/screens/patient-sick-leave/add_patient_sick_leave_screen.dart +++ b/lib/screens/patient-sick-leave/add_patient_sick_leave_screen.dart @@ -52,7 +52,9 @@ class _AddPatientSickLeaveScreenState extends State { showDatePicker( context: context, initialDate: currentDate ?? DateTime.now(), - firstDate: DateTime(DateTime.now().year - 1), + firstDate: AppDateUtils.convertStringToDate( + widget!.patient!.arrivedOn!, + ), lastDate: DateTime(DateTime.now().year + 1), ).then((pickedDate) { if (pickedDate == null) { diff --git a/lib/screens/patients/ECGPage.dart b/lib/screens/patients/ECGPage.dart index 46cb2cdc..69cd56c4 100644 --- a/lib/screens/patients/ECGPage.dart +++ b/lib/screens/patients/ECGPage.dart @@ -95,7 +95,7 @@ class ECGPage extends StatelessWidget { children: [ new TextSpan(text: TranslationBase.of(context).orderNo, style: TextStyle(fontSize: 12, fontFamily: 'Poppins')), new TextSpan( - text: '${/*model.patientMuseResultsModelList[index].orderNo?? */ '3455'}', + text: '${model.patientMuseResultsModelList[index].orderNo}', style: TextStyle(fontWeight: FontWeight.w600, fontFamily: 'Poppins', fontSize: 14)), ], ), diff --git a/lib/screens/patients/insurance_approval_screen_patient.dart b/lib/screens/patients/insurance_approval_screen_patient.dart index 1c672582..b2673ef4 100644 --- a/lib/screens/patients/insurance_approval_screen_patient.dart +++ b/lib/screens/patients/insurance_approval_screen_patient.dart @@ -91,6 +91,7 @@ class _InsuranceApprovalScreenNewState }, child: DoctorCardInsurance( patientOut: "In Patient", + onTap: (){}, profileUrl: model .insuranceApprovalInPatient[index] .doctorImage!, @@ -185,6 +186,7 @@ class _InsuranceApprovalScreenNewState '', branch2: model .insuranceApproval[index].projectName!, + onTap: (){}, ), ), ), diff --git a/lib/screens/patients/insurance_approvals_details.dart b/lib/screens/patients/insurance_approvals_details.dart index 2e9f0099..1b2e31e1 100644 --- a/lib/screens/patients/insurance_approvals_details.dart +++ b/lib/screens/patients/insurance_approvals_details.dart @@ -38,7 +38,7 @@ class _InsuranceApprovalsDetailsState extends State { @override Widget build(BuildContext context) { ProjectViewModel projectViewModel = Provider.of(context); - final routeArgs = ModalRoute.of(context)!.settings.arguments as Map; + // final routeArgs = ModalRoute.of(context)!.settings.arguments as Map; return BaseView( onModelReady: (model) => model.insuranceApprovalInPatient.length == 0 @@ -48,676 +48,472 @@ class _InsuranceApprovalsDetailsState extends State { ? (model) => model.getInsuranceApproval(patient, appointmentNo: patient!.appointmentNo, projectId: patient!.projectId) : (model) => model.getInsuranceApproval(patient) : null, - builder: (BuildContext context, InsuranceViewModel model, Widget? child) => - AppScaffold( - isShowAppBar: true, - baseViewModel: model, - appBar: PatientProfileAppBar(patient!), - body: patient!.admissionNo != null - ? SingleChildScrollView( - child: Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ServiceTitle( - title: TranslationBase.of(context).insurance22, - subTitle: TranslationBase.of(context).approvals22, - ), - Container( - margin: EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border.all( - width: 0.5, - color: Colors.white, - ), - borderRadius: BorderRadius.all( - Radius.circular(15.0), - ), - color: Colors.white), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( + builder: (BuildContext context, InsuranceViewModel model, Widget? child) => AppScaffold( + isShowAppBar: true, + baseViewModel: model, + appBar: PatientProfileAppBar(patient!), + body: patient!.admissionNo != null + ? SingleChildScrollView( + child: Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ServiceTitle( + title: TranslationBase.of(context).insurance22, + subTitle: TranslationBase.of(context).approvals22, + ), + Container( + margin: EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border.all( + width: 0.5, + color: Colors.white, + ), + borderRadius: BorderRadius.all( + Radius.circular(15.0), + ), + color: Colors.white), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Row( children: [ - Row( - children: [ - AppText( - model - .insuranceApprovalInPatient[ - indexInsurance] - .approvalStatusDescption != - null - ? model - .insuranceApprovalInPatient[ - indexInsurance] - .approvalStatusDescption ?? - "" - : "", - color: model - .insuranceApprovalInPatient[ - indexInsurance] - .approvalStatusDescption != - null - ? "${model.insuranceApprovalInPatient[indexInsurance].approvalStatusDescption}" == - "Approved" || - "${model.insuranceApprovalInPatient[indexInsurance].approvalStatusDescption}" == - "تمت الموافقة" - ? AppGlobal.appGreenColor - : Color(0xffD02127) - : Color(0xffD02127), - letterSpacing: -0.4, - fontWeight: FontWeight.w600, - fontSize: SizeConfig - .getTextMultiplierBasedOnWidth() * - 2.7, - ), - ], - ), - Row( - children: [ - AppText( - model - .insuranceApprovalInPatient[ - indexInsurance] - .doctorName! - .toUpperCase(), - color: Color(0xff2E303A), - fontSize: 16, - letterSpacing: -0.64, - fontWeight: FontWeight.w600, - ) - ], + AppText( + model.insuranceApprovalInPatient[indexInsurance].approvalStatusDescption != null + ? model.insuranceApprovalInPatient[indexInsurance].approvalStatusDescption ?? "" + : "", + color: model.insuranceApprovalInPatient[indexInsurance].approvalStatusDescption != null + ? "${model.insuranceApprovalInPatient[indexInsurance].approvalStatusDescption}" == "Approved" || + "${model.insuranceApprovalInPatient[indexInsurance].approvalStatusDescption}" == "تمت الموافقة" + ? AppGlobal.appGreenColor + : Color(0xffD02127) + : Color(0xffD02127), + letterSpacing: -0.4, + fontWeight: FontWeight.w600, + fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 2.7, ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0), - child: Row( + ], + ), + Row( + children: [ + AppText( + model.insuranceApprovalInPatient[indexInsurance].doctorName!.toUpperCase(), + color: Color(0xff2E303A), + fontSize: 16, + letterSpacing: -0.64, + fontWeight: FontWeight.w600, + ) + ], + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + children: [ + Column( children: [ - Column( - children: [ - Container( - height: MediaQuery.of(context) - .size - .height * - 0.065, - width: MediaQuery.of(context) - .size - .height * - 0.065, - child: CircleAvatar( - radius: SizeConfig - .imageSizeMultiplier! * - 12, - // radius: (52) - child: ClipRRect( - borderRadius: - BorderRadius.circular( - 50), - child: Image.network( - model - .insuranceApprovalInPatient[ - indexInsurance] - .doctorImage!, - fit: BoxFit.fill, - width: 700, - ), - ), - backgroundColor: - Colors.transparent, + Container( + height: MediaQuery.of(context).size.height * 0.065, + width: MediaQuery.of(context).size.height * 0.065, + child: CircleAvatar( + radius: SizeConfig.imageSizeMultiplier! * 12, + // radius: (52) + child: ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Image.network( + model.insuranceApprovalInPatient[indexInsurance].doctorImage!, + fit: BoxFit.fill, + width: 700, ), ), - ], - ), - Expanded( - child: Padding( - padding: - const EdgeInsets.symmetric( - horizontal: 8.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - //mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - height: 25.0, - ), - CustomRow( - label: TranslationBase.of( - context) - .clinic + - ": ", - value: model - .insuranceApprovalInPatient[ - indexInsurance] - .clinicName!, - ), - CustomRow( - label: TranslationBase.of( - context) - .approvalNo + - ": ", - value: model - .insuranceApprovalInPatient[ - indexInsurance] - .approvalNo - .toString(), - ), - CustomRow( - label: 'Unused Count:', - value: model - .insuranceApprovalInPatient[ - indexInsurance] - .unUsedCount - .toString(), - ), - CustomRow( - label: TranslationBase.of( - context) - .companyName + - ": ", - value: 'Sample'), - CustomRow( - label: TranslationBase.of( - context) - .receiptOn + - ": ", - value: - '${AppDateUtils.getDayMonthYearDateFormatted(AppDateUtils.getDateTimeFromServerFormat(model.insuranceApprovalInPatient[indexInsurance].receiptOn ?? ""), isArabic: projectViewModel.isArabic)}'), - CustomRow( - label: TranslationBase.of( - context) - .expiryDate + - ": ", - value: - '${AppDateUtils.getDayMonthYearDateFormatted(AppDateUtils.getDateTimeFromServerFormat(model.insuranceApprovalInPatient[indexInsurance].expiryDate ?? ""), isArabic: projectViewModel.isArabic)}'), - ], - ), + backgroundColor: Colors.transparent, ), ), ], ), - ), - SizedBox( - height: 20.0, - ), - Container( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0), - child: Row( - children: [ - Expanded( - child: AppText( - TranslationBase.of(context) - .procedure, - fontWeight: FontWeight.w600, - color: Color(0xff2E303A), - letterSpacing: -0.48, - fontSize: SizeConfig - .getTextMultiplierBasedOnWidth() * - 2.9, - ), - ), - Expanded( - child: AppText( - TranslationBase.of(context) - .status, - fontWeight: FontWeight.w600, - color: Color(0xff2E303A), - letterSpacing: -0.48, - fontSize: SizeConfig - .getTextMultiplierBasedOnWidth() * - 2.9, - ), - ), - Expanded( - child: AppText( - TranslationBase.of(context) - .usageStatus, - fontWeight: FontWeight.w600, - color: Color(0xff2E303A), - letterSpacing: -0.48, - fontSize: SizeConfig - .getTextMultiplierBasedOnWidth() * - 2.9, - ), - ) - ], - ), - ), - Divider( - color: Colors.black, + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + //mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + height: 25.0, + ), + CustomRow( + label: TranslationBase.of(context).clinic + ": ", + value: model.insuranceApprovalInPatient[indexInsurance].clinicName!, + ), + CustomRow( + label: TranslationBase.of(context).approvalNo + ": ", + value: model.insuranceApprovalInPatient[indexInsurance].approvalNo.toString(), + ), + CustomRow( + label: 'Unused Count:', + value: model.insuranceApprovalInPatient[indexInsurance].unUsedCount.toString(), + ), + CustomRow(label: TranslationBase.of(context).companyName + ": ", value: model.insuranceApprovalInPatient[indexInsurance].companyName.toString()), + CustomRow( + label: TranslationBase.of(context).receiptOn + ": ", + value: + '${AppDateUtils.getDayMonthYearDateFormatted(AppDateUtils.getDateTimeFromServerFormat(model.insuranceApprovalInPatient[indexInsurance].receiptOn ?? ""), isArabic: projectViewModel.isArabic)}'), + CustomRow( + label: TranslationBase.of(context).expiryDate + ": ", + value: + '${AppDateUtils.getDayMonthYearDateFormatted(AppDateUtils.getDateTimeFromServerFormat(model.insuranceApprovalInPatient[indexInsurance].expiryDate ?? ""), isArabic: projectViewModel.isArabic)}'), + ], ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0), - child: ListView.builder( - shrinkWrap: true, - physics: ScrollPhysics(), - itemCount: model - .insuranceApprovalInPatient[ - indexInsurance] - .apporvalDetails! - .length, - itemBuilder: - (BuildContext context, - int index) { - return Container( - child: Column( + ), + ), + ], + ), + ), + SizedBox( + height: 20.0, + ), + Container( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + children: [ + Expanded( + child: AppText( + TranslationBase.of(context).procedure, + fontWeight: FontWeight.w600, + color: Color(0xff2E303A), + letterSpacing: -0.48, + fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 2.9, + ), + ), + Expanded( + child: AppText( + TranslationBase.of(context).status, + fontWeight: FontWeight.w600, + color: Color(0xff2E303A), + letterSpacing: -0.48, + fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 2.9, + ), + ), + Expanded( + child: AppText( + TranslationBase.of(context).usageStatus, + fontWeight: FontWeight.w600, + color: Color(0xff2E303A), + letterSpacing: -0.48, + fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 2.9, + ), + ) + ], + ), + ), + Divider( + color: Colors.black, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: ListView.builder( + shrinkWrap: true, + physics: ScrollPhysics(), + itemCount: model.insuranceApprovalInPatient[indexInsurance].apporvalDetails!.length, + itemBuilder: (BuildContext context, int index) { + return Container( + child: Column( + children: [ + Row( children: [ - Row( - children: [ - Expanded( - child: Container( - child: AppText( - model - .insuranceApprovalInPatient[ - indexInsurance] - ?.apporvalDetails![ - index] - ?.procedureName ?? - "", - textAlign: - TextAlign - .center, - fontSize: - SizeConfig - .getTextMultiplierBasedOnWidth() * - 2.7, - letterSpacing: - -0.4, - color: Color( - 0xff575757), - fontWeight: - FontWeight - .w500, - ), - ), + Expanded( + child: Container( + child: AppText( + model.insuranceApprovalInPatient[indexInsurance]?.apporvalDetails![index]?.procedureName ?? "", + textAlign: TextAlign.center, + fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 2.7, + letterSpacing: -0.4, + color: Color(0xff575757), + fontWeight: FontWeight.w500, ), - Expanded( - child: Container( - child: AppText( - model - .insuranceApprovalInPatient[ - indexInsurance] - ?.apporvalDetails![ - index] - ?.status ?? - "", - textAlign: - TextAlign - .center, - fontSize: - SizeConfig - .getTextMultiplierBasedOnWidth() * - 2.7, - letterSpacing: - -0.4, - color: Color( - 0xff575757), - fontWeight: - FontWeight - .w500, - ), - ), - ), - Expanded( - child: Container( - child: AppText( - model - .insuranceApprovalInPatient[ - indexInsurance] - ?.apporvalDetails![ - index] - ?.isInvoicedDesc ?? - "", - textAlign: - TextAlign - .center, - fontSize: - SizeConfig - .getTextMultiplierBasedOnWidth() * - 2.7, - letterSpacing: - -0.4, - color: Color( - 0xff575757), - fontWeight: - FontWeight - .w500, - ), - ), - ), - ], + ), ), - SizedBox( - width: 5, + Expanded( + child: Container( + child: AppText( + model.insuranceApprovalInPatient[indexInsurance]?.apporvalDetails![index]?.status ?? "", + textAlign: TextAlign.center, + fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 2.7, + letterSpacing: -0.4, + color: Color(0xff575757), + fontWeight: FontWeight.w500, + ), + ), ), - Divider( - color: Colors.black38, + Expanded( + child: Container( + child: AppText( + model.insuranceApprovalInPatient[indexInsurance]?.apporvalDetails![index]?.isInvoicedDesc ?? "", + textAlign: TextAlign.center, + fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 2.7, + letterSpacing: -0.4, + color: Color(0xff575757), + fontWeight: FontWeight.w500, + ), + ), ), ], ), - ); - }), - ), - ], + SizedBox( + width: 5, + ), + Divider( + color: Colors.black38, + ), + ], + ), + ); + }), ), - ), - ], + ], + ), ), - ), + ], ), - ], + ), ), - ), - ) - : SingleChildScrollView( - child: Container( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Column( + ], + ), + ), + ) + : SingleChildScrollView( + child: Container( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Row( children: [ - Row( - children: [ - AppText( - TranslationBase.of(context).insurance22, - fontSize: 15.0, - fontWeight: FontWeight.w600, - fontFamily: 'Poppins', - ), - ], - ), - Row( - children: [ - AppText( - TranslationBase.of(context).approvals22, - fontSize: 30.0, - fontWeight: FontWeight.w700, - ), - ], + AppText( + TranslationBase.of(context).insurance22, + fontSize: 15.0, + fontWeight: FontWeight.w600, + fontFamily: 'Poppins', ), ], ), - ), - Container( - margin: EdgeInsets.all(10), - decoration: BoxDecoration( - border: Border.all( - width: 0.5, - color: Colors.white, - ), - borderRadius: BorderRadius.all( - Radius.circular(15.0), + Row( + children: [ + AppText( + TranslationBase.of(context).approvals22, + fontSize: 30.0, + fontWeight: FontWeight.w700, ), - color: Colors.white), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( + ], + ), + ], + ), + ), + Container( + margin: EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border.all( + width: 0.5, + color: Colors.white, + ), + borderRadius: BorderRadius.all( + Radius.circular(15.0), + ), + color: Colors.white), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Row( children: [ - Row( - children: [ - AppText( - model - .insuranceApproval[ - indexInsurance] - .approvalStatusDescption != - null - ? model - .insuranceApproval[ - indexInsurance] - .approvalStatusDescption ?? - "" - : "", - color: model - .insuranceApproval[ - indexInsurance] - .approvalStatusDescption != - null - ? "${model.insuranceApproval[indexInsurance].approvalStatusDescption}" == - "Approved" - ? AppGlobal.appGreenColor - : Color(0xffD02127) - : Color(0xffD02127), - ), - ], + AppText( + model.insuranceApproval[indexInsurance].approvalStatusDescption != null ? model.insuranceApproval[indexInsurance].approvalStatusDescption ?? "" : "", + color: model.insuranceApproval[indexInsurance].approvalStatusDescption != null + ? "${model.insuranceApproval[indexInsurance].approvalStatusDescption}" == "Approved" + ? AppGlobal.appGreenColor + : Color(0xffD02127) + : Color(0xffD02127), ), - Row( - children: [ - AppText( - model - .insuranceApproval[indexInsurance] - .doctorName! - .toUpperCase(), - color: Colors.black, - fontSize: 18, - fontWeight: FontWeight.bold, - ) - ], - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0), - child: Row( + ], + ), + Row( + children: [ + AppText( + model.insuranceApproval[indexInsurance].doctorName!.toUpperCase(), + color: Colors.black, + fontSize: 18, + fontWeight: FontWeight.bold, + ) + ], + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + children: [ + Column( children: [ - Column( - children: [ - Container( - height: 85.0, - width: 85.0, - child: CircleAvatar( - radius: SizeConfig - .imageSizeMultiplier! * - 12, - // radius: (52) - child: ClipRRect( - borderRadius: - BorderRadius.circular( - 50), - child: Image.network( - model - .insuranceApproval[ - indexInsurance] - .doctorImage!, - fit: BoxFit.fill, - width: 700, - ), - ), - backgroundColor: - Colors.transparent, + Container( + height: 85.0, + width: 85.0, + child: CircleAvatar( + radius: SizeConfig.imageSizeMultiplier! * 12, + // radius: (52) + child: ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Image.network( + model.insuranceApproval[indexInsurance].doctorImage!, + fit: BoxFit.fill, + width: 700, ), ), - ], + backgroundColor: Colors.transparent, + ), ), - Expanded( - child: Padding( - padding: - const EdgeInsets.symmetric( - horizontal: 8.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - //mainAxisAlignment: MainAxisAlignment.center, + ], + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + //mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + height: 25.0, + ), + Row( children: [ - SizedBox( - height: 25.0, + AppText( + TranslationBase.of(context).clinic + ": ", + color: Colors.grey[500], + fontSize: 14, ), - Row( - children: [ - AppText( - TranslationBase.of( - context) - .clinic + - ": ", - color: Colors.grey[500], - fontSize: 14, - ), - Expanded( - child: AppText( - model - .insuranceApproval[ - indexInsurance] - .clinicName!, - fontSize: 14, - ), - ) - ], + Expanded( + child: AppText( + model.insuranceApproval[indexInsurance].clinicName!, + fontSize: 14, + ), + ) + ], + ), + Row( + children: [ + AppText( + TranslationBase.of(context).approvalNo + ": ", + color: Colors.grey[500], + fontSize: 14, ), - Row( - children: [ - AppText( - TranslationBase.of( - context) - .approvalNo + - ": ", - color: Colors.grey[500], - fontSize: 14, - ), - AppText( - model - .insuranceApproval[ - indexInsurance] - .approvalNo - .toString(), - fontSize: 14, - ) - ], + AppText( + model.insuranceApproval[indexInsurance].approvalNo.toString(), + fontSize: 14, + ) + ], + ), + Row( + children: [ + AppText( + TranslationBase.of(context).unusedCount + ": ", + color: Colors.grey[500], + fontSize: 14, ), - Row( - children: [ - AppText( - TranslationBase.of( - context) - .unusedCount + - ": ", - color: Colors.grey[500], - fontSize: 14, - ), - AppText( - model - .insuranceApproval[ - indexInsurance] - .unUsedCount - .toString(), - fontSize: 14, - ) - ], + AppText( + model.insuranceApproval[indexInsurance].unUsedCount.toString(), + fontSize: 14, + ) + ], + ), + Row( + children: [ + AppText( + TranslationBase.of(context).companyName + ": ", + color: Colors.grey[500], ), - Row( - children: [ - AppText( - TranslationBase.of( - context) - .companyName + - ": ", - color: Colors.grey[500], - ), - AppText('Sample') - ], + AppText('Sample') + ], + ), + Row( + children: [ + AppText( + TranslationBase.of(context).receiptOn + ": ", + color: Colors.grey[500], ), - Row( - children: [ - AppText( - TranslationBase.of( - context) - .receiptOn + - ": ", - color: Colors.grey[500], - ), - Expanded( - child: AppText( - '${AppDateUtils.getDayMonthYearDateFormatted(AppDateUtils.getDateTimeFromServerFormat(model.insuranceApproval[indexInsurance].rceiptOn!), isArabic: projectViewModel.isArabic)}', - color: Colors.black, - fontWeight: - FontWeight.w600, - ), - ), - ], + Expanded( + child: AppText( + '${AppDateUtils.getDayMonthYearDateFormatted(AppDateUtils.getDateTimeFromServerFormat(model.insuranceApproval[indexInsurance].rceiptOn!), isArabic: projectViewModel.isArabic)}', + color: Colors.black, + fontWeight: FontWeight.w600, + ), ), - Row( - children: [ - AppText( - TranslationBase.of( - context) - .expiryDate + - ": ", - color: Colors.grey[500], - ), - if (model - .insuranceApproval[ - indexInsurance] - .expiryDate != - null) - AppText( - '${AppDateUtils.getDayMonthYearDateFormatted(AppDateUtils.getDateTimeFromServerFormat(model.insuranceApproval[indexInsurance].expiryDate!), isArabic: projectViewModel.isArabic)}', - color: Colors.black, - fontWeight: - FontWeight.w600, - ), - ], + ], + ), + Row( + children: [ + AppText( + TranslationBase.of(context).expiryDate + ": ", + color: Colors.grey[500], ), + if (model.insuranceApproval[indexInsurance].expiryDate != null) + AppText( + '${AppDateUtils.getDayMonthYearDateFormatted(AppDateUtils.getDateTimeFromServerFormat(model.insuranceApproval[indexInsurance].expiryDate!), isArabic: projectViewModel.isArabic)}', + color: Colors.black, + fontWeight: FontWeight.w600, + ), ], ), - ), + ], ), - ], + ), ), - ), - SizedBox( - height: 20.0, - ), - Container( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0), - child: Row( - children: [ - Expanded( - child: AppText( - TranslationBase.of(context) - .procedure, - fontWeight: FontWeight.w700, - ), - ), - Expanded( - child: AppText( - TranslationBase.of(context) - .status, - fontWeight: FontWeight.w700, - ), - ), - Expanded( - child: AppText( - TranslationBase.of(context) - .usageStatus, - fontWeight: FontWeight.w700, - ), - ) - ], + ], + ), + ), + SizedBox( + height: 20.0, + ), + Container( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + children: [ + Expanded( + child: AppText( + TranslationBase.of(context).procedure, + fontWeight: FontWeight.w700, + ), ), - ), - Divider( - color: Colors.black, - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0), - child: (model.insuranceApproval[indexInsurance].apporvalDetails != null && model.insuranceApproval[indexInsurance].apporvalDetails!.isNotEmpty) ? ListView.builder( + Expanded( + child: AppText( + TranslationBase.of(context).status, + fontWeight: FontWeight.w700, + ), + ), + Expanded( + child: AppText( + TranslationBase.of(context).usageStatus, + fontWeight: FontWeight.w700, + ), + ) + ], + ), + ), + Divider( + color: Colors.black, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: (model.insuranceApproval[indexInsurance].apporvalDetails != null && model.insuranceApproval[indexInsurance].apporvalDetails!.isNotEmpty) + ? ListView.builder( shrinkWrap: true, physics: ScrollPhysics(), - itemCount: model - .insuranceApproval[ - indexInsurance] - .apporvalDetails! - .length, - itemBuilder: - (BuildContext context, - int index) { + itemCount: model.insuranceApproval[indexInsurance].apporvalDetails!.length, + itemBuilder: (BuildContext context, int index) { return Container( child: Column( children: [ @@ -726,48 +522,24 @@ class _InsuranceApprovalsDetailsState extends State { Expanded( child: Container( child: AppText( - model - .insuranceApproval[ - indexInsurance] - ?.apporvalDetails![ - index] - ?.procedureName ?? - "", - textAlign: - TextAlign - .start, + model.insuranceApproval[indexInsurance]?.apporvalDetails![index]?.procedureName ?? "", + textAlign: TextAlign.start, ), ), ), Expanded( child: Container( child: AppText( - model - .insuranceApproval[ - indexInsurance] - ?.apporvalDetails![ - index] - ?.status ?? - "", - textAlign: - TextAlign - .center, + model.insuranceApproval[indexInsurance]?.apporvalDetails![index]?.status ?? "", + textAlign: TextAlign.center, ), ), ), Expanded( child: Container( child: AppText( - model - .insuranceApproval[ - indexInsurance] - ?.apporvalDetails![ - index] - ?.isInvoicedDesc ?? - "", - textAlign: - TextAlign - .center, + model.insuranceApproval[indexInsurance]?.apporvalDetails![index]?.isInvoicedDesc ?? "", + textAlign: TextAlign.center, ), ), ), @@ -782,19 +554,20 @@ class _InsuranceApprovalsDetailsState extends State { ], ), ); - }) : NoData(), - ), - ], + }) + : NoData(), ), - ), - ], + ], + ), ), - ), + ], ), - ], + ), ), - ), - )), + ], + ), + ), + )), ); } } diff --git a/lib/screens/patients/patient_search/patient_search_header.dart b/lib/screens/patients/patient_search/patient_search_header.dart index d10a163b..b4276dab 100644 --- a/lib/screens/patients/patient_search/patient_search_header.dart +++ b/lib/screens/patients/patient_search/patient_search_header.dart @@ -9,6 +9,7 @@ class PatientSearchHeader extends StatelessWidget implements PreferredSizeWidget @override Widget build(BuildContext context) { return Container( + height: 120, padding: EdgeInsets.only(left: 0, right: 5, bottom: 5, top: 5), decoration: BoxDecoration( color: Colors.white, diff --git a/lib/screens/patients/profile/diagnosis/diagnosis_screen.dart b/lib/screens/patients/profile/diagnosis/diagnosis_screen.dart index 0cbb5dc1..eb994ff4 100644 --- a/lib/screens/patients/profile/diagnosis/diagnosis_screen.dart +++ b/lib/screens/patients/profile/diagnosis/diagnosis_screen.dart @@ -37,6 +37,9 @@ class _ProgressNoteState extends State { // String type = await sharedPref.getString(SLECTED_PATIENT_TYPE); // // print(type); + String type = await sharedPref.getString(SLECTED_PATIENT_TYPE) == '0' ? "2" : "1"; + + print(type); GetDiagnosisForInPatientRequestModel getDiagnosisForInPatientRequestModel = GetDiagnosisForInPatientRequestModel( admissionNo: int.parse(patient.admissionNo!), diff --git a/lib/screens/patients/profile/discharge_summary/all_discharge_summary.dart b/lib/screens/patients/profile/discharge_summary/all_discharge_summary.dart index c4bf99a2..9364def5 100644 --- a/lib/screens/patients/profile/discharge_summary/all_discharge_summary.dart +++ b/lib/screens/patients/profile/discharge_summary/all_discharge_summary.dart @@ -68,25 +68,23 @@ class _AllDischargeSummaryState extends State { ], ), ), - Expanded( - child: Container( - padding: EdgeInsetsDirectional.fromSTEB(30, 0, 30, 0), - child: ListView.builder( - scrollDirection: Axis.vertical, - itemCount: model.allDisChargeSummaryList.length, - shrinkWrap: true, - itemBuilder: (BuildContext ctxt, int index) { - return Column( - children: [ - InkWell( - child: DischargeSummaryWidget( - dischargeSummary: model - .allDisChargeSummaryList[index]), - ), - ], - ); - }), - ), + Container( + padding: EdgeInsetsDirectional.fromSTEB(30, 0, 30, 0), + child: ListView.builder( + scrollDirection: Axis.vertical, + itemCount: model.allDisChargeSummaryList.length, + shrinkWrap: true, + itemBuilder: (BuildContext ctxt, int index) { + return Column( + children: [ + InkWell( + child: DischargeSummaryWidget( + dischargeSummary: model + .allDisChargeSummaryList[index]), + ), + ], + ); + }), ), ], ), diff --git a/lib/screens/patients/profile/discharge_summary/discharge_Summary_widget.dart b/lib/screens/patients/profile/discharge_summary/discharge_Summary_widget.dart index 140a72e2..9005d5ef 100644 --- a/lib/screens/patients/profile/discharge_summary/discharge_Summary_widget.dart +++ b/lib/screens/patients/profile/discharge_summary/discharge_Summary_widget.dart @@ -27,13 +27,12 @@ class _DischargeSummaryWidgetState extends State { @override Widget build(BuildContext context) { ProjectViewModel projectViewModel = Provider.of(context); - return Column( children: [ Container( width: double.infinity, - margin: EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0), - padding: EdgeInsets.all(8.0), + // margin: EdgeInsets.only(top: 8.0, left: 8.0, right: 8.0), + // padding: EdgeInsets.all(8.0), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all( diff --git a/lib/screens/patients/profile/lab_result/labs_home_page.dart b/lib/screens/patients/profile/lab_result/labs_home_page.dart index 463a971c..a234e9e1 100644 --- a/lib/screens/patients/profile/lab_result/labs_home_page.dart +++ b/lib/screens/patients/profile/lab_result/labs_home_page.dart @@ -182,7 +182,7 @@ class _LabsHomePageState extends State { ), ), ), - if (model.patientLabOrdersList.isEmpty && (patient!.patientStatusType != 43 && patient!.patientStatusType !=null)) + if (model.patientLabOrdersList.isEmpty && patient!.patientStatusType != 43) Center( child: ErrorMessage( error: TranslationBase.of(context).noDataAvailable, diff --git a/lib/screens/patients/profile/medical_report/MedicalReportPage.dart b/lib/screens/patients/profile/medical_report/MedicalReportPage.dart index 72a3c742..1e15da45 100644 --- a/lib/screens/patients/profile/medical_report/MedicalReportPage.dart +++ b/lib/screens/patients/profile/medical_report/MedicalReportPage.dart @@ -23,6 +23,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import '../../../../core/model/doctor/doctor_profile_model.dart'; import '../../../../routes.dart'; import 'AddVerifyMedicalReport.dart'; @@ -42,6 +43,7 @@ class _MedicalReportPageState extends State { return BaseView( onModelReady: (model) async { + await model.getDoctorProfile(isGetProfile: true); await model.getMedicalReportList(patient); await model.getMedicalReportTemplate(); }, diff --git a/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart b/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart index bf7f75d0..2725ec19 100644 --- a/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart +++ b/lib/screens/patients/profile/profile_screen/patient_profile_screen.dart @@ -296,8 +296,22 @@ String noteValidation =""; eventCategory: "Patient Profile ", eventAction: "Update Episode", ); + //todo change the navigator to vida plus screen if ((isFromLiveCare && patient.appointmentNo != null && patient.appointmentNo != 0) || patient.patientStatusType == 43 || isInpatient) { - Navigator.of(context).pushNamed(UPDATE_EPISODE, arguments: {'patient': patient}); + if(Utils.isVidaPlusProject( + projectViewModel, + patient.projectId!, + )){ + Navigator.of(context).pushNamed( + UPDATE_EPISODE_VIDA_PLUS, arguments: { + 'patient': patient + }); + }else { + Navigator.of(context).pushNamed( + UPDATE_EPISODE, arguments: { + 'patient': patient + }); + } } }), ], @@ -486,7 +500,18 @@ String noteValidation =""; Utils.showErrorToast(model.error); } else { patient.episodeNo = model.episodeID; - Navigator.of(context).pushNamed(CREATE_EPISODE, arguments: {'patient': patient}); + if(Utils.isVidaPlusProject( + Provider.of(context), + patient.projectId!, + )){ + Navigator.of(context).pushNamed( + UPDATE_EPISODE_VIDA_PLUS, arguments: { + 'patient': patient + }); + }else { + Navigator.of(context).pushNamed( + CREATE_EPISODE, arguments: {'patient': patient}); + } } } } diff --git a/lib/screens/patients/profile/soap_update/assessment/update_assessment_page.dart b/lib/screens/patients/profile/soap_update/assessment/update_assessment_page.dart index aa745578..e04d040d 100644 --- a/lib/screens/patients/profile/soap_update/assessment/update_assessment_page.dart +++ b/lib/screens/patients/profile/soap_update/assessment/update_assessment_page.dart @@ -39,7 +39,8 @@ class UpdateAssessmentPage extends StatefulWidget { class _UpdateAssessmentPageState extends State implements AssessmentCallBack { bool isAssessmentExpand = false; List mySelectedAssessmentList = []; - bool isPrescriptionOrder =false; + bool isPrescriptionOrder = false; + @override Widget build(BuildContext context) { ProjectViewModel projectViewModel = Provider.of(context); @@ -324,20 +325,16 @@ class _UpdateAssessmentPageState extends State implements ), InkWell( onTap: () { - if(model.isPrescriptionOrder && assessment.selectedDiagnosisType!.id ==2) { + if (model.isPrescriptionOrder && assessment.selectedDiagnosisType!.id == 2) { Utils.showErrorToast(TranslationBase.of(context).principalDiagnosisCannot); - }else{ - openAssessmentDialog( - context, isUpdate: true, - assessment: assessment, - model: model); - + } else { + openAssessmentDialog(context, isUpdate: true, assessment: assessment, model: model); } }, child: Icon( DoctorApp.edit, size: 18, - color: model.isPrescriptionOrder && assessment.selectedDiagnosisType!.id ==2 ? Colors.grey : Colors.black , + color: model.isPrescriptionOrder && assessment.selectedDiagnosisType!.id == 2 ? Colors.grey : Colors.black, ), ) ], @@ -393,15 +390,19 @@ class _UpdateAssessmentPageState extends State implements nextFunction(model) { if (mySelectedAssessmentList.isEmpty) { Utils.showErrorToast(TranslationBase.of(context).assessmentErrorMsg); - } else if(!checkPrimaryDiagnosis()) { + } else if (!checkPrimaryDiagnosis()) { Utils.showErrorToast(TranslationBase.of(context).onePrimaryDiagnosis); - }else{ + } else { widget.changeLoadingState(true); widget.changePageViewIndex(3); } } - bool checkPrimaryDiagnosis(){ - List type = mySelectedAssessmentList.where((element) => element.selectedDiagnosisType!.id==2).toList(); - return type.isEmpty ? false : true; + + bool checkPrimaryDiagnosis() { + ProjectViewModel projectViewModel = Provider.of(context, listen: false); + bool isVidaPlus = Utils.isVidaPlusProject(projectViewModel, widget.patientInfo.projectId!); + List type = + mySelectedAssessmentList.where((element) => (element.selectedDiagnosisType!.id == 2 && isVidaPlus == false) || (element.selectedDiagnosisType!.code == '3' && isVidaPlus == true)).toList(); + return type.isEmpty ? false : true; } } diff --git a/lib/screens/patients/profile/soap_update/shared_soap_widgets/bottom_sheet_title.dart b/lib/screens/patients/profile/soap_update/shared_soap_widgets/bottom_sheet_title.dart index fb4201c5..93f3e824 100644 --- a/lib/screens/patients/profile/soap_update/shared_soap_widgets/bottom_sheet_title.dart +++ b/lib/screens/patients/profile/soap_update/shared_soap_widgets/bottom_sheet_title.dart @@ -6,8 +6,9 @@ class BottomSheetTitle extends StatelessWidget implements PreferredSizeWidget { BottomSheetTitle({ Key? key, this.title = '', + this.isClose =true }) : super(key: key); - + bool isClose; final String title; double headerHeight = SizeConfig.heightMultiplier! * 15; @@ -41,7 +42,7 @@ class BottomSheetTitle extends StatelessWidget implements PreferredSizeWidget { onTap: () { Navigator.pop(context); }, - child: Icon(DoctorApp.close_1, size: SizeConfig.getTextMultiplierBasedOnWidth() * 5, color: Color(0xFF2B353E))) + child: isClose ? Icon(DoctorApp.close_1, size: SizeConfig.getTextMultiplierBasedOnWidth() * 5, color: Color(0xFF2B353E)) :SizedBox()) ], ), ], diff --git a/lib/screens/patients/profile/soap_update/shared_soap_widgets/steper/steps_widget.dart b/lib/screens/patients/profile/soap_update/shared_soap_widgets/steper/steps_widget.dart index e2f21a7a..5c9e103e 100644 --- a/lib/screens/patients/profile/soap_update/shared_soap_widgets/steper/steps_widget.dart +++ b/lib/screens/patients/profile/soap_update/shared_soap_widgets/steper/steps_widget.dart @@ -209,52 +209,49 @@ class StepsWidget extends StatelessWidget { Positioned( top: circleTop, right: 0, - child: InkWell( - onTap: () => index >= 3 ? changeCurrentTab!(4) : null, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Container( - width: circleHeight, - height: circleHeight, - decoration: BoxDecoration( - border: index == 3 - ? Border.all(color: Color(0xFFCC9B14), width: 2) - : index > 3 - ? null - : Border.all(color: Color(0xFFCCCCCC), width: 0.75), - shape: BoxShape.circle, - color: index == 3 - ? Color(0xFFCC9B14) - : index > 3 - ? AppGlobal.appGreenColor - : Color(0xFFCCCCCC), - ), - child: Center( - child: Icon( - FontAwesomeIcons.check, - size: 20, - color: Colors.white, - )), - ), - SizedBox( - height: 5, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - StepDetailsWidget( - stepLabel: "Plan", - marginLeft: 30, - ), - StatusLabel( - selectedStepId: index, - stepId: 3, - ), - ], + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Container( + width: circleHeight, + height: circleHeight, + decoration: BoxDecoration( + border: index == 3 + ? Border.all(color: Color(0xFFCC9B14), width: 2) + : index > 3 + ? null + : Border.all(color: Color(0xFFCCCCCC), width: 0.75), + shape: BoxShape.circle, + color: index == 3 + ? Color(0xFFCC9B14) + : index > 3 + ? AppGlobal.appGreenColor + : Color(0xFFCCCCCC), ), - ], - ), + child: Center( + child: Icon( + FontAwesomeIcons.check, + size: 20, + color: Colors.white, + )), + ), + SizedBox( + height: 5, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + StepDetailsWidget( + stepLabel: "Plan", + marginLeft: 30, + ), + StatusLabel( + selectedStepId: index, + stepId: 3, + ), + ], + ), + ], ), ), ], diff --git a/lib/screens/patients/profile/soap_update/subjective/allergies/update_allergies_widget.dart b/lib/screens/patients/profile/soap_update/subjective/allergies/update_allergies_widget.dart index e5ed2a53..6069e09e 100644 --- a/lib/screens/patients/profile/soap_update/subjective/allergies/update_allergies_widget.dart +++ b/lib/screens/patients/profile/soap_update/subjective/allergies/update_allergies_widget.dart @@ -1,8 +1,11 @@ import 'package:doctor_app_flutter/config/size_config.dart'; import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_allergy.dart'; +import 'package:doctor_app_flutter/screens/patients/In_patient/NoData.dart'; import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/remark_text.dart'; import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/remove_button.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/allergies/reactions_selection.dart'; +import 'package:doctor_app_flutter/utils/extenstions_utils.dart'; import 'package:doctor_app_flutter/utils/utils.dart'; import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; @@ -15,7 +18,7 @@ import 'add_allergies.dart'; // ignore: must_be_immutable class UpdateAllergiesWidget extends StatefulWidget { - List? myAllergiesList; + List? myAllergiesList =[]; UpdateAllergiesWidget({Key? key, this.myAllergiesList}); @@ -29,7 +32,7 @@ class _UpdateAllergiesWidgetState extends State { ProjectViewModel projectViewModel = Provider.of(context); changeAllState() { setState(() { - print(widget.myAllergiesList); + }); } @@ -44,7 +47,7 @@ class _UpdateAllergiesWidgetState extends State { SizedBox( height: 20, ), - Container( + widget.myAllergiesList !=null ? Container( margin: EdgeInsets.only(left: 15, right: 15, top: 15), child: Column( children: widget.myAllergiesList!.map((selectedAllergy) { @@ -110,7 +113,7 @@ class _UpdateAllergiesWidgetState extends State { ], ); }).toList()), - ) + ) : SizedBox() ], ); } diff --git a/lib/screens/patients/profile/soap_update/subjective/update_subjective_page.dart b/lib/screens/patients/profile/soap_update/subjective/update_subjective_page.dart index 1bb8c2b7..a7f415c1 100644 --- a/lib/screens/patients/profile/soap_update/subjective/update_subjective_page.dart +++ b/lib/screens/patients/profile/soap_update/subjective/update_subjective_page.dart @@ -206,9 +206,7 @@ class _UpdateSubjectivePageState extends State implements }, child: Column( children: [ - UpdateAllergiesWidget( - myAllergiesList: myAllergiesList, - ), + UpdateAllergiesWidget(myAllergiesList: myAllergiesList,), SizedBox( height: 30, ), diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/add_diagnosis.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/add_diagnosis.dart new file mode 100644 index 00000000..49740fe4 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/add_diagnosis.dart @@ -0,0 +1,104 @@ +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/patient_search/patient_search_header.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/enter_diagnosis.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/favotite_diagnosis.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; + +class AddDiagnosis extends StatefulWidget { + final PatiantInformtion patientInfo; + + const AddDiagnosis({super.key, required this.patientInfo}); + + @override + State createState() => _AddDiagnosisState(); +} + +class _AddDiagnosisState extends State + with SingleTickerProviderStateMixin { + TabController? _tabController; + bool isLoading = true; + + @override + void initState() { + _tabController = new TabController(length: 2, vsync: this); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) { + WidgetsBinding.instance.addPostFrameCallback((_) { + model.getConditionAndType(widget.patientInfo); + model.favoriteDiagnosis(widget.patientInfo); + setState(() { + isLoading = false; + }); + }); + }, + builder: (_, model, w) => AppScaffold( + isLoading: model.state == ViewState.BusyLocal , + isShowAppBar: true, + appBar: PatientSearchHeader( + title: TranslationBase.of(context).addDiagnosis), + backgroundColor: Colors.white, + body: Column( + children: [ + SizedBox( + height: 56, + child: TabBar( + indicatorColor: Color(0xFFD02127), + unselectedLabelColor: Color(0xFF6D6D6D), + labelColor: Color(0xFF2B353E), + controller: _tabController, + tabs: [ + Tab( + child: Text( + TranslationBase.of(context).mappedDiagnosis, + style:TextStyle( + color: Color(0xFF6D6D6D), + fontSize: 14, + fontWeight: FontWeight.w600, + letterSpacing: -0.56, + ) + ), + ), + Tab( + child: Text( + TranslationBase.of(context).favoriteDiagnosis, + style: TextStyle(color: Color(0xFF6D6D6D), + fontSize: 14, + fontWeight: FontWeight.w600, + letterSpacing: -0.56,) + ), + ), + ], + ), + ), + Expanded( + child: TabBarView( + controller: _tabController, + children: [ + EnterDiagnosis( + patientInfo: widget.patientInfo, + ), + FavoriteDiagnosis( + patientInfo: widget.patientInfo, + ), + ], + ), + ), + ], + ), + )); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/update_assessment_page.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/update_assessment_page.dart new file mode 100644 index 00000000..fd6f85ee --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/update_assessment_page.dart @@ -0,0 +1,228 @@ +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/enum/master_lookup_key.dart'; +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_assement.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/icons_app/doctor_app_icons.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/assessment/assessment_call_back.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/SOAP_open_items.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/SOAP_step_header.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/expandable_SOAP_widget.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/remark_text.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/soap_utils.dart'; +import 'package:doctor_app_flutter/utils/date-utils.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/utils/utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../../soap_update/assessment/add_assessment_details.dart'; + +import 'widget/current_diagnosis.dart'; +import 'widget/previous_diagnosis.dart'; + +// ignore: must_be_immutable +class UpdateAssessmentPage extends StatefulWidget { + final Function changePageViewIndex; + final PatiantInformtion patientInfo; + final Function changeLoadingState; + final int currentIndex; + + UpdateAssessmentPage( + {Key? key, + required this.changePageViewIndex, + required this.patientInfo, + required this.changeLoadingState, + required this.currentIndex}); + + @override + _UpdateAssessmentPageState createState() => _UpdateAssessmentPageState(); +} + +class _UpdateAssessmentPageState extends State + with SingleTickerProviderStateMixin + implements AssessmentCallBack { + bool isAssessmentExpand = false; + List mySelectedAssessmentList = []; + bool isPrescriptionOrder = false; + TabController? _tabController; + + @override + void initState() { + _tabController = new TabController(length: 2, vsync: this); + super.initState(); + } + + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + + return BaseView( + onModelReady: (model) async { + model.setAssessmentCallBack(this); + mySelectedAssessmentList.clear(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + widget.changeLoadingState(true); + model.getConditionAndType(widget.patientInfo); + model.getPreviousPatientDetails(widget.patientInfo); + model.getCurrentDiagnosisList(widget.patientInfo); + widget.changeLoadingState(false); + //todo handle get diagnosis list + }); + }, + builder: (_, model, w) => AppScaffold( + isShowAppBar: false, + isLoading: model.state == ViewState.BusyLocal, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + body: SingleChildScrollView( + physics: ScrollPhysics(), + child: Container( + color: Theme.of(context).scaffoldBackgroundColor, + child: Center( + child: FractionallySizedBox( + widthFactor: 0.9, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SOAPStepHeader( + currentIndex: widget.currentIndex, + changePageViewIndex: widget.changePageViewIndex, + patientInfo: widget.patientInfo, + ), + ExpandableSOAPWidget( + headerTitle: TranslationBase.of(context).assessment, + onTap: () { + setState(() { + isAssessmentExpand = !isAssessmentExpand; + }); + }, + child: Column(children: [ + SizedBox( + height: 10, + ), + + SizedBox( + height: 64, + child: TabBar( + indicatorColor: Color(0xFFD02127), + unselectedLabelColor: Color(0xFF6D6D6D), + labelColor: Color(0xFF2B353E), + tabs: [ + Tab( + child: Text( + TranslationBase.of(context) + .currentDiagnosis, + style: TextStyle( + color: Color(0xFF6D6D6D), + fontSize: 14, + fontWeight: FontWeight.w600, + letterSpacing: -0.56,) + ), + ), + Tab( + child: Text( + TranslationBase.of(context) + .previousDiagnosis, + style: TextStyle( + color: Color(0xFF6D6D6D), + fontSize: 14, + fontWeight: FontWeight.w600, + letterSpacing: -0.56,) + ) + ) + ], + controller: _tabController, + ), + ), + SizedBox( + height: 300, + child: TabBarView( + controller: _tabController, + children: [ + CurrentDiagnosis( + patientInfo: widget.patientInfo, + model: model, + currentDiagnosisItems: model.diagnosisList, + ), + PreviousDiagnosis( + diagnosisItems: model.patientPreviousDiagnosis, + patientInfo: widget.patientInfo, + ) + ], + ), + ) + ]), + isExpanded: isAssessmentExpand, + ), + SizedBox( + height: 130, + ), + ], + ), + ), + ), + ), + ), + ), + ); + } + + openAssessmentDialog(BuildContext context, + {MySelectedAssessment? assessment, + bool isUpdate = false, + required SOAPViewModel model}) { + if (assessment == null) { + assessment = SoapUtils.generateMySelectedAssessment( + remark: '', appointmentNo: widget.patientInfo.appointmentNo); + } + showModalBottomSheet( + backgroundColor: Colors.white, + isScrollControlled: true, + context: context, + builder: (context) { + return AddAssessmentDetails( + mySelectedAssessment: assessment!, + patientInfo: widget.patientInfo, + isUpdate: isUpdate, + mySelectedAssessmentList: mySelectedAssessmentList, + addSelectedAssessment: (MySelectedAssessment mySelectedAssessment, + bool isUpdate) async { + setState(() { + if (!isUpdate) + mySelectedAssessmentList.add(mySelectedAssessment); + }); + }); + }); + } + + @override + nextFunction(model) { + if (mySelectedAssessmentList.isEmpty) { + Utils.showErrorToast(TranslationBase.of(context).assessmentErrorMsg); + } else if (!checkPrimaryDiagnosis()) { + Utils.showErrorToast(TranslationBase.of(context).onePrimaryDiagnosis); + } else { + widget.changeLoadingState(true); + widget.changePageViewIndex(3); + } + } + + bool checkPrimaryDiagnosis() { + ProjectViewModel projectViewModel = + Provider.of(context, listen: false); + bool isVidaPlus = Utils.isVidaPlusProject( + projectViewModel, widget.patientInfo.projectId!); + List type = mySelectedAssessmentList + .where((element) => + (element.selectedDiagnosisType!.id == 2 && isVidaPlus == false) || + (element.selectedDiagnosisType!.code == '3' && isVidaPlus == true)) + .toList(); + return type.isEmpty ? false : true; + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/audit_item.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/audit_item.dart new file mode 100644 index 00000000..79a7e297 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/audit_item.dart @@ -0,0 +1,94 @@ +import 'package:doctor_app_flutter/core/model/SOAP/assessment/audit_diagnosis.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class AuditItem extends StatelessWidget { + final AuditDiagnosis auditDiagnosis; + + const AuditItem({super.key, required this.auditDiagnosis}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + AppText( + auditDiagnosis.doctorName ?? '', + fontWeight: FontWeight.w600, + fontSize: 12, + color: Color(0xFF2B353E), + ), + AppText( + getDate(auditDiagnosis.createdOn?.isNotEmpty== true ? auditDiagnosis.createdOn ?? '' : auditDiagnosis.modifiedOn??''), + fontWeight: FontWeight.w600, + fontSize: 10, + color: Color(0xFF2B353E), + ), + ], + ), + SizedBox(height: 4,), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + AppText( + "${TranslationBase.of(context).diagnosis}: ${auditDiagnosis.diagnosisType}", + fontWeight: FontWeight.w600, + fontSize: 12, + color: Color(0xFF2B353E), + ), + AppText( + getTime(auditDiagnosis.createdOn?.isNotEmpty== true ? auditDiagnosis.createdOn ?? '' : auditDiagnosis.modifiedOn??''), + fontWeight: FontWeight.w600, + fontSize: 10, + color: Color(0xFF2B353E), + ), + ], + ), + SizedBox( + height: 4, + ), + + Visibility( + visible: auditDiagnosis.deletedRemarks?.isEmpty == true, + child: AppText( + //todo handle the item after the discussion from the vidapro team this is temporary + "${TranslationBase.of(context).remarks}: ${auditDiagnosis.remarks?.isNotEmpty == true? auditDiagnosis.remarks : TranslationBase.of(context).noRemarks}", + fontWeight: FontWeight.w600, + fontSize: 12, + color: Color(0xFF2B353E), + ), + ), + Visibility( + visible: auditDiagnosis.deletedRemarks?.isNotEmpty == true, + child: AppText( + //todo handle the item after the discussion from the vidapro team this is temporary + "${TranslationBase.of(context).deletedRemarks}${auditDiagnosis.deletedRemarks}", + fontWeight: FontWeight.w600, + fontSize: 12, + color: Color(0xFF2B353E), + ), + ), + ], + ), + ); + } + + String getDate(String dateTime) { + if (dateTime.isEmpty) return ''; + DateTime now = DateTime.now(); + return DateFormat('dd MMM yyyy').format(now); + } + + String getTime(String dateTime) { + if (dateTime.isEmpty) return ''; + DateTime now = DateTime.now(); + return DateFormat('hh:mm a').format(now); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/audit_list_bottom_sheet.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/audit_list_bottom_sheet.dart new file mode 100644 index 00000000..f976063b --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/audit_list_bottom_sheet.dart @@ -0,0 +1,62 @@ +import 'package:doctor_app_flutter/core/model/SOAP/assessment/audit_diagnosis.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/audit_item.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; + +class AuditListBottomSheet extends StatelessWidget { + final List auditList; + + const AuditListBottomSheet({super.key, required this.auditList}); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: (auditList.length>1)?MediaQuery.sizeOf(context).height*.41:MediaQuery.sizeOf(context).height*.28, + child: Material( + color: Color(0xFFF7F7F7), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20))), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 32), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).audit, + fontWeight: FontWeight.w700, + fontSize: 24, + color: Color(0xFF2B353E), + ), + SizedBox( + height: 16, + ), + SizedBox( + height: (auditList.length>1)?MediaQuery.sizeOf(context).height*.25:MediaQuery.sizeOf(context).height*.12, + child: Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10)), + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: ListView.separated( + + itemCount: auditList.length, + itemBuilder: (context, index) => AuditItem( + auditDiagnosis: auditList[index], + ), + separatorBuilder: (_, __) => Divider(), + )) + ], + ), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/current_diagnosis.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/current_diagnosis.dart new file mode 100644 index 00000000..80fc5906 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/current_diagnosis.dart @@ -0,0 +1,324 @@ +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/audit_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/patient_previous_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/add_diagnosis.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/audit_list_bottom_sheet.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/edit_diagnosis.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_diagnosis.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/add_soap_item.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/widgets/SoapDetailItem.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:doctor_app_flutter/widgets/transitions/fade_page.dart'; +import 'package:flutter/material.dart'; + +import '../../../../../../widgets/shared/text_fields/app-textfield-custom.dart'; + +class CurrentDiagnosis extends StatefulWidget { + final PatiantInformtion patientInfo; + final List currentDiagnosisItems; + final SOAPViewModel model; + + const CurrentDiagnosis( + {super.key, + required this.currentDiagnosisItems, + required this.patientInfo, + required this.model}); + + @override + State createState() => _CurrentDiagnosisState(); +} + +class _CurrentDiagnosisState extends State { + TextEditingController deleteController = TextEditingController(); + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) async {}, + builder: (_, model, w) { + if (model.showAudit) { + WidgetsBinding.instance.addPostFrameCallback((_) { + showAuditBottomSheet(context, model.auditDiagnosislist, + model.toggleShowBottomSheetValue); + model.toggleShowBottomSheetValue(false); + }); + } + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + SizedBox( + height: 10, + ), + AddSoapItem( + title: TranslationBase.of(context).addNewDiagnosis, + onAddSoapItemClicked: () async { + bool result = await Navigator.push( + context, + FadePage( + page: AddDiagnosis( + patientInfo: widget.patientInfo, + ))); + if (result) { + model.getCurrentDiagnosisList(widget.patientInfo); + } + }), + SizedBox( + height: 16, + ), + Divider(), + SizedBox( + height: 16, + ), + if (widget.currentDiagnosisItems.isEmpty) ...{ + Center( + child: EmptyDiagnosis(), + ), + } else ...{ + Flexible( + child: ListView.separated( + itemBuilder: (_, index) { + return SoapDetailItem( + title: widget.currentDiagnosisItems[index] + .selectedDisease ?? + '', + status: + widget.currentDiagnosisItems[index].status ?? + '', + condition: model.getConditionValue(widget + .currentDiagnosisItems[index] + .condition ?? + '') ?? + '', + type: model.getDiagnosisTypeValue(widget + .currentDiagnosisItems[index] + .diagnosisType ?? + '') ?? + '', + remarks: + widget.currentDiagnosisItems[index].remarks ?? + '', + onSoapDetailActionClicked: (action) async { + switch (action) { + case SoapDetailItemActions.AUDIT: + model.getAuditOfDiagnosis( + widget.patientInfo, + widget.currentDiagnosisItems[index] + .patientProblemRevisionId + ?.toString() ?? + ''); + break; + case SoapDetailItemActions.EDIT: + if (widget.currentDiagnosisItems[index] + .status == + "Deleted") { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .diagnosisAlreadyDeleted); + return; + } + + if (widget.currentDiagnosisItems[index] + .resolved == + true) { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .diagnosisAlreadyResolved); + return; + } + + bool result = await Navigator.push( + context, + FadePage( + page: EditDiagnosis( + patientInfo: widget.patientInfo, + diagnosis: widget + .currentDiagnosisItems[index], + ))); + if (result) { + model.getCurrentDiagnosisList( + widget.patientInfo); + } + break; + case SoapDetailItemActions.RESOLVE: + if (widget.currentDiagnosisItems[index] + .status == + "Deleted") { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .diagnosisAlreadyDeleted); + return; + } + if (widget.currentDiagnosisItems[index] + .resolved == + true) { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .diagnosisAlreadyResolved); + return; + } + bool result = await model.resolveDiagnosis( + widget.currentDiagnosisItems[index], + widget.patientInfo); + if (result) { + model.getCurrentDiagnosisList( + widget.patientInfo); + } + break; + + case SoapDetailItemActions.REMOVE: + if (widget.currentDiagnosisItems[index] + .status == + "Deleted") { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .diagnosisAlreadyDeleted); + return; + } + if (widget.currentDiagnosisItems[index] + .resolved == + true) { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .diagnosisAlreadyResolved); + return; + } + showConfirmationDialog(context, + "${TranslationBase.of(context).delete} ${TranslationBase.of(context).diagnosis}", + (remarks) { + widget.model.removeDiagnosis( + widget.patientInfo, + widget.currentDiagnosisItems[index], + remarks); + }); + + case SoapDetailItemActions.CHANGE_STATUS: + // TODO: Handle this case. + default: + } + }, + ); + }, + separatorBuilder: (_, index) => Divider(), + itemCount: widget.currentDiagnosisItems.length)) + } + ], + ), + ); + }); + } + + showConfirmationDialog( + BuildContext context, String message, Function(String) okFunction) { + return showDialog( + context: context, + barrierDismissible: true, // user must tap button! + builder: (_) { + return Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + AlertDialog( + title: null, + content: Container( + child: Column( + children: [ + AppText(message), + SizedBox( + height: 8, + ), + AppText( + TranslationBase.of(context) + .areYouSureYouWantToDeleteDiagnosis, + textAlign: TextAlign.center, + ), + SizedBox( + height: 8, + ), + AppTextFieldCustom( + hintText: TranslationBase.of(context).remarks, + controller: deleteController, + maxLines: 25, + minLines: 3, + hasBorder: true, + onChanged: (value) {}, + inputType: TextInputType.multiline, + onClick: () {}, + onFieldSubmitted: () {}, + ), + ], + ), + ), + actions: [ + Row( + children: [ + Expanded( + child: AppButton( + onPressed: () { + Navigator.of(context).pop(); + }, + title: TranslationBase.of(context).cancel, + fontColor: Colors.black, + color: Color(0xffEAEAEA), + ), + ), + SizedBox( + width: 8, + ), + Expanded( + child: AppButton( + onPressed: () { + if (deleteController.text.isEmpty) { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .remarksCanNotBeEmpty); + return; + ; + } + okFunction(deleteController.text); + Navigator.of(context).pop(); + }, + title: TranslationBase.of(context).delete, + fontColor: Colors.white, + color: Colors.red[600], + ), + ), + ], + ), + ], + ), + ], + ), + ); + }).then((value) { + deleteController.clear(); + }); + } + + void showAuditBottomSheet( + BuildContext context, + List diagnosis, + void Function(bool status) toggleShowBottomSheetValue, + ) { + showModalBottomSheet( + isDismissible: true, + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), topRight: Radius.circular(20))), + builder: (_) { + return AuditListBottomSheet( + auditList: diagnosis, + ); + }, + ).then((value) => toggleShowBottomSheetValue(false)); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/edit_diagnosis.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/edit_diagnosis.dart new file mode 100644 index 00000000..a4af47f0 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/edit_diagnosis.dart @@ -0,0 +1,495 @@ +import 'dart:async'; + +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/diagnosis_type.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/patient_previous_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/search_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/patient_search/patient_search_header.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_dropdown.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get_it/get_it.dart'; +import 'package:hexcolor/hexcolor.dart'; + +class EditDiagnosis extends StatefulWidget { + final PatiantInformtion patientInfo; + final PatientPreviousDiagnosis diagnosis; + + const EditDiagnosis( + {super.key, required this.patientInfo, required this.diagnosis}); + + @override + State createState() => _EditDiagnosisState(); +} + +class _EditDiagnosisState extends State { + final TextEditingController filteredSearchController = + TextEditingController(); + bool showAllDiagnosis = true; + String status = ''; + String? selectedDiagnosisItem; + String? selectedDiagnosisItemValue; + TextEditingController remarksController = TextEditingController(); + Timer? _tTimer; + SOAPViewModel? model; + SearchDiagnosis? selectedDiagnosis; + + @override + void initState() { + super.initState(); + filteredSearchController.text = widget.diagnosis.selectedDisease ?? ''; + remarksController.text = widget.diagnosis.remarks ?? ''; + selectedDiagnosisItemValue = widget.diagnosis?.diagnosisType ?? ''; + } + + void _onTextChanged(String text) { + if (_tTimer != null) { + _tTimer!.cancel(); + } + if(text.isEmpty) return; + + _tTimer = Timer(Duration(milliseconds: 500), () { + _onStopped(text); + }); + } + + void _onStopped(String searchText) async { + FocusScope.of(context).unfocus(); + await model?.searchDiagnosis(widget.patientInfo, searchText); + } + + @override + Widget build(BuildContext context) { + return BaseView(onModelReady: (model) { + this.model = model; + WidgetsBinding.instance.addPostFrameCallback((_) { + model.getConditionAndType(widget.patientInfo); + status = + model.getConditionValue(widget.diagnosis.condition ?? '') ?? ''; + }); + }, builder: (_, model, w) { + if (selectedDiagnosisItem == null && model.diagnosisTypeList.isNotEmpty) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + setState(() { + selectedDiagnosisItem = model.diagnosisTypeList.keys.firstWhere( + (k) => + model.diagnosisTypeList[k] == selectedDiagnosisItemValue, + orElse: () => ''); + if (selectedDiagnosisItem?.isEmpty == true) + selectedDiagnosisItem = null; + }); + } + }); + } + return AppScaffold( + isLoading: model.state == ViewState.BusyLocal, + isShowAppBar: true, + appBar: PatientSearchHeader( + title: TranslationBase.of(context).editDiagnosis), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).editDiagnosis, + fontWeight: FontWeight.w600, + color: Color(0xFF2E303A), + fontSize: 16, + ), + SizedBox( + height: 16, + ), + AppTextFieldCustom( + hintText: TranslationBase.of(context).diagnosis, + isTextFieldHasSuffix: true, + hasBorder: true, + controller: filteredSearchController, + onClick: () { + setState( + () { + selectedDiagnosis = null; + filteredSearchController.text = ''; + model.selectedIcd = ''; + }, + ); + }, + onChanged: (value) {}, + onFieldSubmitted: () {}, + onEditingComplete: () { + if (filteredSearchController.text.isEmpty) return; + _onStopped(filteredSearchController.text); + }, + suffixIcon: IconButton( + icon: Icon( + Icons.search, + color: Color(0xff2B353E), + size: 30, + ), + onPressed: () { + if (filteredSearchController.text.isEmpty) return; + _onStopped(filteredSearchController.text); + }, + ), + ), + Material( + elevation: 4.0, // Optional: for shadow effect + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: 0, maxHeight: 300), + child: ListView.builder( + shrinkWrap: true, + itemCount: model.icdVersionList.length, + itemBuilder: (context, index) { + return ListTile( + title: InkWell( + child: AppText(model.icdVersionList[index]), + onTap: () { + setState( + () { + selectedDiagnosis = + model.findTheDiagnosisItem( + model.icdVersionList[index]); + filteredSearchController.text = + model.icdVersionList[index]; + model.searchDiagnosisList.clear(); + model.icdVersionList.clear(); + }, + ); + }, + ), + ); + }, + ), + ), + ), + SizedBox( + height: 8, + ), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Row( + // children: [ + // Switch( + // value: showAllDiagnosis, + // activeColor: Colors.red, + // onChanged: (bool value) { + // setState(() { + // showAllDiagnosis = value; + // }); + // }, + // ), + // SizedBox( + // width: 8, + // ), + // AppText( + // TranslationBase.of(context).showAllDiagnosis, + // fontWeight: FontWeight.w500, + // color: Color(0xFF2E303A), + // fontSize: 11, + // ), + // ], + // ), + // SvgPicture.asset('assets/images/svgs/information.svg'), + // ], + // ), + Container( + margin: EdgeInsets.only(bottom: 12), + child: AppText( + TranslationBase.of(context).condition, + fontWeight: FontWeight.bold, + fontFamily: 'Poppins', + fontSize: 11, + ), + ), + SizedBox( + width: MediaQuery.sizeOf(context).width, + height: 24, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + itemCount: model.conditionTypeList.length, + itemBuilder: (context, index) => InkWell( + onTap: () { + setState(() { + status = model.conditionTypeList[index]; + }); + }, + child: Row( + children: [ + Container( + padding: EdgeInsets.all(2.0), + margin: EdgeInsets.symmetric(horizontal: 6), + width: 20, + height: 20, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: Border.all( + color: Colors.grey, width: 1), + ), + child: Container( + decoration: BoxDecoration( + color: status.toLowerCase() == + model.conditionTypeList[index] + .toLowerCase() + ? HexColor("#D02127") + : Colors.white, + shape: BoxShape.circle, + ), + ), + ), + AppText( + model.conditionTypeList[index], + fontWeight: FontWeight.normal, + fontFamily: 'Poppins', + fontSize: SizeConfig.textMultiplier! * 1.6, + ), + ], + ), + )), + ), + SizedBox( + height: 8, + ), + Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, vertical: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).diagnoseType, + textAlign: TextAlign.start, + fontWeight: FontWeight.w600, + fontSize: 11, + color: Color(0xFF2E303A), + ), + SizedBox( + height: 4, + ), + model.diagnosisTypeList.isEmpty + ? EmptyDropDown() + : DropdownButtonHideUnderline( + child: DropdownButton( + dropdownColor: Colors.white, + iconEnabledColor: Colors.black, + icon: Icon(Icons.keyboard_arrow_down), + isExpanded: true, + value: selectedDiagnosisItem == null + ? model.diagnosisTypeList.keys.first + : selectedDiagnosisItem, + iconSize: 25, + elevation: 16, + onChanged: (newValue) async { + if (newValue != null) + setState(() { + selectedDiagnosisItem = newValue; + selectedDiagnosisItemValue = + model.diagnosisTypeList[newValue]; + }); + }, + items: + model.diagnosisTypeList.keys.map((item) { + return DropdownMenuItem( + child: AppText( + item ?? '', + fontSize: 14, + letterSpacing: -0.96, + color: AppGlobal.appTextColor, + fontWeight: FontWeight.normal, + textAlign: TextAlign.left, + ), + value: item, + ); + }).toList(), + ), + ), + ], + ), + ), + ), + Container( + margin: EdgeInsets.only(top: 8), + child: AppTextFieldCustom( + hintText: TranslationBase.of(context).remarks, + controller: remarksController, + minLines: 2, + maxLines: 4, + inputType: TextInputType.multiline, + onChanged: (value) {}, + onClick: () {}, + onFieldSubmitted: () {}, + ), + ), + SizedBox( + height: 16, + ), + // InkWell( + // onTap: () async { + // if (selectedDiagnosis != null) { + // SearchDiagnosis? diagnosis = + // await model.addToFavoriteDiagnosis(widget.patientInfo, + // diagnosis: selectedDiagnosis); + // setState(() { + // selectedDiagnosis = diagnosis; + // }); + // } + // }, + // child: Row( + // children: [ + // SvgPicture.asset(selectedDiagnosis?.isFavorite == true + // ? 'assets/images/svgs/favoriteadded.svg' + // : 'assets/images/svgs/favorite.svg'), + // SizedBox( + // width: 4, + // ), + // AppText( + // TranslationBase.of(context).addToFavorite, + // textAlign: TextAlign.start, + // fontWeight: FontWeight.w600, + // fontSize: 10, + // color: Color(0xFF449BF1), + // ), + // ], + // ), + // ) + ], + ), + ), + ), + bottomNavigationBar: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(0.0), + ), + border: Border.all(color: HexColor('#707070'), width: 0), + ), + height: SizeConfig.heightMultiplier! * + (SizeConfig.isHeightVeryShort ? 12 : 10), + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(10), + child: Column( + children: [ + Center( + child: Row( + children: [ + Expanded( + child: AppButton( + title: TranslationBase.of(context).previous, + color: Colors.grey[300]!, + fontColor: Colors.black, + fontWeight: FontWeight.w600, + onPressed: () { + Navigator.pop(context); + }, + ), + ), + SizedBox( + width: 5, + ), + Expanded( + child: AppButton( + title: TranslationBase.of(context).save, + fontWeight: FontWeight.w600, + color: Color(0xFF359846), + onPressed: () async { + selectedDiagnosisItem ??= + model.diagnosisTypeList.keys.first; + if (selectedDiagnosis == null && + filteredSearchController.text.isEmpty) { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .selectedDiagnosis); + return; + } + if (status.isEmpty) { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .selectConditionFirst); + return; + } + + if (remarksController.text.isEmpty) { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .remarksCanNotBeEmpty); + return; + } + + if (filteredSearchController.text == + widget.diagnosis.selectedDisease && + status.toLowerCase() == + widget.diagnosis.condition + ?.toLowerCase() && + widget.diagnosis.diagnosisType == + selectedDiagnosisItemValue && + widget.diagnosis.remarks == + remarksController.text) { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .noChangeRecorded); + return; + } + widget.diagnosis.selectedDisease = + filteredSearchController.text; + widget.diagnosis.remarks = remarksController.text; + widget.diagnosis.condition = model.getConditionID(status); + widget.diagnosis.diagnosisType = + selectedDiagnosisItemValue; + + if (selectedDiagnosis != null) { + widget.diagnosis.selectedCategoryCode = + selectedDiagnosis?.selectedCategoryCode ?? + ''; + widget.diagnosis.selectedIcdCode = + selectedDiagnosis?.selectedIcdCode ?? ''; + widget.diagnosis.selectedChapterCode = + selectedDiagnosis?.selectedChapterCode ?? + ''; + widget.diagnosis.selectedSectionCode = + selectedDiagnosis?.selectedSectionCode ?? + ''; + } + + bool result = + await model.editDiagnosis(widget.diagnosis); + if (result) { + Navigator.pop(context, result); + } + }), + ), + ], + ), + ) + ], + ), + ), + ), + ); + }); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_diagnosis.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_diagnosis.dart new file mode 100644 index 00000000..704b41c2 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_diagnosis.dart @@ -0,0 +1,25 @@ +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class EmptyDiagnosis extends StatelessWidget{ + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment : MainAxisAlignment.center, + children: [ + SvgPicture.asset('assets/images/svgs/unavailable.svg'), + SizedBox(height: 10,), + AppText( + TranslationBase.of(context).noDiagnosisFound, + fontSize: 12, + fontWeight: FontWeight.w400, + textAlign: TextAlign.center, + color: Color(0xFFADADAD), + ) + ], + ); + } + +} \ No newline at end of file diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_dropdown.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_dropdown.dart new file mode 100644 index 00000000..1db5dd98 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_dropdown.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +class EmptyDropDown extends StatelessWidget{ + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(12.0), + child: Row( + children: [ + Expanded(child: SizedBox.shrink()), + Align( + alignment: Alignment.centerLeft, + child: Icon(Icons.keyboard_arrow_down), + ) + ], + ), + ); + } + +} \ No newline at end of file diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/enter_diagnosis.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/enter_diagnosis.dart new file mode 100644 index 00000000..42a649d3 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/enter_diagnosis.dart @@ -0,0 +1,426 @@ +import 'dart:async'; + +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/diagnosis_type.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/search_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_dropdown.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:hexcolor/hexcolor.dart'; + +List patientState = ["", "Stable", "Not Stable", "Not Defined"]; + +class EnterDiagnosis extends StatefulWidget { + final PatiantInformtion patientInfo; + + const EnterDiagnosis({super.key, required this.patientInfo}); + + @override + State createState() => _EnterDiagnosisState(); +} + +class _EnterDiagnosisState extends State { + final TextEditingController filteredSearchController = + TextEditingController(); + bool showAllDiagnosis = true; + String status = ''; + String? selectedDiagnosisItem; + String? selectedDiagnosisItemValue; + TextEditingController remarksController = TextEditingController(); + Timer? _tTimer; + SOAPViewModel? model; + SearchDiagnosis? selectedDiagnosis; + + void _onTextChanged(String text) { + // if (_tTimer != null) { + // _tTimer!.cancel(); + // } + // if(text.isEmpty) return; + // _tTimer = Timer(Duration(milliseconds: 500), () { + // _onStopped(text); + // }); + } + + void _onStopped(String searchText) async { + FocusScope.of(context).unfocus(); + await model?.searchDiagnosis(widget.patientInfo, searchText); + } + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) { + this.model = model; + }, + builder: (_, model, w) => AppScaffold( + isShowAppBar: false, + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).addDiagnosis, + fontWeight: FontWeight.w600, + color: Color(0xFF2E303A), + fontSize: 16, + ), + SizedBox( + height: 16, + ), + AppTextFieldCustom( + hintText: TranslationBase.of(context).diagnosis, + isTextFieldHasSuffix: true, + hasBorder: true, + controller: filteredSearchController, + onClick: () { + setState( + () { + selectedDiagnosis = null; + filteredSearchController.text = ''; + model.selectedIcd = ''; + }, + ); + }, + onChanged: (value) { + + }, + onFieldSubmitted: () {}, + onEditingComplete: (){ + if(filteredSearchController.text.isEmpty) return; + _onStopped(filteredSearchController.text); + }, + suffixIcon: IconButton( + icon: Icon( + Icons.search, + color: Color(0xff2B353E), + size: 30, + ), + onPressed: () { + if(filteredSearchController.text.isEmpty) return; + _onStopped(filteredSearchController.text); + }, + ), + ), + Material( + elevation: 4.0, // Optional: for shadow effect + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: 0, maxHeight: 300), + child: ListView.builder( + shrinkWrap: true, + itemCount: model.icdVersionList.length, + itemBuilder: (context, index) { + return ListTile( + title: InkWell( + child: AppText(model.icdVersionList[index]), + onTap: () { + setState( + () { + selectedDiagnosis = + model.findTheDiagnosisItem( + model.icdVersionList[index]); + filteredSearchController.text = + model.icdVersionList[index]; + model.searchDiagnosisList.clear(); + model.icdVersionList.clear(); + }, + ); + }, + ), + ); + }, + ), + ), + ), + SizedBox( + height: 8, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Switch( + value: showAllDiagnosis, + activeColor: Colors.red, + onChanged: (bool value) { + setState(() { + showAllDiagnosis = value; + }); + }, + ), + SizedBox( + width: 8, + ), + AppText( + TranslationBase.of(context).showAllDiagnosis, + fontWeight: FontWeight.w500, + color: Color(0xFF2E303A), + fontSize: 11, + ), + ], + ), + SvgPicture.asset('assets/images/svgs/information.svg'), + ], + ), + Container( + margin: EdgeInsets.only(bottom: 12), + child: AppText( + TranslationBase.of(context).condition, + fontWeight: FontWeight.bold, + fontFamily: 'Poppins', + fontSize: 11, + ), + ), + SizedBox( + width: MediaQuery.sizeOf(context).width, + height: 24, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + itemCount: model.conditionTypeList.length, + itemBuilder: (context, index) => InkWell( + onTap: () { + setState(() { + status = model.conditionTypeList[index]; + }); + }, + child: Row( + children: [ + Container( + padding: EdgeInsets.all(2.0), + margin: EdgeInsets.symmetric(horizontal: 6), + width: 20, + height: 20, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: Border.all( + color: Colors.grey, width: 1), + ), + child: Container( + decoration: BoxDecoration( + color: status == + model.conditionTypeList[index] + ? HexColor("#D02127") + : Colors.white, + shape: BoxShape.circle, + ), + ), + ), + AppText( + model.conditionTypeList[index], + fontWeight: FontWeight.normal, + fontFamily: 'Poppins', + fontSize: SizeConfig.textMultiplier! * 1.6, + ), + ], + ), + )), + ), + SizedBox( + height: 8, + ), + Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, vertical: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).diagnoseType, + textAlign: TextAlign.start, + fontWeight: FontWeight.w600, + fontSize: 11, + color: Color(0xFF2E303A), + ), + SizedBox( + height: 4, + ), + model.diagnosisTypeList.isEmpty + ? EmptyDropDown() + : DropdownButtonHideUnderline( + child: DropdownButton( + dropdownColor: Colors.white, + iconEnabledColor: Colors.black, + icon: Icon(Icons.keyboard_arrow_down), + isExpanded: true, + value: selectedDiagnosisItem == null + ? model.diagnosisTypeList.keys.first + : selectedDiagnosisItem, + iconSize: 25, + elevation: 16, + onChanged: (newValue) async { + if (newValue != null) + setState(() { + selectedDiagnosisItem = newValue; + selectedDiagnosisItemValue = model.diagnosisTypeList[newValue]; + }); + }, + items: + model.diagnosisTypeList.keys.map((item) { + return DropdownMenuItem( + child: AppText( + item ?? '', + fontSize: 14, + letterSpacing: -0.96, + color: AppGlobal.appTextColor, + fontWeight: FontWeight.normal, + textAlign: TextAlign.left, + ), + value: item, + ); + }).toList(), + ), + ), + ], + ), + ), + ), + Container( + margin: EdgeInsets.only(top: 8), + child: AppTextFieldCustom( + hintText: TranslationBase.of(context).remarks, + controller: remarksController, + minLines: 2, + maxLines: 4, + inputType: TextInputType.multiline, + onChanged: (value) {}, + onClick: () {}, + onFieldSubmitted: () {}, + ), + ), + SizedBox( + height: 16, + ), + InkWell( + onTap: () async { + if (selectedDiagnosis != null) { + SearchDiagnosis? diagnosis = + await model.addToFavoriteDiagnosis(widget.patientInfo, + diagnosis: selectedDiagnosis); + setState(() { + selectedDiagnosis = diagnosis; + }); + } + }, + child: Row( + children: [ + SvgPicture.asset(selectedDiagnosis?.isFavorite == true + ? 'assets/images/svgs/favoriteadded.svg' + : 'assets/images/svgs/favorite.svg'), + SizedBox( + width: 4, + ), + AppText( + TranslationBase.of(context).addToFavorite, + textAlign: TextAlign.start, + fontWeight: FontWeight.w600, + fontSize: 10, + color: Color(0xFF449BF1), + ), + ], + ), + ) + ], + ), + ), + ), + bottomNavigationBar: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(0.0), + ), + border: Border.all(color: HexColor('#707070'), width: 0), + ), + height: SizeConfig.heightMultiplier! * + (SizeConfig.isHeightVeryShort ? 12 : 10), + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(10), + child: Column( + children: [ + Center( + child: Row( + children: [ + Expanded( + child: AppButton( + title: TranslationBase.of(context).cancelSmall, + color: Colors.grey[300]!, + fontColor: Colors.black, + fontWeight: FontWeight.w600, + onPressed: () { + Navigator.pop(context); + }, + ), + ), + SizedBox( + width: 5, + ), + Expanded( + child: AppButton( + title: TranslationBase.of(context).save, + fontWeight: FontWeight.w600, + color: Color(0xFF359846), + onPressed: () async { + selectedDiagnosisItem ??= model.diagnosisTypeList.keys.first; + selectedDiagnosisItemValue = model.diagnosisTypeList[selectedDiagnosisItem]; + + if(selectedDiagnosis == null ){ + DrAppToastMsg.showErrorToast(TranslationBase.of(context).selectedDiagnosis); + return; + } + if(status.isEmpty){ + DrAppToastMsg.showErrorToast(TranslationBase.of(context).selectConditionFirst); + return; + } + + if(remarksController.text.isEmpty){ + DrAppToastMsg.showErrorToast(TranslationBase.of(context).remarksCanNotBeEmpty); + return; + } + + bool result = await model.createDiagnosis( + widget.patientInfo, + selectedDiagnosis, + selectedDiagnosisItemValue, + status, + remarksController.text, + false); + if (result) { + Navigator.pop(context, result); + } + }, + ), + ), + ], + ), + ) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/favotite_diagnosis.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/favotite_diagnosis.dart new file mode 100644 index 00000000..c65d145e --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/favotite_diagnosis.dart @@ -0,0 +1,492 @@ +import 'dart:async'; + +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/FavoriteDiseaseDetails.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/diagnosis_type.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/search_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_dropdown.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:hexcolor/hexcolor.dart'; + +List patientState = ["", "Stable", "Not Stable", "Not Defined"]; + +class FavoriteDiagnosis extends StatefulWidget { + final PatiantInformtion patientInfo; + + const FavoriteDiagnosis({super.key, required this.patientInfo}); + + @override + State createState() => _FavoriteDiagnosisState(); +} + +class _FavoriteDiagnosisState extends State { + final TextEditingController filteredSearchController = + TextEditingController(); + bool showAllDiagnosis = true; + String status = ''; + String? selectedDiagnosisItem; + String? selectedDiagnosisItemValue; + FavoriteDiseaseDetails? selectedFavorite; + TextEditingController remarksController = TextEditingController(); + Timer? _tTimer; + SOAPViewModel? model; + SearchDiagnosis? selectedDiagnosis; + + void _onTextChanged(String text) { + if (_tTimer != null) { + _tTimer!.cancel(); + } + _tTimer = Timer(Duration(milliseconds: 500), () { + _onStopped(text); + }); + } + + void _onStopped(String searchText) async { + await model?.searchDiagnosis(widget.patientInfo, searchText); + } + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) { + this.model = model; + WidgetsBinding.instance.addPostFrameCallback((_) { + model.favoriteDiagnosis(widget.patientInfo); + }); + }, + builder: (_, model, w) => AppScaffold( + isShowAppBar: false, + body: SingleChildScrollView( + child: Padding( + padding: + const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).addDiagnosis, + fontWeight: FontWeight.w600, + color: Color(0xFF2E303A), + fontSize: 16, + ), + SizedBox( + height: 16, + ), + Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, vertical: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).diagnosis, + textAlign: TextAlign.start, + fontWeight: FontWeight.w600, + fontSize: 11, + color: Color(0xFF2E303A), + ), + SizedBox( + height: 4, + ), + model.favoriteDiagnosisDetails.isEmpty + ? EmptyDropDown() + : DropdownButtonHideUnderline( + child: DropdownButton( + dropdownColor: Colors.white, + iconEnabledColor: Colors.black, + icon: Icon(Icons.keyboard_arrow_down), + isExpanded: true, + itemHeight: null, + value: selectedFavorite == null + ? model.favoriteDiagnosisDetails.first + : selectedFavorite, + iconSize: 25, + elevation: 16, + onChanged: (newValue) async { + if (newValue != null) + setState(() { + selectedFavorite = newValue; + }); + }, + items: model.favoriteDiagnosisDetails + .map((item) { + return DropdownMenuItem( + child: AppText( + item.diseases ?? '', + fontSize: 14, + letterSpacing: -0.96, + color: AppGlobal.appTextColor, + fontWeight: FontWeight.normal, + textAlign: TextAlign.left, + ), + value: item, + ); + }).toList(), + ), + ), + ], + ), + ), + ), + + SizedBox( + height: 8, + ), + Container( + margin: EdgeInsets.only(bottom: 12), + child: AppText( + TranslationBase.of(context).condition, + fontWeight: FontWeight.bold, + fontFamily: 'Poppins', + fontSize: 11, + ), + ), + // Row( + // children: [ + // Expanded( + // child: InkWell( + // onTap: () { + // setState(() { + // status = ""; + // }); + // }, + // child: Row( + // children: [ + // Container( + // padding: EdgeInsets.all(2.0), + // margin: EdgeInsets.symmetric(horizontal: 6), + // width: 20, + // height: 20, + // decoration: BoxDecoration( + // color: Colors.white, + // shape: BoxShape.circle, + // border: + // Border.all(color: Colors.grey, width: 1), + // ), + // child: Container( + // decoration: BoxDecoration( + // color: status == 1 + // ? HexColor("#D02127") + // : Colors.white, + // shape: BoxShape.circle, + // ), + // ), + // ), + // AppText( + // TranslationBase.of(context).acute, + // fontWeight: FontWeight.normal, + // fontFamily: 'Poppins', + // fontSize: SizeConfig.textMultiplier! * 1.6, + // ), + // ], + // ), + // )), + // Expanded( + // child: InkWell( + // onTap: () { + // setState(() { + // status = "2"; + // }); + // }, + // child: Row( + // children: [ + // Container( + // padding: EdgeInsets.all(2.0), + // margin: EdgeInsets.symmetric(horizontal: 6), + // width: 20, + // height: 20, + // decoration: BoxDecoration( + // color: Colors.white, + // shape: BoxShape.circle, + // border: Border.all( + // color: Colors.grey, width: 1), + // ), + // child: Container( + // decoration: BoxDecoration( + // color: status == 2 + // ? HexColor("#D02127") + // : Colors.white, + // shape: BoxShape.circle, + // ), + // ), + // ), + // AppText( + // TranslationBase.of(context).subAcute, + // fontWeight: FontWeight.normal, + // fontFamily: 'Poppins', + // fontSize: SizeConfig.textMultiplier! * 1.6, + // ), + // ], + // ), + // ), + // ), + // Expanded( + // child: InkWell( + // onTap: () { + // setState(() { + // status = "3"; + // }); + // }, + // child: Row( + // children: [ + // Container( + // padding: EdgeInsets.all(2.0), + // margin: EdgeInsets.symmetric(horizontal: 6), + // width: 20, + // height: 20, + // decoration: BoxDecoration( + // color: Colors.white, + // shape: BoxShape.circle, + // border: Border.all( + // color: Colors.grey, width: 1), + // ), + // child: Container( + // decoration: BoxDecoration( + // color: status == 3 + // ? HexColor("#D02127") + // : Colors.white, + // shape: BoxShape.circle, + // ), + // ), + // ), + // AppText( + // TranslationBase.of(context).chronic, + // fontWeight: FontWeight.normal, + // fontFamily: 'Poppins', + // fontSize: SizeConfig.textMultiplier! * 1.6, + // ), + // ], + // ), + // ), + // ), + // ], + // ), + SizedBox( + width: MediaQuery.sizeOf(context).width, + height: 24, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + itemCount: model.conditionTypeList.length, + itemBuilder: (context, index) => InkWell( + onTap: () { + setState(() { + status = model.conditionTypeList[index]; + }); + }, + child: Row( + children: [ + Container( + padding: EdgeInsets.all(2.0), + margin: + EdgeInsets.symmetric(horizontal: 6), + width: 20, + height: 20, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: Border.all( + color: Colors.grey, width: 1), + ), + child: Container( + decoration: BoxDecoration( + color: status == + model.conditionTypeList[index] + ? HexColor("#D02127") + : Colors.white, + shape: BoxShape.circle, + ), + ), + ), + AppText( + model.conditionTypeList[index], + fontWeight: FontWeight.normal, + fontFamily: 'Poppins', + fontSize: + SizeConfig.textMultiplier! * 1.6, + ), + ], + ), + )), + ), + SizedBox( + height: 8, + ), + Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, vertical: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).diagnoseType, + textAlign: TextAlign.start, + fontWeight: FontWeight.w600, + fontSize: 11, + color: Color(0xFF2E303A), + ), + SizedBox( + height: 4, + ), + model.diagnosisTypeList.isEmpty + ? EmptyDropDown() + : DropdownButtonHideUnderline( + child: DropdownButton( + dropdownColor: Colors.white, + iconEnabledColor: Colors.black, + icon: Icon(Icons.keyboard_arrow_down), + isExpanded: true, + value: selectedDiagnosisItem == null + ? model.diagnosisTypeList.keys.first + : selectedDiagnosisItem, + iconSize: 25, + elevation: 16, + onChanged: (newValue) async { + if (newValue != null) + setState(() { + selectedDiagnosisItem = newValue; + selectedDiagnosisItemValue = model.diagnosisTypeList[newValue]; + }); + }, + items: + model.diagnosisTypeList.keys.map((item) { + return DropdownMenuItem( + child: AppText( + item ?? '', + fontSize: 14, + letterSpacing: -0.96, + color: AppGlobal.appTextColor, + fontWeight: FontWeight.normal, + textAlign: TextAlign.left, + ), + value: item, + ); + }).toList(), + ), + ), + ], + ), + ), + ), + Container( + margin: EdgeInsets.only(top: 8), + child: AppTextFieldCustom( + hintText: TranslationBase.of(context).remarks, + controller: remarksController, + minLines: 2, + maxLines: 4, + inputType: TextInputType.multiline, + onChanged: (value) {}, + onClick: () {}, + onFieldSubmitted: () {}, + ), + ), + SizedBox( + height: 16, + ), + ], + ), + ), + ), + bottomNavigationBar: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(0.0), + ), + border: Border.all(color: HexColor('#707070'), width: 0), + ), + height: SizeConfig.heightMultiplier! * + (SizeConfig.isHeightVeryShort ? 12 : 10), + width: double.infinity, + child: Padding( + padding: const EdgeInsets.all(10), + child: Column( + children: [ + Center( + child: Row( + children: [ + Expanded( + child: AppButton( + title: TranslationBase.of(context).cancelSmall, + color: Colors.grey[300]!, + fontColor: Colors.black, + fontWeight: FontWeight.w600, + onPressed: () { + Navigator.pop(context); + }, + ), + ), + SizedBox( + width: 5, + ), + Expanded( + child: AppButton( + title: TranslationBase.of(context).save, + fontWeight: FontWeight.w600, + color: Color(0xFF359846), + onPressed: () async { + selectedDiagnosisItem ??= model.diagnosisTypeList.keys.first; + selectedDiagnosisItemValue = model.diagnosisTypeList[selectedDiagnosisItem]; + selectedFavorite ??=model.favoriteDiagnosisDetails.first; + + if(status.isEmpty){ + DrAppToastMsg.showErrorToast(TranslationBase.of(context).selectConditionFirst); + return; + } + + if(remarksController.text.isEmpty){ + DrAppToastMsg.showErrorToast(TranslationBase.of(context).remarksCanNotBeEmpty); + return; + } + + bool result = await model.createDiagnosisFromFavorite( + widget.patientInfo, + selectedFavorite, + selectedDiagnosisItemValue, + status, + remarksController.text, + false); + if (result) { + Navigator.pop(context, result); + } + }, + ), + ), + ], + ), + ) + ], + ), + ), + ), + )); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/previous_diagnosis.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/previous_diagnosis.dart new file mode 100644 index 00000000..1df5714c --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/previous_diagnosis.dart @@ -0,0 +1,104 @@ +import 'package:doctor_app_flutter/core/model/SOAP/assessment/audit_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/assessment/patient_previous_diagnosis.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/audit_list_bottom_sheet.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_diagnosis.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/previous_diagnosis_item.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/add_soap_item.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/widgets/SoapDetailItem.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:flutter/material.dart'; + +import '../../../../../../core/viewModel/SOAP_view_model.dart'; + +class PreviousDiagnosis extends StatelessWidget { + final List diagnosisItems; + final PatiantInformtion patientInfo; + + const PreviousDiagnosis( + {super.key, required this.diagnosisItems, required this.patientInfo}); + + @override + Widget build(BuildContext context) { + if (diagnosisItems.isEmpty) + return Center( + child: EmptyDiagnosis(), + ); + + return BaseView( + onModelReady: (model) async {}, + builder: (_, model, w) { + if (model.showAudit) { + WidgetsBinding.instance.addPostFrameCallback((_) { + showAuditBottomSheet(context, model.auditDiagnosislist, + model.toggleShowBottomSheetValue); + model.toggleShowBottomSheetValue(false); + }); + } + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + child: ListView.separated( + itemBuilder: (_, index) { + return PreviousDiagnosisItem( + title: diagnosisItems[index].selectedDisease ?? '', + status: diagnosisItems[index].status ?? '', + condition: diagnosisItems[index].condition ?? '', + remarks: diagnosisItems[index].remarks ?? '', + type: model.getDiagnosisTypeValue( + diagnosisItems[index].diagnosisType ?? '') ?? + '', + isPreviousAddedToCurrent: + diagnosisItems[index].visitWiseSelected == true, + onSoapDetailActionClicked: (action) { + switch (action) { + case SoapDetailItemActions.AUDIT: + model.getAuditOfDiagnosis( + patientInfo, + diagnosisItems[index] + .patientProblemRevisionId + ?.toString() ?? + ''); + break; + case SoapDetailItemActions.CHANGE_STATUS: + model.convertPreviousDiagnosisCurrent( + patientInfo, diagnosisItems[index]); + default: + } + }, + ); + }, + separatorBuilder: (_, index) => Divider(), + itemCount: diagnosisItems.length), + ) + ], + ), + ); + }); + } + + void showAuditBottomSheet( + BuildContext context, + List diagnosis, + void Function(bool status) toggleShowBottomSheetValue, + ) { + showModalBottomSheet( + isDismissible: true, + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), topRight: Radius.circular(20))), + builder: (_) { + return AuditListBottomSheet( + auditList: diagnosis, + ); + }, + ).then((value) => toggleShowBottomSheetValue(false)); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/previous_diagnosis_item.dart b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/previous_diagnosis_item.dart new file mode 100644 index 00000000..1bab8dcf --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/assessment/widget/previous_diagnosis_item.dart @@ -0,0 +1,153 @@ +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/widgets/SoapDetailItem.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:hexcolor/hexcolor.dart'; + +typedef OnSoapDetailActionClicked = Function(SoapDetailItemActions); + +class PreviousDiagnosisItem extends StatelessWidget { + final String title; + final String condition; + final String status; + final String remarks; + final String? type; + final bool isPreviousAddedToCurrent; + final OnSoapDetailActionClicked onSoapDetailActionClicked; + + const PreviousDiagnosisItem( + {super.key, + required this.title, + required this.condition, + required this.remarks, + required this.onSoapDetailActionClicked, + required this.status, + this.type, + required this.isPreviousAddedToCurrent}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Stack( + // children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + title, + color: Color(0XFF2B353E), + fontSize: 12, + fontWeight: FontWeight.bold, + ), + SizedBox( + height: 4, + ), + Row( + children: [ + AppText( + "${TranslationBase.of(context).condition}:", + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + SizedBox( + width: 4, + ), + AppText( + condition, + color: Color(0xffD02127), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ], + ), + ], + ), + ), + Status(status: status), + ], + ), + Visibility( + visible: remarks.isNotEmpty, + child: Column( + children: [ + SizedBox( + height: 8, + ), + AppText( + remarks, + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w400, + ), + ], + )) + ], + ), + // Align( + // alignment: Alignment.topRight, child: Status(status: status)) + // ], + // ), + SizedBox( + height: 16, + ), + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => + onSoapDetailActionClicked(SoapDetailItemActions.AUDIT), + child: SoapDetailItemActionsView( + icon: 'assets/images/svgs/audit.svg', + fontColor: Color(0XFF2B353E), + text: TranslationBase.of(context).audit, + ), + ), + SizedBox( + width: 16, + ), + SizedBox( + width: 187, + height: 27, + child: Material( + color: isPreviousAddedToCurrent + ? Color(0xffEAEAEA) + : HexColor("#D02127"), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5.0)), + child: InkWell( + onTap: () { + if (!isPreviousAddedToCurrent) // to make it clickable if it has not been added to the current diagnosis + onSoapDetailActionClicked( + SoapDetailItemActions.CHANGE_STATUS); + }, + child: Center( + child: AppText( + TranslationBase.of(context).makeCurrentDiagnosis, + color: Colors.white, + )), + ), + ), + ) + ], + ) + ], + ), + ); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/objective/add_details_to_examination_vida_plus.dart b/lib/screens/patients/profile/soap_update_vida_plus/objective/add_details_to_examination_vida_plus.dart new file mode 100644 index 00000000..86d0bf15 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/objective/add_details_to_examination_vida_plus.dart @@ -0,0 +1,322 @@ +import 'package:doctor_app_flutter/core/enum/master_lookup_key.dart'; +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/GeneralSpeciality.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_examination.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/routes.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/patient_search/patient_search_header.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/expandable_SOAP_widget.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/objective/widget/examination_items.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/add_soap_item.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../../../../../core/model/SOAP/physical_exam/Category.dart'; +import '../../../../../core/viewModel/project_view_model.dart'; + +class AddDetailsToExaminationVidaPlus extends StatefulWidget { + final List? mySelectedExamination; + final PatiantInformtion patientInfo; + + const AddDetailsToExaminationVidaPlus( + {super.key, this.mySelectedExamination, required this.patientInfo}); + + @override + State createState() => + _AddDetailsToExaminationVidaPlusState(); +} + +class _AddDetailsToExaminationVidaPlusState + extends State { + String currentlyExpanded = ''; + + @override + Widget build(BuildContext context) { + print('the widget is build'); + ProjectViewModel projectViewModel = Provider.of(context); + return BaseView( + onModelReady: (model) async { + WidgetsBinding.instance.addPostFrameCallback((_) async { + widget.mySelectedExamination?.forEach((value) => + model.getSpecialityDetails( + value.name ?? '', value.id, widget.patientInfo)); + }); + }, + builder: (_, model, w) => AppScaffold( + isShowAppBar: true, + isLoading: model.state == ViewState.BusyLocal, + appBar: PatientSearchHeader( + title: TranslationBase.of(context).examinationPart), + backgroundColor: Colors.white, + body: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + children: [ + Expanded( + child: ListView.separated( + itemBuilder: (context, index) { + var title = + model.specialityDetails.keys.elementAt(index); + return ExpandableSOAPWidget( + headerTitle: title, + onTap: () { + setState(() { + if (currentlyExpanded == title) { + currentlyExpanded = ''; + } else + currentlyExpanded = title; + }); + }, + child: ExaminationItems( + examination: model.specialityDetails[title]), + isExpanded: currentlyExpanded == title, + ); + }, + separatorBuilder: (context, index) { + return SizedBox( + height: 8, + ); + }, + itemCount: model.specialityDetails.length ?? 0), + ), + ], + ), + ), + bottomNavigationBar: Material( + color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + Expanded( + child: AppButton( + title: TranslationBase.of(context).cancelSmall, + color: Color(0xffEAEAEA), + fontColor: Colors.black, + fontWeight: FontWeight.w600, + onPressed: () async { + Navigator.pop(context); + }, + ), + ), + SizedBox( + width: 10, + ), + Expanded( + child: AppButton( + title: TranslationBase.of(context).saveSmall, + color: Color(0xff359846), + fontColor: Colors.white, + fontWeight: FontWeight.w600, + onPressed: () async { + var listOfSelectedCategory = + model.getListOfSelectedCategory(); + + + if (listOfSelectedCategory.isEmpty) { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .kindlySelectCategory); + return; + } + /* if (listOfSelectedCategory.any((value) { + return value.remarksController.text.isEmpty && value.conditionsList?.firstWhere((item){ + return item.conditionName == value.selectedCondition; + }).conditionCode?.toLowerCase() == TranslationBase.of(context).normal.toLowerCase(); + })) { + DrAppToastMsg.showErrorToast( + TranslationBase.of(context) + .remarksCanNotBeEmpty); + return; + }*/ + if(listOfSelectedCategory.any((value) { + print('the value is ${value.selectedConditionName}'); + return value.remarksController.text.isEmpty == true && value.selectedConditionName.isNotEmpty &&value.selectedConditionName != TranslationBase.of(context).normal.toLowerCase(); })) { + DrAppToastMsg.showErrorToast(TranslationBase.of(context).remarksCanNotBeEmpty); + return; + } + var result = + await model.postPhysicalExamination( + widget.patientInfo, + listOfSelectedCategory); + if (result) { + model.getPhysicalExamination( + widget.patientInfo); + Navigator.popUntil(context, ((route) { + if (route.settings.name == + UPDATE_EPISODE_VIDA_PLUS) { + return true; + } else { + return false; + } + })); + } + }, + ), + ), + ], + ))), + )); + } +} + +/* Container( + padding: EdgeInsets.symmetric(horizontal: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only(bottom: 8), + child: AppText( + TranslationBase.of(context).status, + fontWeight: FontWeight.bold, + fontFamily: 'Poppins', + fontSize: SizeConfig.textMultiplier! * 1.6, + ), + ), + Row( + children: [ + Expanded( + child: InkWell( + onTap: () { + setState(() { + status = 1; + }); + examination.isNormal = true; + examination.isAbnormal = false; + examination.notExamined = false; + }, + child: Row( + children: [ + Container( + padding: EdgeInsets.all(2.0), + margin: EdgeInsets.symmetric(horizontal: 6), + width: 20, + height: 20, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: Border.all(color: Colors.grey, width: 1), + ), + child: Container( + decoration: BoxDecoration( + color: status == 1 ? HexColor("#D02127") : Colors.white, + shape: BoxShape.circle, + ), + ), + ), + AppText( + TranslationBase.of(context).normal, + fontWeight: FontWeight.normal, + fontFamily: 'Poppins', + fontSize: SizeConfig.textMultiplier! * 1.6, + ), + ], + ), + )), + Expanded( + child: InkWell( + onTap: () { + setState(() { + status = 2; + }); + examination.isNormal = false; + examination.isAbnormal = true; + examination.notExamined = false; + }, + child: Row( + children: [ + Container( + padding: EdgeInsets.all(2.0), + margin: EdgeInsets.symmetric(horizontal: 6), + width: 20, + height: 20, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: Border.all(color: Colors.grey, width: 1), + ), + child: Container( + decoration: BoxDecoration( + color: status == 2 ? HexColor("#D02127") : Colors.white, + shape: BoxShape.circle, + ), + ), + ), + AppText( + TranslationBase.of(context).abnormal, + fontWeight: FontWeight.normal, + fontFamily: 'Poppins', + fontSize: SizeConfig.textMultiplier! * 1.6, + ), + ], + ), + )), + if (!examination.isLocal) + Expanded( + child: InkWell( + onTap: () { + setState(() { + status = 3; + }); + examination.isNormal = false; + examination.isAbnormal = false; + examination.notExamined = true; + }, + child: Row( + children: [ + Container( + padding: EdgeInsets.all(2.0), + margin: EdgeInsets.symmetric(horizontal: 6), + width: 20, + height: 20, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: Border.all(color: Colors.grey, width: 1), + ), + child: Container( + decoration: BoxDecoration( + color: status == 3 ? HexColor("#D02127") : Colors.white, + shape: BoxShape.circle, + ), + ), + ), + Expanded( + child: AppText( + TranslationBase.of(context).notExamined, + fontWeight: FontWeight.normal, + fontFamily: 'Poppins', + fontSize: SizeConfig.textMultiplier! * 1.6, + ), + ), + ], + ), + )), + ], + ), + Container( + margin: EdgeInsets.only(top: 8), + child: AppTextFieldCustom( + hintText: TranslationBase.of(context).remarks, + controller: remarksController, + minLines: 2, + maxLines: 4, + inputType: TextInputType.multiline, + onChanged: (value) { + examination.remark = value; + }, + onClick: () {}, + onFieldSubmitted: () {}, + ), + ), + ], + ), + );*/ diff --git a/lib/screens/patients/profile/soap_update_vida_plus/objective/add_examination_page_vida_plus.dart b/lib/screens/patients/profile/soap_update_vida_plus/objective/add_examination_page_vida_plus.dart new file mode 100644 index 00000000..56140917 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/objective/add_examination_page_vida_plus.dart @@ -0,0 +1,156 @@ +import 'package:doctor_app_flutter/core/enum/master_lookup_key.dart'; +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/GeneralSpeciality.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/patient_physical_examination.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_examination.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/authentication_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/patient_search/patient_search_header.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/objective/add_details_to_examination_vida_plus.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:doctor_app_flutter/widgets/transitions/fade_page.dart'; +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; + +import 'examinations_list_search_vida_plus_widget.dart'; + +class AddExaminationPageVidaPlus extends StatefulWidget { + final PatiantInformtion patientInfo; + final List? examination; + + ///todo handle the data if edit is added + AddExaminationPageVidaPlus({required this.patientInfo, this.examination}); + + @override + _AddExaminationPageVidaPlusState createState() => + _AddExaminationPageVidaPlusState(); +} + +class _AddExaminationPageVidaPlusState + extends State { + List mySelectedExaminationLocal = []; + + @override + initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) async { + WidgetsBinding.instance.addPostFrameCallback((_) async => + await model.getGeneralSpeciality(widget.patientInfo) + ); + }, + builder: (_, model, w) => AppScaffold( + isShowAppBar: true, + isLoading: model.state == ViewState.BusyLocal, + appBar: PatientSearchHeader( + title: TranslationBase.of(context).examinationPart), + backgroundColor: Colors.white, + body: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: ExaminationsListSearchVidaPlusWidget( + masterList: model.speciality, + removeExamination: (selectedExamination) { + if(selectedExamination == null ) return; + setState(() { + mySelectedExaminationLocal + .remove(selectedExamination); + // Find the object by its ID + try { + model.changeCurrentCategorySelectedState(selectedExamination, false); + } catch (e) {} + }); + }, + addExamination: (selectedExamination) { + if(selectedExamination == null ) return; + + mySelectedExaminationLocal.insert( + 0, selectedExamination); + + try { + model.changeCurrentCategorySelectedState(selectedExamination, true); + } catch (e) {} + //setState(() {}); + }, + ), + ), + ), + ], + ), + ), + bottomNavigationBar: Material( + color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + Expanded( + child: AppButton( + title: TranslationBase.of(context).cancelSmall, + color: Color(0xffEAEAEA), + fontColor: Colors.black, + fontWeight: FontWeight.w600, + onPressed: () async { + Navigator.pop(context); + }, + ), + ), + SizedBox( + width: 10, + ), + Expanded( + child: AppButton( + title: TranslationBase.of(context).next, + color: Color(0xffD02127), + fontColor: Colors.white, + fontWeight: FontWeight.w600, + onPressed: () async { + if(mySelectedExaminationLocal.isEmpty){ + DrAppToastMsg.showErrorToast(TranslationBase.of(context).kindlySelectCategory); + return; + } + pushAddExamination(mySelectedExaminationLocal); + }, + ), + ), + ], + ))), + ), + ); + } + + void pushAddExamination( + List mySelectedExaminationLocal) { + Navigator.push( + context, + FadePage( + page: AddDetailsToExaminationVidaPlus( + mySelectedExamination: mySelectedExaminationLocal, + patientInfo: widget.patientInfo, + ), + ), + ); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/objective/add_examination_vida_plus_widget.dart b/lib/screens/patients/profile/soap_update_vida_plus/objective/add_examination_vida_plus_widget.dart new file mode 100644 index 00000000..5721dc70 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/objective/add_examination_vida_plus_widget.dart @@ -0,0 +1,90 @@ +// ignore: must_be_immutable +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/GeneralSpeciality.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_examination.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/expandable-widget-header-body.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:provider/provider.dart'; + +// ignore: must_be_immutable +class AddExaminationVidaPlusWidget extends StatefulWidget { + GeneralSpeciality? item; + final Function(GeneralSpeciality?) removeExamination; + final Function(GeneralSpeciality?) addExamination; + + final List? mySelectedExamination; + + AddExaminationVidaPlusWidget({ + this.item, + required this.removeExamination, + required this.addExamination, + this.mySelectedExamination, + }); + + @override + _AddExaminationVidaPlusWidgetState createState() => _AddExaminationVidaPlusWidgetState(); +} + +class _AddExaminationVidaPlusWidgetState extends State { + int status = 1; + TextEditingController remarksController = TextEditingController(); + MySelectedExamination examination = MySelectedExamination(); + + @override + void initState() { + + super.initState(); + } + + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + onExamTap(); + }, + child: Row( + children: [ + Checkbox( + value:widget.item?.isSelected ?? false, + activeColor: Colors.red[800], + onChanged: (bool? newValue) { + onExamTap(); + }), + Container( + child: AppText( + widget.item?.name ?? '', + color: Color(0xFF575757), + fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * (SizeConfig.isWidthLarge ? 3 : 3.8), + letterSpacing: -0.56, + ), + ), + ], + ), + ), + ], + ); + } + + onExamTap() { + if(widget.item != null ){ + if(widget.item?.isSelected == true){ + widget.removeExamination(widget.item); + }else{ + widget.addExamination(widget.item); + + } + } + } + +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/objective/examinations_list_search_vida_plus_widget.dart b/lib/screens/patients/profile/soap_update_vida_plus/objective/examinations_list_search_vida_plus_widget.dart new file mode 100644 index 00000000..f293df1e --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/objective/examinations_list_search_vida_plus_widget.dart @@ -0,0 +1,132 @@ +import 'package:doctor_app_flutter/core/model/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/GeneralSpeciality.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/patient_physical_examination.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_examination.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/objective/add_examination_vida_plus_widget.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/utils/utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/divider_with_spaces_around.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; + +class ExaminationsListSearchVidaPlusWidget extends StatefulWidget { + final Function(GeneralSpeciality?) removeExamination; + final Function(GeneralSpeciality?) addExamination; + final List? masterList; + + ExaminationsListSearchVidaPlusWidget( + {required this.removeExamination, + required this.addExamination, + this.masterList}); + + @override + _ExaminationsListSearchVidaPlusWidgetState createState() => + _ExaminationsListSearchVidaPlusWidgetState(); +} + +class _ExaminationsListSearchVidaPlusWidgetState + extends State { + int expandedIndex = -1; + List? items = []; + TextEditingController filteredSearchController = TextEditingController(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BaseView( + + builder: (_, model, w) => Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: AppTextFieldCustom( + height: Utils.getTextFieldHeight(), + hintText: TranslationBase.of(context).searchExamination, + isTextFieldHasSuffix: false, + hasBorder: false, + controller: filteredSearchController, + onChanged: (value) { + if (value != null) filterSearchResults(model,value); + }, + suffixWidget: InkWell( + child: Icon( + Icons.search, + color: Colors.black, + ), + onTap: () {}, + ), + onClick: () {}, + onFieldSubmitted: () {}, + ), + ), + ), + + + ...model.speciality.mapIndexed((index, item) { + return Column( + children: [ + AddExaminationVidaPlusWidget( + item: item, + addExamination: widget.addExamination, + removeExamination: widget.removeExamination, + ), + SizedBox(height: 8,), + Divider() + ], + ); + }).toList(), + ], + ), + )); + } + + void filterSearchResults(SOAPViewModel model,String query) { + model.filterData(query); + // List dummySearchList = []; + // dummySearchList.addAll(widget.masterList as Iterable); + // if (query.isNotEmpty) { + // List dummyListData = []; + // dummySearchList.forEach((item) { + // if (item.nameAr!.toLowerCase().contains(query.toLowerCase()) || item.nameEn!.toLowerCase().contains(query.toLowerCase())) { + // dummyListData.add(item); + // } + // }); + // setState(() { + // items!.clear(); + // items!.addAll(dummyListData); + // }); + // return; + // } else { + // setState(() { + // items!.clear(); + // items!.addAll(widget.masterList as Iterable); + // }); + // } + } +} + +extension FicListExtension on List { + /// Maps each element of the list. + /// The [map] function gets both the original [item] and its [index]. + Iterable mapIndexed(E Function(int index, T item) map) sync* { + for (var index = 0; index < length; index++) { + yield map(index, this[index]); + } + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/objective/list_of_examination.dart b/lib/screens/patients/profile/soap_update_vida_plus/objective/list_of_examination.dart new file mode 100644 index 00000000..082221f5 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/objective/list_of_examination.dart @@ -0,0 +1,44 @@ +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/patient_physical_examination.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_examination.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/widgets/SoapDetailItem.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../../../../../utils/translations_delegate_base_utils.dart'; + +class ListOfExamination extends StatelessWidget { + final List listOfSelection; + + const ListOfExamination({super.key, required this.listOfSelection}); + + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + return Flexible( + child: ListView.separated( + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemBuilder: (_, index) => SoapDetailItem( + title: "${listOfSelection[index].specialityDescription}>${listOfSelection[index].physicalExaminationDescription}", + condition: getCondition(listOfSelection[index].physicalExaminationCondition ?? 3, context)??TranslationBase.of(context).notExamined, + remarks: listOfSelection[index].remark??'', + onSoapDetailActionClicked: (action) { + ///todo handle the event as per the actiion + /// the action is [SoapDetailItemActions] + }, + status: TranslationBase.of(context).active, + showActions: false, + ), + separatorBuilder: (_, __) => Divider(), + itemCount: listOfSelection.length), + ); + } + + String? getCondition(int condition, BuildContext context) => condition == 1 + ? TranslationBase.of(context).normal + : condition == 2 + ? TranslationBase.of(context).abnormal + : TranslationBase.of(context).notExamined; +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/objective/update_objective_page_vida_plus.dart b/lib/screens/patients/profile/soap_update_vida_plus/objective/update_objective_page_vida_plus.dart new file mode 100644 index 00000000..6cadab91 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/objective/update_objective_page_vida_plus.dart @@ -0,0 +1,334 @@ +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/config/shared_pref_kay.dart'; +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/enum/master_lookup_key.dart'; +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/patient_physical_examination.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/post_physical_exam_request_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_examination.dart'; +import 'package:doctor_app_flutter/core/model/doctor/doctor_profile_model.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/objective/add_examination_page.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/SOAP_step_header.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/expandable_SOAP_widget.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/soap_utils.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/objective/add_examination_page_vida_plus.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/objective/list_of_examination.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/objective/widget/EmptyExamination.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/add_soap_item.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/utils/utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/transitions/fade_page.dart'; +import 'package:flutter/material.dart'; + +import '../../soap_update/objective/examination_item_card.dart'; +import '../../soap_update/objective/objective_call_back.dart'; +import '../../soap_update/shared_soap_widgets/SOAP_open_items.dart'; +import 'add_details_to_examination_vida_plus.dart'; + +class UpdateObjectivePageVidaPlus extends StatefulWidget { + final Function changePageViewIndex; + final Function changeLoadingState; + final int currentIndex; + final PatiantInformtion patientInfo; + + UpdateObjectivePageVidaPlus( + {Key? key, + required this.changePageViewIndex, + required this.patientInfo, + required this.changeLoadingState, + required this.currentIndex}); + + @override + _UpdateObjectivePageVidaPlusState createState() => + _UpdateObjectivePageVidaPlusState(); +} + +class _UpdateObjectivePageVidaPlusState + extends State implements ObjectiveCallBack { + bool isSysExaminationExpand = false; + List mySelectedExamination = []; + + BoxDecoration containerBorderDecoration( + Color containerColor, Color borderColor) { + return BoxDecoration( + color: containerColor, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.all(Radius.circular(6)), + border: Border.fromBorderSide(BorderSide( + color: borderColor, + width: 0.5, + )), + ); + } + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) async { + WidgetsBinding.instance.addPostFrameCallback((_) async { + widget.changeLoadingState(true); + + model.getPhysicalExamination(widget.patientInfo); + + widget.changeLoadingState(false); + }); + }, + builder: (_, model, w) => AppScaffold( + isShowAppBar: false, + isLoading: model.state == ViewState.BusyLocal, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + body: SingleChildScrollView( + physics: ScrollPhysics(), + child: Center( + child: FractionallySizedBox( + widthFactor: 0.9, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SOAPStepHeader( + currentIndex: widget.currentIndex, + changePageViewIndex: widget.changePageViewIndex, + patientInfo: widget.patientInfo, + ), + ExpandableSOAPWidget( + headerTitle: + TranslationBase.of(context).physicalExamination, + onTap: () { + setState(() { + isSysExaminationExpand = !isSysExaminationExpand; + }); + }, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 10, + ), + AddSoapItem( + title: + TranslationBase.of(context).physicalExamination, + onAddSoapItemClicked: () { + openExaminationList(context); + }), + SizedBox( + height: 16, + ), + + if (model.patientPhysicalExaminationList.isEmpty) ...{ + Center( + child: Padding( + padding: const EdgeInsets.all(65), + child: EmptyWidget(TranslationBase.of(context) + .noPhysicalExamination), + ), + ), + } else ...{ + Divider(), + ListOfExamination( + listOfSelection: model.patientPhysicalExaminationList) + } + + // if (mySelectedExamination.isNotEmpty && mySelectedExamination.first.isLocal) + // Row( + // children: [ + // AppText( + // "New", + // fontWeight: FontWeight.w600, + // fontFamily: 'Poppins', + // color: Color(0xFFCC9B14), + // ), + // ], + // ), + // Column( + // children: mySelectedExamination + // .sublist(0, model.getFirstIndexForOldExamination(mySelectedExamination) == -1 ? 0 : model.getFirstIndexForOldExamination(mySelectedExamination)) + // .map((examination) { + // return ExaminationItemCard(examination, () { + // removeExamination(examination.selectedExamination!); + // }); + // }).toList(), + // ), + // if (mySelectedExamination.isNotEmpty && model.getFirstIndexForOldExamination(mySelectedExamination) > -1) + // Row( + // children: [ + // AppText( + // "Verified", + // fontWeight: FontWeight.w600, + // fontFamily: 'Poppins', + // color: AppGlobal.appGreenColor, + // ), + // ], + // ), + // Column( + // children: mySelectedExamination + // .sublist(model.getFirstIndexForOldExamination(mySelectedExamination) == -1 ? 0 : model.getFirstIndexForOldExamination(mySelectedExamination)) + // .map((examination) { + // return ExaminationItemCard(examination, () { + // removeExamination(examination.selectedExamination!); + // }); + // }).toList(), + // ) + ], + ), + isExpanded: isSysExaminationExpand, + ), + SizedBox( + height: SizeConfig.heightMultiplier! * + (SizeConfig.isHeightVeryShort ? 14 : 12), + ) + ], + ), + ), + ), + ), + ), + ); + } + + // submitUpdateObjectivePage(SOAPViewModel model) async { + // if (mySelectedExamination.isNotEmpty) { + // if (!model.isAddExamInProgress && + // widget.patientInfo.admissionNo != null && + // widget.patientInfo.admissionNo!.isNotEmpty) { + // Navigator.of(context).pop(); + // } else { + // widget.changeLoadingState(true); + // Map profile = await sharedPref.getObj(DOCTOR_PROFILE); + // + // DoctorProfileModel doctorProfile = DoctorProfileModel.fromJson(profile); + // PostPhysicalExamRequestModel postPhysicalExamRequestModel = + // new PostPhysicalExamRequestModel(); + // mySelectedExamination.forEach((exam) { + // if (postPhysicalExamRequestModel + // .listHisProgNotePhysicalExaminationVM == + // null) + // postPhysicalExamRequestModel.listHisProgNotePhysicalExaminationVM = + // []; + // ListHisProgNotePhysicalExaminationVM + // listHisProgNotePhysicalExaminationVM = + // ListHisProgNotePhysicalExaminationVM( + // patientMRN: widget.patientInfo.patientMRN, + // episodeId: widget.patientInfo.episodeNo == null + // ? 0 + // : widget.patientInfo.episodeNo, + // appointmentNo: widget.patientInfo.appointmentNo == null + // ? 0 + // : widget.patientInfo.appointmentNo, + // remarks: exam.remark ?? '', + // createdBy: exam.createdBy ?? doctorProfile.doctorID, + // createdOn: exam.createdOn ?? DateTime.now().toIso8601String(), + // editedBy: doctorProfile.doctorID, + // editedOn: DateTime.now().toIso8601String(), + // examId: exam.selectedExamination!.id, + // examType: exam.selectedExamination!.typeId, + // isAbnormal: exam.isAbnormal, + // isNormal: exam.isNormal, + // notExamined: exam.notExamined, + // examinationType: exam.isNormal + // ? 1 + // : exam.isAbnormal + // ? 2 + // : 3, + // examinationTypeName: exam.isNormal + // ? "Normal" + // : exam.isAbnormal + // ? 'AbNormal' + // : "Not Examined", + // isNew: exam.isNew, + // ); + // if (widget.patientInfo.admissionNo != null && + // widget.patientInfo.admissionNo!.isNotEmpty) { + // listHisProgNotePhysicalExaminationVM.admissionNo = + // int.parse(widget.patientInfo.admissionNo!); + // } else { + // listHisProgNotePhysicalExaminationVM.admissionNo = 0; + // } + // postPhysicalExamRequestModel.listHisProgNotePhysicalExaminationVM! + // .add(listHisProgNotePhysicalExaminationVM); + // }); + // + // if (model.patientPhysicalExamList.isEmpty) { + // await model.postPhysicalExam(postPhysicalExamRequestModel); + // } else { + // await model.patchPhysicalExam(postPhysicalExamRequestModel); + // } + // + // if (model.state == ViewState.ErrorLocal) { + // widget.changeLoadingState(false); + // Utils.showErrorToast(model.error); + // if (widget.patientInfo.admissionNo != null && + // widget.patientInfo.admissionNo!.isNotEmpty) { + // // Navigator.of(context).pop(); + // model.isAddExamInProgress = false; + // } + // } else { + // if (widget.patientInfo.admissionNo != null && + // widget.patientInfo.admissionNo!.isNotEmpty) { + // // Navigator.of(context).pop(); + // widget.changeLoadingState(false); + // model.isAddExamInProgress = false; + // } else { + // widget.changeLoadingState(true); + // widget.changePageViewIndex(2); + // } + // } + // } + // } else { + // Utils.showErrorToast(TranslationBase.of(context).examinationErrorMsg); + // } + // } + + // removeExamination(MasterKeyModel masterKey) { + // Iterable history = mySelectedExamination.where( + // (element) => + // masterKey.id == element.selectedExamination!.id && + // masterKey.typeId == element.selectedExamination!.typeId); + // + // if (history.length > 0) { + // setState(() { + // if (history.first.isLocal) { + // mySelectedExamination.remove(history.first); + // } else { + // history.first.notExamined = true; + // history.first.isNormal = false; + // history.first.isAbnormal = false; + // } + // }); + // } + // } + + openExaminationList(BuildContext context) { + Navigator.push( + context, + FadePage( + page: AddExaminationPageVidaPlus( + patientInfo: widget.patientInfo, + ), + ), + ); + } + + @override + nextFunction(model) async { + // await submitUpdateObjectivePage(model); + } + + // void pushAddExamination( + // List mySelectedExaminationLocal) { + // Navigator.push( + // context, + // FadePage( + // page: AddDetailsToExaminationVidaPlus( + // mySelectedExamination: mySelectedExamination, + // ), + // ), + // ); + // } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/objective/widget/EmptyExamination.dart b/lib/screens/patients/profile/soap_update_vida_plus/objective/widget/EmptyExamination.dart new file mode 100644 index 00000000..2d9094f4 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/objective/widget/EmptyExamination.dart @@ -0,0 +1,32 @@ +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import '../../../../../../../utils/translations_delegate_base_utils.dart'; + +class EmptyWidget extends StatelessWidget{ + + String message = ""; + + + EmptyWidget(this.message); + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment : MainAxisAlignment.center, + children: [ + SvgPicture.asset('assets/images/svgs/unavailable.svg'), + SizedBox(height: 10,), + AppText( + this.message, + //TranslationBase.of(context).noPhysicalExamination, + fontSize: 12, + fontWeight: FontWeight.w400, + textAlign: TextAlign.center, + color: Color(0xFFADADAD), + ) + ], + ); + } + +} \ No newline at end of file diff --git a/lib/screens/patients/profile/soap_update_vida_plus/objective/widget/examination_items.dart b/lib/screens/patients/profile/soap_update_vida_plus/objective/widget/examination_items.dart new file mode 100644 index 00000000..126e84e1 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/objective/widget/examination_items.dart @@ -0,0 +1,652 @@ +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/physical_exam/Category.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_examination.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:provider/provider.dart'; + +class ExaminationItems extends StatefulWidget { + final List? examination; + + const ExaminationItems({super.key, this.examination}); + + @override + State createState() => _ExaminationItemsState(); +} + +class _ExaminationItemsState extends State { + bool isExpanded = false; + + List? examinations; + + @override + void initState() { + // TODO: implement initState + super.initState(); + this.examinations = widget.examination; + } + + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + return SingleChildScrollView( + child: Column( + children: examinations?.map((value)=> Column( + children: [ + ListTileTheme( + horizontalTitleGap: 0, + child: CheckboxListTile( + activeColor: Color(0xFFD02127), + checkColor: Colors.white, + contentPadding: EdgeInsets.zero, + side: MaterialStateBorderSide.resolveWith( + (Set states) { + if (states.contains(MaterialState.selected)) { + return const BorderSide(color: Color(0xFFD02127)); + } + return const BorderSide(color: Color(0xFFE6E6E6)); + }, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16)), + value: value.isSelected, + controlAffinity: ListTileControlAffinity.leading, + onChanged: (bool? selected) { + setState(() { + value?.isSelected = selected ?? false; + }); + }, + title: AppText( + value.name!, + color: Color(0XFF575757), + fontSize: 14, + fontWeight: FontWeight.w400, + ), + ), + ), + (value.isSelected == true) + ? Container( + padding: EdgeInsets.symmetric(horizontal: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only(bottom: 8), + child: AppText( + TranslationBase.of(context).condition, + fontWeight: FontWeight.bold, + fontFamily: 'Poppins', + fontSize: SizeConfig.textMultiplier! * 1.6, + ), + ), + SizedBox( + width: MediaQuery.sizeOf(context).width, + height: 24, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + itemCount: value + .conditionsList + ?.length ?? + 0, + itemBuilder: (context, currentIndex) => InkWell( + onTap: () { + setState(() { + value + .selectedConditionName = value.conditionsList?[currentIndex].conditionCode?? ''; + value + .selectedCondition = + int.parse(value + .conditionsList?[ + currentIndex] + .conditionName ?? + "-1"); + }); + }, + child: Row( + children: [ + Container( + padding: EdgeInsets.all(2.0), + margin: EdgeInsets.symmetric( + horizontal: 6), + width: 20, + height: 20, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: Border.all( + color: Colors.grey, width: 1), + ), + child: Container( + decoration: BoxDecoration( + color: value + .selectedCondition == + int.parse(value + .conditionsList?[ + currentIndex] + .conditionName ?? + "-1") + ? HexColor("#D02127") + : Colors.white, + shape: BoxShape.circle, + ), + ), + ), + AppText( + value + .conditionsList?[ + currentIndex] + .conditionCode ?? + '', + fontWeight: FontWeight.normal, + fontFamily: 'Poppins', + fontSize: + SizeConfig.textMultiplier! * + 1.6, + ), + ], + ), + )), + ), + // Row( + // children: [ + // if(examinations?[index] + // .conditionsList?.length == 1) + // Expanded( + // child: InkWell( + // onTap: () { + // setState(() { + // examinations?[index].selectedCondition = + // int.parse(examinations?[index] + // .conditionsList?[0] + // .conditionName ?? + // "-1"); + // }); + // }, + // child: Row( + // children: [ + // Container( + // padding: EdgeInsets.all(2.0), + // margin: + // EdgeInsets.symmetric(horizontal: 6), + // width: 20, + // height: 20, + // decoration: BoxDecoration( + // color: Colors.white, + // shape: BoxShape.circle, + // border: Border.all( + // color: Colors.grey, width: 1), + // ), + // child: Container( + // decoration: BoxDecoration( + // color: examinations?[index].selectedCondition == + // int.parse(examinations?[index] + // .conditionsList?[0] + // .conditionName ?? + // "-1") + // ? HexColor("#D02127") + // : Colors.white, + // shape: BoxShape.circle, + // ), + // ), + // ), + // AppText( + // examinations?[index] + // .conditionsList?[0] + // .conditionCode ?? + // TranslationBase.of(context).normal, + // fontWeight: FontWeight.normal, + // fontFamily: 'Poppins', + // fontSize: + // SizeConfig.textMultiplier! * 1.6, + // ), + // ], + // ), + // )), + // Expanded( + // child: InkWell( + // onTap: () { + // setState(() { + // setState(() { + // examinations?[index].selectedCondition = + // int.parse(examinations?[index] + // .conditionsList?[1] + // .conditionName ?? + // "-1"); + // }); + // }); + // }, + // child: Row( + // children: [ + // Container( + // padding: EdgeInsets.all(2.0), + // margin: + // EdgeInsets.symmetric(horizontal: 6), + // width: 20, + // height: 20, + // decoration: BoxDecoration( + // color: Colors.white, + // shape: BoxShape.circle, + // border: Border.all( + // color: Colors.grey, width: 1), + // ), + // child: Container( + // decoration: BoxDecoration( + // color: examinations?[index].selectedCondition == + // int.parse(examinations?[index] + // .conditionsList?[1] + // .conditionName ?? + // "-1") + // ? HexColor("#D02127") + // : Colors.white, + // shape: BoxShape.circle, + // ), + // ), + // ), + // AppText( + // examinations?[index] + // .conditionsList?[1] + // .conditionCode ?? + // TranslationBase.of(context).abnormal, + // fontWeight: FontWeight.normal, + // fontFamily: 'Poppins', + // fontSize: + // SizeConfig.textMultiplier! * 1.6, + // ), + // ], + // ), + // )), + // Expanded( + // child: InkWell( + // onTap: () { + // setState(() { + // setState(() { + // examinations?[index].selectedCondition = + // int.parse(examinations?[index] + // .conditionsList?[2] + // .conditionName ?? + // "-1"); + // }); + // }); + // + // }, + // child: Row( + // children: [ + // Container( + // padding: EdgeInsets.all(2.0), + // margin: + // EdgeInsets.symmetric(horizontal: 6), + // width: 20, + // height: 20, + // decoration: BoxDecoration( + // color: Colors.white, + // shape: BoxShape.circle, + // border: Border.all( + // color: Colors.grey, width: 1), + // ), + // child: Container( + // decoration: BoxDecoration( + // color: examinations?[index].selectedCondition == + // int.parse(examinations?[index] + // .conditionsList?[2] + // .conditionName ?? + // "-1") + // ? HexColor("#D02127") + // : Colors.white, + // shape: BoxShape.circle, + // ), + // ), + // ), + // Expanded( + // child: AppText( + // examinations?[index] + // .conditionsList?[2] + // .conditionCode ?? + // TranslationBase.of(context).notExamined, + // fontWeight: FontWeight.normal, + // fontFamily: 'Poppins', + // fontSize: + // SizeConfig.textMultiplier! * 1.6, + // ), + // ), + // ], + // ), + // )), + // ], + // ), + Container( + margin: EdgeInsets.only(top: 8), + child: AppTextFieldCustom( + hintText: TranslationBase.of(context).remarks, + controller: value.remarksController, + minLines: 2, + maxLines: 4, + inputType: TextInputType.multiline, + onChanged: (value) {}, + onClick: () {}, + onFieldSubmitted: () {}, + ), + ), + ], + ), + ) + : SizedBox.shrink(), + ], + ),)?.toList() ?? [] + // Expanded( + // child: ListView.builder( + // shrinkWrap: true, + // itemCount: examinations?.length ?? 0, + // itemBuilder: (context, index) => Column( + // children: [ + // ListTileTheme( + // horizontalTitleGap: 0, + // child: CheckboxListTile( + // activeColor: Color(0xFFD02127), + // checkColor: Colors.white, + // contentPadding: EdgeInsets.zero, + // side: MaterialStateBorderSide.resolveWith( + // (Set states) { + // if (states.contains(MaterialState.selected)) { + // return const BorderSide(color: Color(0xFFD02127)); + // } + // return const BorderSide(color: Color(0xFFE6E6E6)); + // }, + // ), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(16)), + // value: examinations?[index].isSelected, + // controlAffinity: ListTileControlAffinity.leading, + // onChanged: (bool? value) { + // setState(() { + // examinations?[index].isSelected = value ?? false; + // }); + // }, + // title: AppText( + // examinations![index].name!, + // color: Color(0XFF575757), + // fontSize: 14, + // fontWeight: FontWeight.w400, + // ), + // ), + // ), + // (examinations?[index].isSelected == true) + // ? Container( + // padding: EdgeInsets.symmetric(horizontal: 12), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Container( + // margin: EdgeInsets.only(bottom: 8), + // child: AppText( + // TranslationBase.of(context).condition, + // fontWeight: FontWeight.bold, + // fontFamily: 'Poppins', + // fontSize: SizeConfig.textMultiplier! * 1.6, + // ), + // ), + // SizedBox( + // width: MediaQuery.sizeOf(context).width, + // height: 24, + // child: ListView.builder( + // shrinkWrap: true, + // scrollDirection: Axis.horizontal, + // itemCount: examinations?[index] + // .conditionsList + // ?.length ?? + // 0, + // itemBuilder: (context, currentIndex) => InkWell( + // onTap: () { + // setState(() { + // examinations?[index] + // .selectedCondition = + // int.parse(examinations?[index] + // .conditionsList?[ + // currentIndex] + // .conditionName ?? + // "-1"); + // }); + // }, + // child: Row( + // children: [ + // Container( + // padding: EdgeInsets.all(2.0), + // margin: EdgeInsets.symmetric( + // horizontal: 6), + // width: 20, + // height: 20, + // decoration: BoxDecoration( + // color: Colors.white, + // shape: BoxShape.circle, + // border: Border.all( + // color: Colors.grey, width: 1), + // ), + // child: Container( + // decoration: BoxDecoration( + // color: examinations?[index] + // .selectedCondition == + // int.parse(examinations?[ + // index] + // .conditionsList?[ + // currentIndex] + // .conditionName ?? + // "-1") + // ? HexColor("#D02127") + // : Colors.white, + // shape: BoxShape.circle, + // ), + // ), + // ), + // AppText( + // examinations?[index] + // .conditionsList?[ + // currentIndex] + // .conditionCode ?? + // '', + // fontWeight: FontWeight.normal, + // fontFamily: 'Poppins', + // fontSize: + // SizeConfig.textMultiplier! * + // 1.6, + // ), + // ], + // ), + // )), + // ), + // // Row( + // // children: [ + // // if(examinations?[index] + // // .conditionsList?.length == 1) + // // Expanded( + // // child: InkWell( + // // onTap: () { + // // setState(() { + // // examinations?[index].selectedCondition = + // // int.parse(examinations?[index] + // // .conditionsList?[0] + // // .conditionName ?? + // // "-1"); + // // }); + // // }, + // // child: Row( + // // children: [ + // // Container( + // // padding: EdgeInsets.all(2.0), + // // margin: + // // EdgeInsets.symmetric(horizontal: 6), + // // width: 20, + // // height: 20, + // // decoration: BoxDecoration( + // // color: Colors.white, + // // shape: BoxShape.circle, + // // border: Border.all( + // // color: Colors.grey, width: 1), + // // ), + // // child: Container( + // // decoration: BoxDecoration( + // // color: examinations?[index].selectedCondition == + // // int.parse(examinations?[index] + // // .conditionsList?[0] + // // .conditionName ?? + // // "-1") + // // ? HexColor("#D02127") + // // : Colors.white, + // // shape: BoxShape.circle, + // // ), + // // ), + // // ), + // // AppText( + // // examinations?[index] + // // .conditionsList?[0] + // // .conditionCode ?? + // // TranslationBase.of(context).normal, + // // fontWeight: FontWeight.normal, + // // fontFamily: 'Poppins', + // // fontSize: + // // SizeConfig.textMultiplier! * 1.6, + // // ), + // // ], + // // ), + // // )), + // // Expanded( + // // child: InkWell( + // // onTap: () { + // // setState(() { + // // setState(() { + // // examinations?[index].selectedCondition = + // // int.parse(examinations?[index] + // // .conditionsList?[1] + // // .conditionName ?? + // // "-1"); + // // }); + // // }); + // // }, + // // child: Row( + // // children: [ + // // Container( + // // padding: EdgeInsets.all(2.0), + // // margin: + // // EdgeInsets.symmetric(horizontal: 6), + // // width: 20, + // // height: 20, + // // decoration: BoxDecoration( + // // color: Colors.white, + // // shape: BoxShape.circle, + // // border: Border.all( + // // color: Colors.grey, width: 1), + // // ), + // // child: Container( + // // decoration: BoxDecoration( + // // color: examinations?[index].selectedCondition == + // // int.parse(examinations?[index] + // // .conditionsList?[1] + // // .conditionName ?? + // // "-1") + // // ? HexColor("#D02127") + // // : Colors.white, + // // shape: BoxShape.circle, + // // ), + // // ), + // // ), + // // AppText( + // // examinations?[index] + // // .conditionsList?[1] + // // .conditionCode ?? + // // TranslationBase.of(context).abnormal, + // // fontWeight: FontWeight.normal, + // // fontFamily: 'Poppins', + // // fontSize: + // // SizeConfig.textMultiplier! * 1.6, + // // ), + // // ], + // // ), + // // )), + // // Expanded( + // // child: InkWell( + // // onTap: () { + // // setState(() { + // // setState(() { + // // examinations?[index].selectedCondition = + // // int.parse(examinations?[index] + // // .conditionsList?[2] + // // .conditionName ?? + // // "-1"); + // // }); + // // }); + // // + // // }, + // // child: Row( + // // children: [ + // // Container( + // // padding: EdgeInsets.all(2.0), + // // margin: + // // EdgeInsets.symmetric(horizontal: 6), + // // width: 20, + // // height: 20, + // // decoration: BoxDecoration( + // // color: Colors.white, + // // shape: BoxShape.circle, + // // border: Border.all( + // // color: Colors.grey, width: 1), + // // ), + // // child: Container( + // // decoration: BoxDecoration( + // // color: examinations?[index].selectedCondition == + // // int.parse(examinations?[index] + // // .conditionsList?[2] + // // .conditionName ?? + // // "-1") + // // ? HexColor("#D02127") + // // : Colors.white, + // // shape: BoxShape.circle, + // // ), + // // ), + // // ), + // // Expanded( + // // child: AppText( + // // examinations?[index] + // // .conditionsList?[2] + // // .conditionCode ?? + // // TranslationBase.of(context).notExamined, + // // fontWeight: FontWeight.normal, + // // fontFamily: 'Poppins', + // // fontSize: + // // SizeConfig.textMultiplier! * 1.6, + // // ), + // // ), + // // ], + // // ), + // // )), + // // ], + // // ), + // Container( + // margin: EdgeInsets.only(top: 8), + // child: AppTextFieldCustom( + // hintText: TranslationBase.of(context).remarks, + // controller: examinations?[index].remarksController, + // minLines: 2, + // maxLines: 4, + // inputType: TextInputType.multiline, + // onChanged: (value) {}, + // onClick: () {}, + // onFieldSubmitted: () {}, + // ), + // ), + // ], + // ), + // ) + // : SizedBox.shrink(), + // ], + // ), + // ), + // ), + // ], + ), + ); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/plan/update_plan_page_vida_plus.dart b/lib/screens/patients/profile/soap_update_vida_plus/plan/update_plan_page_vida_plus.dart new file mode 100644 index 00000000..db343091 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/plan/update_plan_page_vida_plus.dart @@ -0,0 +1,399 @@ +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/progress_note.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/plan/plan_call_back.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/SOAP_step_header.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/expandable_SOAP_widget.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/plan/widget/add_progress_note.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/plan/widget/empty_progress_note.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/plan/widget/list_of_notes.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/add_soap_item.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/transitions/fade_page.dart'; +import 'package:flutter/material.dart'; + +class UpdatePlanPageVidaPlus extends StatefulWidget { + final Function changePageViewIndex; + final PatiantInformtion patientInfo; + final Function changeLoadingState; + final Function changeStateFun; + final SOAPViewModel sOAPViewModel; + + final int currentIndex; + + UpdatePlanPageVidaPlus( + {Key? key, + required this.changePageViewIndex, + required this.patientInfo, + required this.changeLoadingState, + required this.currentIndex, + required this.sOAPViewModel, + required this.changeStateFun}); + + @override + _UpdatePlanPageVidaPlusState createState() => _UpdatePlanPageVidaPlusState(); +} + +class _UpdatePlanPageVidaPlusState extends State + implements PlanCallBack { + bool isProgressExpanded = true; + + BoxDecoration containerBorderDecoration( + Color containerColor, Color borderColor) { + return BoxDecoration( + color: containerColor, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.all(Radius.circular(6)), + border: Border.fromBorderSide(BorderSide( + color: borderColor, + width: 0.5, + )), + ); + } + + @override + void initState() { + super.initState(); + } + + // getPatientProgressNote(SOAPViewModel model, + // {bool isAddProgress = false}) async { + // GetProgressNoteReqModel getGetProgressNoteReqModel = + // GetProgressNoteReqModel( + // appointmentNo: + // int.parse(widget.patientInfo.appointmentNo.toString()), + // patientMRN: widget.patientInfo.patientMRN, + // episodeID: widget.patientInfo.episodeNo.toString(), + // editedBy: '', + // doctorID: ''); + // await widget.sOAPViewModel + // .getPatientProgressNote(getGetProgressNoteReqModel); + // + // ///TODO set progressNote in model; + // if (widget.sOAPViewModel.patientProgressNoteList.isNotEmpty) { + // progressNoteController.text = Utils.parseHtmlString( + // widget.sOAPViewModel.patientProgressNoteList[0].planNote!); + // patientProgressNote.planNote = progressNoteController.text; + // + // patientProgressNote.createdByName = + // widget.sOAPViewModel.patientProgressNoteList[0].createdByName; + // patientProgressNote.createdOn = + // widget.sOAPViewModel.patientProgressNoteList[0].createdOn; + // patientProgressNote.editedOn = + // widget.sOAPViewModel.patientProgressNoteList[0].editedOn; + // patientProgressNote.editedByName = + // widget.sOAPViewModel.patientProgressNoteList[0].editedByName; + // patientProgressNote.appointmentNo = + // widget.sOAPViewModel.patientProgressNoteList[0].appointmentNo; + // setState(() { + // isAddProgress = isAddProgress; + // widget.sOAPViewModel.isAddProgress = isAddProgress; + // widget.sOAPViewModel.progressNoteText = progressNoteController.text; + // }); + // } + // } + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) async { + widget.sOAPViewModel.setPlanCallBack(this); + WidgetsBinding.instance.addPostFrameCallback((_) async { + widget.changeLoadingState(true); + model.getProgressNoteAndCondition(widget.patientInfo); + widget.changeLoadingState(false); + }); + }, + builder: (_, model, w) => AppScaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + isShowAppBar: false, + isLoading: model.state == ViewState.BusyLocal, + body: SingleChildScrollView( + physics: ScrollPhysics(), + child: Center( + child: FractionallySizedBox( + widthFactor: 0.90, + child: Column( + children: [ + SOAPStepHeader( + currentIndex: widget.currentIndex, + changePageViewIndex: widget.changePageViewIndex, + patientInfo: widget.patientInfo, + ), + SizedBox( + height: 10, + ), + ExpandableSOAPWidget( + headerTitle: TranslationBase.of(context).progressNote, + onTap: () { + setState(() { + isProgressExpanded = !isProgressExpanded; + }); + }, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + height: 10, + ), + AddSoapItem( + title: TranslationBase.of(context) + .addProgressNote, + onAddSoapItemClicked: () { + navigateToAddPlan(model); + }), + SizedBox( + height: 16, + ), + + if (model.progressNote.isEmpty) ...{ + Center( + child: Padding( + padding: const EdgeInsets.all(65), + child: EmptyProgressNote(), + ), + ), + } else ...{ + Divider(), + ListOfNotes(notes: model.progressNote, model: model,) + } + + // if (mySelectedExamination.isEmpty) ...{ + // + // Center( + // child: Padding( + // padding: const EdgeInsets.all(65), + // child: EmptyExamination(), + // ), + // ), + // + // } else ...{ + // Divider(), + // ListOfExamination( + // listOfSelection: mySelectedExamination + // ) + // } + // Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // if (isAddProgress) + // Container( + // margin: EdgeInsets.only(left: 10, right: 10, top: 15), + // child: AppTextFieldCustom( + // hintText: TranslationBase.of(context).progressNote, + // controller: progressNoteController, + // minLines: 2, + // maxLines: 4, + // inputType: TextInputType.multiline, + // onChanged: (value) { + // setState(() { + // patientProgressNote.planNote = value; + // model.progressNoteText = value!; + // widget.changeStateFun(); + // }); + // }, + // onFieldSubmitted: () {}, + // ), + // ), + // SizedBox( + // height: 9, + // ), + // if (patientProgressNote.planNote != null && !isAddProgress) + // Container( + // margin: EdgeInsets.only( + // left: 5, + // right: 5, + // ), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Row( + // children: [ + // AppText( + // 'Appointment No: ', + // fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 3, + // letterSpacing: -0.4, + // color: Color(0xFF575757), + // ), + // AppText( + // patientProgressNote.appointmentNo != null ? patientProgressNote.appointmentNo.toString() : '', + // fontWeight: FontWeight.w600, + // letterSpacing: -0.48, + // color: Color(0xFF2B353E), + // fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 3.6, + // ), + // ], + // ), + // AppText( + // patientProgressNote.createdOn != null + // ? AppDateUtils.getDayMonthYearDateFormatted(DateTime.parse(patientProgressNote.createdOn!)) + // : AppDateUtils.getDayMonthYearDateFormatted(DateTime.now()), + // fontWeight: FontWeight.w600, + // fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 3.6, + // ) + // ], + // ), + // Row( + // mainAxisAlignment: MainAxisAlignment.end, + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // // Row( + // // children: [ + // // AppText( + // // 'Condition: ', + // // fontSize: 12, + // // ), + // // AppText( + // // patientProgressNote.mName ?? + // // '', + // // fontWeight: FontWeight.w600), + // // ], + // // ), + // AppText( + // patientProgressNote.createdOn != null ? AppDateUtils.getHour(DateTime.parse(patientProgressNote.createdOn!)) : AppDateUtils.getHour(DateTime.now()), + // fontWeight: FontWeight.w600, + // color: Color(0xFF575757), + // fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 3.6, + // ) + // ], + // ), + // SizedBox( + // height: 8, + // ), + // Row( + // mainAxisAlignment: MainAxisAlignment.start, + // children: [ + // Expanded( + // child: AppText( + // progressNoteController.text, + // fontSize: 10, + // ), + // ), + // InkWell( + // onTap: () { + // setState(() { + // isAddProgress = true; + // widget.sOAPViewModel.isAddProgress = true; + // }); + // }, + // child: Icon( + // DoctorApp.edit, + // size: 18, + // )) + // ], + // ), + // ], + // ), + // ) + // ], + // ), + ], + ), + isExpanded: isProgressExpanded, + ), + SizedBox( + height: SizeConfig.heightMultiplier! * + (SizeConfig.isHeightVeryShort ? 20 : 10), + ), + ], + ), + ), + ), + ), + )); + } + + // submitPlan(SOAPViewModel model) async { + // if (progressNoteController.text.isNotEmpty) { + // widget.changeLoadingState(true); + // PostProgressNoteRequestModel postProgressNoteRequestModel = + // new PostProgressNoteRequestModel( + // patientMRN: widget.patientInfo.patientMRN, + // episodeId: widget.patientInfo.episodeNo, + // appointmentNo: widget.patientInfo.appointmentNo, + // planNote: patientProgressNote.planNote, + // doctorID: widget.patientInfo.doctorId, + // createdBy: widget.patientInfo.doctorId, + // createdByName: widget.patientInfo.doctorName, + // editedBy: ''); + // + // if (widget.sOAPViewModel.patientProgressNoteList.isEmpty) { + // await widget.sOAPViewModel + // .postProgressNote(postProgressNoteRequestModel); + // } else { + // Map profile = await sharedPref.getObj(DOCTOR_PROFILE); + // DoctorProfileModel doctorProfile = DoctorProfileModel.fromJson(profile); + // postProgressNoteRequestModel.editedBy = doctorProfile.doctorID; + // await widget.sOAPViewModel + // .patchProgressNote(postProgressNoteRequestModel); + // } + // + // if (widget.sOAPViewModel.state == ViewState.ErrorLocal) { + // Utils.showErrorToast(widget.sOAPViewModel.error); + // } else { + // GetProgressNoteReqModel getGetProgressNoteReqModel = + // GetProgressNoteReqModel( + // appointmentNo: + // int.parse(widget.patientInfo.appointmentNo.toString()), + // patientMRN: widget.patientInfo.patientMRN, + // episodeID: widget.patientInfo.episodeNo.toString(), + // editedBy: '', + // doctorID: ''); + // await widget.sOAPViewModel + // .getPatientProgressNote(getGetProgressNoteReqModel); + // if (widget.sOAPViewModel.patientProgressNoteList.isNotEmpty) { + // progressNoteController.text = Utils.parseHtmlString( + // widget.sOAPViewModel.patientProgressNoteList[0].planNote!); + // patientProgressNote.planNote = progressNoteController.text; + // patientProgressNote.createdByName = + // widget.sOAPViewModel.patientProgressNoteList[0].createdByName; + // patientProgressNote.createdOn = + // widget.sOAPViewModel.patientProgressNoteList[0].createdOn; + // patientProgressNote.editedOn = + // widget.sOAPViewModel.patientProgressNoteList[0].editedOn; + // patientProgressNote.editedByName = + // widget.sOAPViewModel.patientProgressNoteList[0].editedByName; + // patientProgressNote.appointmentNo = + // widget.sOAPViewModel.patientProgressNoteList[0].appointmentNo; + // + // setState(() { + // isAddProgress = false; + // widget.sOAPViewModel.isAddProgress = false; + // }); + // } + // + // Navigator.of(context).pop(); + // Utils.showErrorToast("Episode Created Successfully"); + // } + // widget.changeLoadingState(false); + // } else { + // Utils.showErrorToast(TranslationBase.of(context).progressNoteErrorMsg); + // } + // } + + @override + nextFunction(model) { + //todo handle the next event here + } + + void navigateToAddPlan(SOAPViewModel model) async{ + bool result = await Navigator.push( + context, + FadePage( + page: AddProgressNote(information: widget.patientInfo,), + )); + + if(result){ + model.getProgressNote(widget.patientInfo); + } + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/ProgressNoteItem.dart b/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/ProgressNoteItem.dart new file mode 100644 index 00000000..cadf51a3 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/ProgressNoteItem.dart @@ -0,0 +1,146 @@ +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/widgets/SoapDetailItem.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + + +class ProgressNoteItem extends StatelessWidget { + final String type; + final String speciality; + final String Notes; + final String patientCondition; + final String doctorName; + final String modifiedOn; + + const ProgressNoteItem( + {super.key, + required this.type, + required this.speciality, + required this.Notes, + required this.patientCondition, + required this.doctorName, + required this.modifiedOn, + }); + + @override + Widget build(BuildContext context) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + AppText( + "${TranslationBase.of(context).type}:", + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + SizedBox( + width: 4, + ), + AppText( + type, + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ], + ), + SizedBox( + height: 4, + ), + Row( + children: [ + AppText( + "${TranslationBase.of(context).speciality}:", + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + SizedBox( + width: 4, + ), + AppText( + speciality, + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ], + ), + SizedBox( + height: 4, + ), + Row( + children: [ + AppText( + "${TranslationBase.of(context).doctorName}:", + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + SizedBox( + width: 4, + ), + AppText( + doctorName, + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ], + ), + SizedBox( + height: 4, + ), + Row( + children: [ + AppText( + "${TranslationBase.of(context).dateTime}", + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + SizedBox( + width: 4, + ), + AppText( + getDateAndTime(modifiedOn), + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ], + ), + ], + ), + ), + Visibility( + visible: patientCondition.isNotEmpty, + child: Status(status: patientCondition)) + ], + ), + SizedBox( + height: 8, + ), + AppText( + Notes, + color: Color(0XFF2B353E), + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ], + ); + + String getDateAndTime(String dateTime) { + if (dateTime.isEmpty) return ''; + DateTime now = DateTime.now(); + return DateFormat('dd/MM/yyyy hh:mm a').format(now); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/add_progress_note.dart b/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/add_progress_note.dart new file mode 100644 index 00000000..ab92d4d8 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/add_progress_note.dart @@ -0,0 +1,351 @@ + +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/Clinic.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/PatientCondition.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/patient_search/patient_search_header.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_dropdown.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:provider/provider.dart'; + +class AddProgressNote extends StatefulWidget{ + final PatiantInformtion information; + + const AddProgressNote({super.key, required this.information}); + @override + State createState() => _AddProgressNoteState(); +} + +class _AddProgressNoteState extends State { + SOAPClinic? selectedClinicItem; + + PatientCondition? selectedPatientConditionItem; + + int status = 1; + final TextEditingController noteController = TextEditingController(); + + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + + return BaseView( + onModelReady: (model){ + WidgetsBinding.instance.addPostFrameCallback((_) async { + model.getClinics(); + model.getPatientConditionList(); + }); + }, + builder: (_, model, w) => AppScaffold( + isLoading: model.state == ViewState.BusyLocal, + isShowAppBar: true, + appBar: PatientSearchHeader( + title: TranslationBase.of(context).progressNote + ), + body: Padding( + padding: const EdgeInsets.all(20.0), + child: SingleChildScrollView( + child: Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).addProgressNote, + fontSize: 16, + fontWeight: FontWeight.w600, + textAlign: TextAlign.start, + color: Colors.black, + ), + SizedBox( + height: 16, + ), + Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, vertical: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).patientCondition, + textAlign: TextAlign.start, + fontWeight: FontWeight.w600, + fontSize: 11, + color: Color(0xFF2E303A), + ), + SizedBox( + height: 4, + ), + model.patientConditionList.isEmpty + ? EmptyDropDown() + : DropdownButtonHideUnderline( + child: DropdownButton( + dropdownColor: Colors.white, + iconEnabledColor: Colors.black, + icon: Icon(Icons.keyboard_arrow_down), + isExpanded: true, + value: + selectedPatientConditionItem == null + ? model.patientConditionList.first + : selectedPatientConditionItem, + iconSize: 25, + elevation: 16, + onChanged: (newValue) async { + setState(() { + selectedPatientConditionItem = + newValue; + }); + }, + items: model.patientConditionList + .map((item) { + return DropdownMenuItem( + child: AppText( + item.name ?? '', + fontSize: 14, + letterSpacing: -0.96, + color: AppGlobal.appTextColor, + fontWeight: FontWeight.normal, + textAlign: TextAlign.left, + ), + value: item, + ); + }).toList(), + ), + ), + ], + ), + ), + ), + SizedBox( + height: 16, + ), + AppText( + TranslationBase.of(context).progressNoteType, + fontWeight: FontWeight.bold, + fontFamily: 'Poppins', + fontSize: 11, + ), + SizedBox( + height: 8, + ), + Row( + children: [ + Flexible( + child: InkWell( + onTap: () { + setState(() { + status = 1; + }); + }, + child: Row( + children: [ + Container( + padding: EdgeInsets.all(2.0), + margin: EdgeInsets.symmetric(horizontal: 6), + width: 20, + height: 20, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: + Border.all(color: Colors.grey, width: 1), + ), + child: Container( + decoration: BoxDecoration( + color: status == 1 + ? HexColor("#D02127") + : Colors.white, + shape: BoxShape.circle, + ), + ), + ), + AppText( + TranslationBase.of(context).doctorProgressNote, + fontWeight: FontWeight.w600, + fontFamily: 'Poppins', + fontSize: 12, + ), + ], + ), + )), + ], + ), + SizedBox( + height: 24, + ), + Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, vertical: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).speciality, + textAlign: TextAlign.start, + fontWeight: FontWeight.w600, + fontSize: 11, + color: Color(0xFF2E303A), + ), + SizedBox( + height: 4, + ), + model.clinics.isEmpty + ? EmptyDropDown() + : DropdownButtonHideUnderline( + child: DropdownButton( + dropdownColor: Colors.white, + iconEnabledColor: Colors.black, + icon: Icon(Icons.keyboard_arrow_down), + isExpanded: true, + value: selectedClinicItem == null + ? model.clinics.first + : selectedClinicItem, + iconSize: 25, + elevation: 16, + onChanged: (newValue) async { + setState(() { + selectedClinicItem = newValue; + }); + }, + items: model.clinics.map((item) { + return DropdownMenuItem( + child: AppText( + projectViewModel.isArabic + ? item.clinicNameArabic ?? '' + : item.clinicNameEnglish ?? '', + fontSize: 14, + letterSpacing: -0.96, + color: AppGlobal.appTextColor, + fontWeight: FontWeight.normal, + textAlign: TextAlign.left, + ), + value: item, + ); + }).toList(), + ), + ), + ], + ), + ), + ), + SizedBox( + height: 16, + ), + AppTextFieldCustom( + hintText: TranslationBase.of(context).addYourNote, + controller: noteController, + inputType: TextInputType.multiline, + maxLines: 25, + minLines: 4, + hasBorder: true, + onClick: () {}, + onChanged: (value) {}, + onFieldSubmitted: () {}, + ), + SizedBox( + height: 16, + ), + // Row( + // children: [ + // SvgPicture.asset( + // 'assets/images/svgs/save_as_draft.svg'), + // SizedBox( + // width: 4, + // ), + // AppText( + // TranslationBase.of(context).saveAsDraft, + // textAlign: TextAlign.start, + // fontWeight: FontWeight.w600, + // fontSize: 10, + // color: Color(0xFF449BF1), + // ), + // ], + // ) + ], + ), + ), + ), + ), + ), + bottomNavigationBar: Material( + color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + Expanded( + child: AppButton( + title: TranslationBase.of(context).cancelSmall, + color: Color(0xffEAEAEA), + fontColor: Colors.black, + fontWeight: FontWeight.w600, + onPressed: () async { + Navigator.pop(context); + }, + ), + ), + SizedBox( + width: 10, + ), + Expanded( + child: AppButton( + title: TranslationBase.of(context).save, + color: Color(0xff359846), + fontColor: Colors.white, + fontWeight: FontWeight.w600, + onPressed: () async { + selectedPatientConditionItem ??= model.patientConditionList.first; + selectedClinicItem ??= model.clinics.first; + + if(noteController.text.isEmpty){ + DrAppToastMsg.showErrorToast(TranslationBase.of(context).progressNoteCanNotBeEmpty); + return; + } + + bool result = await model.createProgressNote(widget.information, selectedClinicItem?.clinicID?.toString(), selectedPatientConditionItem?.code ?? '',noteController.text ); + Navigator.pop(context, result); + + }, + ), + ), + ], + ))), + ), + ); + } +} \ No newline at end of file diff --git a/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/add_progress_note_details.dart b/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/add_progress_note_details.dart new file mode 100644 index 00000000..24af94c9 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/add_progress_note_details.dart @@ -0,0 +1,282 @@ +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/PatientCondition.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/assessment/widget/empty_dropdown.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/utils/utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:hexcolor/hexcolor.dart'; +import 'package:provider/provider.dart'; + +import '../../../../../../core/model/SOAP/progress_note/Clinic.dart'; +import '../../../../../base/base_view.dart'; + +class AddProgressNoteDetails extends StatefulWidget { + @override + State createState() => _AddProgressNoteDetailsState(); +} + +class _AddProgressNoteDetailsState extends State { + SOAPClinic? selectedClinicItem; + + PatientCondition? selectedPatientConditionItem; + + int status = 1; + final TextEditingController noteController = TextEditingController(); + + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + return BaseView( + builder: (_, model, w) => Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).addProgressNote, + fontSize: 16, + fontWeight: FontWeight.w600, + textAlign: TextAlign.start, + color: Colors.black, + ), + SizedBox( + height: 16, + ), + Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, vertical: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).patientCondition, + textAlign: TextAlign.start, + fontWeight: FontWeight.w600, + fontSize: 11, + color: Color(0xFF2E303A), + ), + SizedBox( + height: 4, + ), + model.patientConditionList.isEmpty + ? EmptyDropDown() + : DropdownButtonHideUnderline( + child: DropdownButton( + dropdownColor: Colors.white, + iconEnabledColor: Colors.black, + icon: Icon(Icons.keyboard_arrow_down), + isExpanded: true, + value: + selectedPatientConditionItem == null + ? model.patientConditionList.first + : selectedPatientConditionItem, + iconSize: 25, + elevation: 16, + onChanged: (newValue) async { + setState(() { + selectedPatientConditionItem = + newValue; + }); + }, + items: model.patientConditionList + .map((item) { + return DropdownMenuItem( + child: AppText( + item.name ?? '', + fontSize: 14, + letterSpacing: -0.96, + color: AppGlobal.appTextColor, + fontWeight: FontWeight.normal, + textAlign: TextAlign.left, + ), + value: item, + ); + }).toList(), + ), + ), + ], + ), + ), + ), + SizedBox( + height: 16, + ), + AppText( + TranslationBase.of(context).progressNoteType, + fontWeight: FontWeight.bold, + fontFamily: 'Poppins', + fontSize: 11, + ), + SizedBox( + height: 8, + ), + Row( + children: [ + Flexible( + child: InkWell( + onTap: () { + setState(() { + status = 1; + }); + }, + child: Row( + children: [ + Container( + padding: EdgeInsets.all(2.0), + margin: EdgeInsets.symmetric(horizontal: 6), + width: 20, + height: 20, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: + Border.all(color: Colors.grey, width: 1), + ), + child: Container( + decoration: BoxDecoration( + color: status == 1 + ? HexColor("#D02127") + : Colors.white, + shape: BoxShape.circle, + ), + ), + ), + AppText( + TranslationBase.of(context).doctorProgressNote, + fontWeight: FontWeight.w600, + fontFamily: 'Poppins', + fontSize: 12, + ), + ], + ), + )), + ], + ), + SizedBox( + height: 24, + ), + Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, vertical: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase.of(context).speciality, + textAlign: TextAlign.start, + fontWeight: FontWeight.w600, + fontSize: 11, + color: Color(0xFF2E303A), + ), + SizedBox( + height: 4, + ), + model.clinics.isEmpty + ? EmptyDropDown() + : DropdownButtonHideUnderline( + child: DropdownButton( + dropdownColor: Colors.white, + iconEnabledColor: Colors.black, + icon: Icon(Icons.keyboard_arrow_down), + isExpanded: true, + value: selectedClinicItem == null + ? model.clinics.first + : selectedClinicItem, + iconSize: 25, + elevation: 16, + onChanged: (newValue) async { + setState(() { + selectedClinicItem = newValue; + }); + }, + items: model.clinics.map((item) { + return DropdownMenuItem( + child: AppText( + projectViewModel.isArabic + ? item.clinicNameArabic ?? '' + : item.clinicNameEnglish ?? '', + fontSize: 14, + letterSpacing: -0.96, + color: AppGlobal.appTextColor, + fontWeight: FontWeight.normal, + textAlign: TextAlign.left, + ), + value: item, + ); + }).toList(), + ), + ), + ], + ), + ), + ), + SizedBox( + height: 16, + ), + AppTextFieldCustom( + hintText: TranslationBase.of(context).addYourNote, + controller: noteController, + inputType: TextInputType.multiline, + maxLines: 25, + minLines: 4, + hasBorder: true, + onClick: () {}, + onChanged: (value) {}, + onFieldSubmitted: () {}, + ), + SizedBox( + height: 16, + ), + // Row( + // children: [ + // SvgPicture.asset( + // 'assets/images/svgs/save_as_draft.svg'), + // SizedBox( + // width: 4, + // ), + // AppText( + // TranslationBase.of(context).saveAsDraft, + // textAlign: TextAlign.start, + // fontWeight: FontWeight.w600, + // fontSize: 10, + // color: Color(0xFF449BF1), + // ), + // ], + // ) + ], + ), + ), + )); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/empty_progress_note.dart b/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/empty_progress_note.dart new file mode 100644 index 00000000..590fe54c --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/empty_progress_note.dart @@ -0,0 +1,26 @@ +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import '../../../../../../../utils/translations_delegate_base_utils.dart'; + +class EmptyProgressNote extends StatelessWidget{ + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment : MainAxisAlignment.center, + children: [ + SvgPicture.asset('assets/images/svgs/unavailable.svg'), + SizedBox(height: 10,), + AppText( + TranslationBase.of(context).noProgressNote, + fontSize: 12, + fontWeight: FontWeight.w400, + textAlign: TextAlign.center, + color: Color(0xFFADADAD), + ) + ], + ); + } + +} \ No newline at end of file diff --git a/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/list_of_notes.dart b/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/list_of_notes.dart new file mode 100644 index 00000000..03700f6f --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/plan/widget/list_of_notes.dart @@ -0,0 +1,31 @@ +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/GetGetProgressNoteResModel.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/progress_note/progress_note.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/plan/widget/ProgressNoteItem.dart'; +import 'package:flutter/material.dart'; + +class ListOfNotes extends StatelessWidget { + final List notes; + final SOAPViewModel model; + + const ListOfNotes({super.key, required this.notes, required this.model}); + + @override + Widget build(BuildContext context) => Flexible( + child: ListView.separated( + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemBuilder: (_, index) => ProgressNoteItem( + type: notes[index].progressNotesTypesName ?? '', + speciality: notes[index].specialityName ?? '', + Notes: notes[index].progressNote ?? '', + patientCondition: model.getPatientConditionValue( + notes[index].patientCondition ?? '') ?? + '', + doctorName: notes[index].userFullName ?? '', + modifiedOn: notes[index].modifiedOn ?? '', + ), + separatorBuilder: (_, __) => Divider(), + itemCount: notes.length), + ); +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/add_allergies.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/add_allergies.dart new file mode 100644 index 00000000..7fd7bde3 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/add_allergies.dart @@ -0,0 +1,68 @@ +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/bottom_sheet/custom_bottom_sheet_container.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:flutter/material.dart'; + +import '../../../../../../core/model/SOAP/allergy/get_patient_allergies_list_vida_plus.dart'; +import '../../../../../../core/model/patient/patiant_info_model.dart'; +import '../../../../patient_search/patient_search_header.dart'; +import 'master_key_checkbox_search_allergies_widget.dart'; + +class AddAllergies extends StatefulWidget { + final PatientAllergiesVidaPlus? myAllergiesList; + final PatiantInformtion patientInfo; + const AddAllergies({Key? key, this.myAllergiesList, required this.patientInfo}) + : super(key: key); + + @override + _AddAllergiesState createState() => _AddAllergiesState(); +} + +class _AddAllergiesState extends State { + // List allergiesList = []; + // List allergySeverityList = []; + // + // myAllergiesListLocal = []; + + @override + initState() { + super.initState(); + // myAllergiesListLocal = [...?widget.myAllergiesList]; + } + + // GlobalKey key = new GlobalKey>(); + bool isFormSubmitted = false; + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model){ + WidgetsBinding.instance.addPostFrameCallback((_) { + model.clearAllergy(); + }); + }, + builder: (_, model, w) => AppScaffold( + isShowAppBar: true, + isLoading: model.state == ViewState.BusyLocal, + appBar: PatientSearchHeader( + title: TranslationBase.of(context).addAllergies), + body: MasterKeyCheckboxSearchAllergiesWidget( + model: model, + myAllergiesList: widget.myAllergiesList, + patientInfo: widget.patientInfo + ), + bottomSheet: CustomBottomSheetContainer( + widthFactor: .9, + buttonColor: Color(0xffEAEAEA), + fontColor: Colors.black, + label: TranslationBase.of(context).cancel, + onTap: () { + Navigator.of(context).pop(); + }, + )), + ); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/allergies_item.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/allergies_item.dart new file mode 100644 index 00000000..66c488ac --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/allergies_item.dart @@ -0,0 +1,180 @@ +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_allergy.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/utils/utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/dialogs/master_key_dailog.dart'; +import 'package:doctor_app_flutter/widgets/shared/expandable-widget-header-body.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:eva_icons_flutter/eva_icons_flutter.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../../../soap_update/soap_utils.dart'; + + +class AddAllergiesItem extends StatefulWidget { + final SOAPViewModel? model; + final Function(MasterKeyModel)? removeAllergy; + final Function(MySelectedAllergy mySelectedAllergy)? addAllergy; + final bool Function(MasterKeyModel)? isServiceSelected; + final MySelectedAllergy Function(MasterKeyModel)? getServiceSelectedAllergy; + final MasterKeyModel? item; + + const AddAllergiesItem({Key? key, this.model, this.removeAllergy, this.addAllergy, this.isServiceSelected, this.getServiceSelectedAllergy, this.item}) : super(key: key); + + @override + _AddAllergiesItemState createState() => _AddAllergiesItemState(); +} + +class _AddAllergiesItemState extends State { + MasterKeyModel _selectedAllergySeverity = MasterKeyModel(); + bool isSubmitted = false; + + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + + bool isSelected = widget.isServiceSelected!(widget.item!); + MySelectedAllergy mySelectedAllergy = MySelectedAllergy(); + if (isSelected) { + mySelectedAllergy = widget.getServiceSelectedAllergy!(widget.item!); + } + TextEditingController remarkController = TextEditingController(text: isSelected ? mySelectedAllergy.remark : null); + TextEditingController severityController = TextEditingController( + text: isSelected + ? mySelectedAllergy.selectedAllergySeverity != null + ? projectViewModel.isArabic + ? mySelectedAllergy.selectedAllergySeverity!.nameAr + : mySelectedAllergy.selectedAllergySeverity!.nameEn + : null + : null); + return HeaderBodyExpandableNotifier( + headerWidget: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Checkbox( + value: widget.isServiceSelected!(widget.item!), + activeColor: Colors.red[800], + onChanged: (bool? newValue) { + onTapItem(); + }), + InkWell( + onTap: onTapItem, + child: Container( + child: AppText( + projectViewModel.isArabic + ? widget.item!.nameAr != "" + ? widget.item!.nameAr! + : widget.item!.nameEn! + : widget.item!.nameEn!, + color: Color(0xFF575757), + fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * (SizeConfig.isWidthLarge ? 3 : 3.8), + letterSpacing: -0.56, + ), + width: MediaQuery.of(context).size.width * 0.55, + ), + ), + ], + ), + InkWell( + onTap: () { + if (mySelectedAllergy != null) { + setState(() { + mySelectedAllergy.isExpanded = mySelectedAllergy.isExpanded == null ? false : true; + }); + } + }, + child: Icon( + (mySelectedAllergy != null ? mySelectedAllergy.isExpanded! : false) ? EvaIcons.arrowIosUpwardOutline : EvaIcons.arrowIosDownwardOutline, + color: Color(0xFF575757), + size: 20, + ), + ) + ], + ), + bodyWidget: Center( + child: FractionallySizedBox( + widthFactor: 0.9, + child: Center( + child: Column( + children: [ + AppTextFieldCustom( + onClick: widget.model!.allergySeverityList != null + ? () { + MasterKeyDailog dialog = MasterKeyDailog( + list: widget.model!.allergySeverityList, + selectedValue: mySelectedAllergy.selectedAllergySeverity!, + okText: TranslationBase.of(context).ok, + okFunction: (selectedValue) { + setState(() { + mySelectedAllergy.selectedAllergySeverity = selectedValue; + }); + }, + ); + showDialog( + barrierDismissible: false, + context: context, + builder: (BuildContext context) { + return dialog; + }, + ); + } + : () {}, + isTextFieldHasSuffix: true, + hintText: TranslationBase.of(context).selectSeverity + "*", + enabled: false, + maxLines: 1, + minLines: 1, + height: Utils.getTextFieldHeight(), + validationError: mySelectedAllergy != null && mySelectedAllergy.selectedAllergySeverity == null && mySelectedAllergy.hasValidationError! + ? TranslationBase.of(context).severityValidationError + : "", + controller: severityController, + onChanged: (value) {}, + onFieldSubmitted: () {}, + ), + SizedBox( + height: 10, + ), + AppTextFieldCustom( + hintText: TranslationBase.of(context).remarks, + controller: remarkController, + maxLines: 25, + minLines: 3, + hasBorder: true, + onChanged: (value) { + mySelectedAllergy.remark = value; + }, + inputType: TextInputType.multiline, + onClick: () {}, + onFieldSubmitted: () {}, + ), + SizedBox( + height: 10, + ), + ], + ), + ), + ), + ), + isExpand: mySelectedAllergy != null ? mySelectedAllergy.isExpanded! : false, + ); + } + + onTapItem() { + setState(() { + if (widget.isServiceSelected!(widget.item!)) { + widget.removeAllergy!(widget.item!); + } else { + MySelectedAllergy mySelectedAllergy = SoapUtils.generateMySelectedAllergy(allergy: widget.item, allergySeverity: _selectedAllergySeverity, remark: null, isChecked: true, isExpanded: true); + widget.addAllergy!(mySelectedAllergy); + } + }); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/master_key_checkbox_search_allergies_widget.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/master_key_checkbox_search_allergies_widget.dart new file mode 100644 index 00000000..a5d1c693 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/master_key_checkbox_search_allergies_widget.dart @@ -0,0 +1,166 @@ +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/allergy/get_allergies_list_vida_plus.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/allergies/reactions_selection.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/utils/utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/rounded_container_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import '../../../../../../core/model/SOAP/allergy/get_patient_allergies_list_vida_plus.dart'; +import '../../../../../../core/model/patient/patiant_info_model.dart'; +import '../../../../../../widgets/transitions/fade_page.dart'; +import '../../objective/widget/EmptyExamination.dart'; + +class MasterKeyCheckboxSearchAllergiesWidget extends StatefulWidget { + final SOAPViewModel model; + final String? buttonName; + final String? hintSearchText; + final PatientAllergiesVidaPlus? myAllergiesList; + final PatiantInformtion patientInfo; + + MasterKeyCheckboxSearchAllergiesWidget({ + Key? key, + required this.model, + this.myAllergiesList, + required this.patientInfo, + this.buttonName, + this.hintSearchText, + }) : super(key: key); + + @override + _MasterKeyCheckboxSearchAllergiesWidgetState createState() => + _MasterKeyCheckboxSearchAllergiesWidgetState(); +} + +class _MasterKeyCheckboxSearchAllergiesWidgetState + extends State { + // List items = []; + bool loading = false; + TextEditingController filteredSearchController = TextEditingController(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Expanded( + child: Container( + margin: EdgeInsets.all(20), + height: Utils.getTextFieldHeight(), + child: Center( + child: Container( + decoration: + BoxDecoration(borderRadius: BorderRadius.circular(12)), + child: Column( + children: [ + AppTextFieldCustom( + hintText: TranslationBase.of(context).selectAllergy, + isTextFieldHasSuffix: true, + hasBorder: true, + controller: filteredSearchController, + onChanged: (value) { + // filterSearchResults(value); + }, + onFieldSubmitted: () { + }, + onEditingComplete: (){ + loading = true; + if(filteredSearchController.text.isNotEmpty) { + widget.model + .searchAllergies(filteredSearchController.text); + } + }, + suffixIcon: IconButton( + icon: Icon( + Icons.search, + color: Color(0xff2B353E), + size: 30, + ), + onPressed: () { + loading = true; + widget.model + .searchAllergies(filteredSearchController.text); + }, + ), + ), + // DividerWithSpacesAround(), + SizedBox( + height: 10, + ), + Expanded( + child: RoundedContainer( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height * 0.60, + child: widget.model.searchAllergiesVidaPlus.isEmpty + ? Center( + child: EmptyWidget( + TranslationBase.of(context) + .noDataAvailable)) + : ListView.builder( + itemCount: widget + .model.searchAllergiesVidaPlus.length, + itemBuilder: (context, index) { + loading = false; + return ListTile( + title: AppText(widget + .model + .searchAllergiesVidaPlus[index] + .allergyName!), + trailing: TextButton.icon( + icon: SvgPicture.asset( + "assets/images/svgs/add-square.svg", + color: Color(0xffD02127), + ), + style: ButtonStyle( + + // iconColor: + // WidgetStateProperty.all< + // Color>()), + ), + onPressed: () { + openReaction( + widget.model, + widget.model + .searchAllergiesVidaPlus[ + index]); + }, + label: AppText( + TranslationBase.of(context).add, + fontSize: 12, + color: Color(0xffD02127), + ), + ), + ); + }, + ) + ), + ), + ], + ), + ), + ), + ), + ), + ], + ); + } + + openReaction(model, AllergiesListVidaPlus mySelectedAllergy) { + Navigator.of(context).pop(); + Navigator.push( + context, + FadePage( + page: ReactionsSelectionAllergiesWidget( + model: model, + mySelectedAllergy: mySelectedAllergy, + patientInfo: widget.patientInfo))); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/reactions_selection.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/reactions_selection.dart new file mode 100644 index 00000000..a3e3d43a --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/reactions_selection.dart @@ -0,0 +1,541 @@ +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/allergy/get_allergies_list_vida_plus.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/allergy/get_patient_allergies_list_vida_plus.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/patient_search/patient_search_header.dart'; +import 'package:doctor_app_flutter/utils/extenstions_utils.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/rounded_container_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; + + +class ReactionsSelectionAllergiesWidget extends StatefulWidget { + final SOAPViewModel? model; + final AllergiesListVidaPlus? mySelectedAllergy; + final bool isEdit; + final PatientAllergiesVidaPlus? editSelectedAllergy; + final PatiantInformtion patientInfo; + final String? buttonName; + + ReactionsSelectionAllergiesWidget({ + Key? key, + required this.model, + required this.patientInfo, + this.mySelectedAllergy, + this.editSelectedAllergy, + this.isEdit = false, + this.buttonName, + }) : super(key: key); + + @override + _ReactionsSelectionAllergiesWidgetState createState() => + _ReactionsSelectionAllergiesWidgetState(); +} + +class _ReactionsSelectionAllergiesWidgetState + extends State { + bool loading = false; + TextEditingController remark = TextEditingController(); + List? controllers =[]; + + @override + void initState() { + controllers = List.generate(widget.mySelectedAllergy! + .allergyReactionDTOs!.length, (index) => ExpansionTileController()); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BaseView( + builder: (_, model, w) => AppScaffold( + isLoading: loading, + appBar: PatientSearchHeader( + title: TranslationBase.of(context).selectReaction), + body: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + widget.mySelectedAllergy != null + ? Expanded( + child: RoundedContainer( + margin: EdgeInsets.only(top:6, left: 15, right: 15, bottom: 6), + child: ListView.builder( + itemCount: widget.mySelectedAllergy! + .allergyReactionDTOs!.length, + itemBuilder: (context, index) { + loading = false; + + return Column(children: [ + ExpansionTile( + + controller: controllers![index], + key: Key(index.toString()), + // dense: false, + // enableFeedback: false, + // showTrailingIcon: false, + initiallyExpanded: widget + .mySelectedAllergy! + .allergyReactionDTOs![index] + .isSelected!, + leading: Checkbox( + activeColor: Color(0xffD02127), + value: widget + .mySelectedAllergy! + .allergyReactionDTOs![index] + .isSelected!, + onChanged: (value) { + widget + .mySelectedAllergy! + .allergyReactionDTOs![index] + .isSelected = value; + + value ==true ? controllers![index].expand() : controllers![index].collapse() ; + setState(() { + + }); // setState(() {}); + }), + title: AppText(widget + .mySelectedAllergy! + .allergyReactionDTOs![index] + .allergyReactionName!), + children: [ + Row( + children: [ + Expanded( + + child: ListTile( + contentPadding: EdgeInsets.zero , + + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Radio( + activeColor: Color(0xffD02127), + materialTapTargetSize: + MaterialTapTargetSize + .shrinkWrap, + // Reduces padding around checkbox + visualDensity: + VisualDensity.compact, + value: 1, + groupValue: widget + .mySelectedAllergy! + .allergyReactionDTOs![index] + .severity ?? 1, + onChanged: (value) { + widget + .mySelectedAllergy! + .allergyReactionDTOs![ + index] + .severity = value; + setState(() {}); + }, + ), + AppText( + TranslationBase.of(context) + .mild, + fontSize: 10, + ), + ], + ))), + Expanded( + child: ListTile( + contentPadding: EdgeInsets.zero , + title: Row( + children: [ + Radio( + activeColor: Color(0xffD02127), + materialTapTargetSize: + MaterialTapTargetSize + .shrinkWrap, + // Reduces padding around checkbox + visualDensity: + VisualDensity.compact, + value: 2, + groupValue: widget + .mySelectedAllergy! + .allergyReactionDTOs![index] + .severity, + onChanged: (value) { + widget + .mySelectedAllergy! + .allergyReactionDTOs![ + index] + .severity = value; + setState(() {}); + }, + ), + AppText( + TranslationBase.of(context) + .moderate, + fontSize: 10, + ), + ], + ))), + Expanded( + child: ListTile( + contentPadding: EdgeInsets.zero , + + title: Row( + children: [ + Radio( + activeColor: Color(0xffD02127), + materialTapTargetSize: + MaterialTapTargetSize + .shrinkWrap, + // Reduces padding around checkbox + visualDensity: + VisualDensity.compact, + value: 3, + groupValue: widget + .mySelectedAllergy! + .allergyReactionDTOs![index] + .severity, + onChanged: (value) { + widget + .mySelectedAllergy! + .allergyReactionDTOs![ + index] + .severity = value; + setState(() {}); + }, + ), + AppText( + TranslationBase.of(context) + .severe, + fontSize: 10, + ), + ], + ))) + ], + ) + ], + ), + // Divider(), + ]); + }, + ))) + : Expanded( + child: RoundedContainer( + margin: EdgeInsets.all(15), + child: ListView.builder( + itemCount: widget.editSelectedAllergy! + .patientsAllergyReactionsDTOs!.length, + itemBuilder: (context, index) { + loading = false; + return Column(children: [ + ExpansionTile( + key: Key(index.toString()), + // dense: false, + // enableFeedback: false, + // showTrailingIcon: false, + initiallyExpanded: widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![index] + .isSelected!, + leading: Checkbox( + activeColor: Color(0xffD02127), + value: widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![ + index] + .isSelected!, + onChanged: (value) { + widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![ + index] + .isSelected = value; + setState(() {}); + }), + title: AppText(widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![index] + .allergyReactionName!), + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: ListTile( + contentPadding: EdgeInsets.zero , + + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Radio( + activeColor: Color(0xffD02127), + materialTapTargetSize: + MaterialTapTargetSize + .shrinkWrap, + // Reduces padding around checkbox + visualDensity: + VisualDensity.compact, + value: + TranslationBase.of(context) + .mild, + groupValue: getSeverityByID(widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![ + index] + .severity!), + onChanged: (value) { + widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![ + index] + .reactionSelection = + getSeverityByID(widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![ + index] + .severity!); + setState(() {}); + }, + ), + AppText( + TranslationBase.of(context) + .mild, + fontSize: 10, + ), + ], + ))), + Expanded( + child: ListTile( + contentPadding: EdgeInsets.zero , + + title: Row( + children: [ + Radio( + activeColor: Color(0xffD02127), + materialTapTargetSize: + MaterialTapTargetSize + .shrinkWrap, + // Reduces padding around checkbox + visualDensity: + VisualDensity.compact, + value: + TranslationBase.of(context) + .moderate, + groupValue: getSeverityByID(widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![ + index] + .severity!), + onChanged: (value) { + widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![ + index] + .reactionSelection = + getSeverityByID(widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![ + index] + .severity!); + setState(() {}); + }, + ), + AppText( + TranslationBase.of(context) + .moderate, + fontSize: 10, + ), + ], + ))), + Expanded( + child: ListTile( + contentPadding: EdgeInsets.zero , + + title: Row( + children: [ + Radio( + activeColor: Color(0xffD02127), + materialTapTargetSize: + MaterialTapTargetSize + .shrinkWrap, + // Reduces padding around checkbox + visualDensity: + VisualDensity.compact, + value: + TranslationBase.of(context) + .severe, + groupValue: getSeverityByID(widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![ + index] + .severity!), + onChanged: (value) { + widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![ + index] + .reactionSelection = + getSeverityByID(widget + .editSelectedAllergy! + .patientsAllergyReactionsDTOs![ + index] + .severity!); + + setState(() {}); + }, + ), + AppText( + TranslationBase.of(context) + .severe, + fontSize: 10, + ), + ], + ))) + ], + ) + ], + ), + Divider(), + ]); + }, + ))), + + Container( + margin: EdgeInsets.only(left: 15, right: 15), + child: AppTextFieldCustom( + + hintText: + TranslationBase.of(context).remarks, + controller: remark, + maxLines: 4, + minLines: 4, + hasBorder: true, + inputType: TextInputType.multiline, + + onClick: () {}, + onChanged: (value) {}, + onFieldSubmitted: () {}, + )), + SizedBox(height: 90,) + ], + ), + bottomSheet: Container( + height: 70, + color: Colors.white, + margin: EdgeInsets.all(10), + child: Row( + children: [ + Expanded( + child: Container( + child: AppButton( + title: TranslationBase.of(context).cancel, + vPadding: 8, + hPadding: 8, + color: Color(0xffEAEAEA), + fontColor: Colors.black, + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ), + ), + SizedBox( + width: 8, + ), + Expanded( + child: Container( + child: AppButton( + loading: loading, + title: TranslationBase.of(context).save, + vPadding: 8, + hPadding: 8, + color: AppGlobal.appGreenColor, + fontColor: Colors.white, + onPressed: () { + if (widget.isEdit == true) { + editAllergy(); + } else { + addAllergy(); + } + }, + ), + ), + ), + ], + )) + + // CustomBottomSheetContainer( + // buttonColor: Color(0xff359846), + // fontColor: Colors.white, + // label: TranslationBase.of(context).next, + // onTap: () { + // widget.addReactionFun(widget + // .mySelectedAllergy + // ); + // }, + // ) + + )); + } + + getSeverityByID(int id) { + Map severity = { + 1: TranslationBase.of(context).mild, + 2: TranslationBase.of(context).moderate, + 3: TranslationBase.of(context).severe + }; + return severity[id]; + } + + addAllergy() async { + setLoader(true); + AllergiesListVidaPlus request = widget.mySelectedAllergy!; + request.remark = remark.text; + request.allergyReactionDTOs = widget.mySelectedAllergy!.allergyReactionDTOs! + .where((i) => i.isSelected!) + .toList(); + await widget.model!.addAllergies(request, widget.patientInfo); + await widget.model!.getAllergiesVidaPlus(widget.patientInfo); + setLoader(false); + Navigator.of(context).pop(); + } + + editAllergy() async{ + setLoader(true); + PatientAllergiesVidaPlus request = widget.editSelectedAllergy!; + request.remark = remark.text; + request.patientsAllergyReactionsDTOs =[]; + widget.mySelectedAllergy!.allergyReactionDTOs! + .forEach((i){ + if(i.isSelected!){ + request.patientsAllergyReactionsDTOs!.add(PatientsAllergyReactionsDTOs( + pomrId: i.pomrid, + patientID:i.patientID, + hospitalGroupID:i.hospitalGroupID, + hospitalID:i.hospitalID, + isActive:i.isActive, + allergyReactionMappingID:i.allergyReactionMappingID, + allergyReactionID:i.allergyReactionID, + allergyReactionName: i.allergyReactionName, + severity:i.severity ??1 + + )); + } + }); + + await widget.model!.updateAllergies(request, widget.patientInfo); + + setLoader(false); + Navigator.of(context).pop(); + } + + setLoader(bool value) { + loading = value; + setState(() {}); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/update_allergies_widget.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/update_allergies_widget.dart new file mode 100644 index 00000000..755e49a6 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/allergies/update_allergies_widget.dart @@ -0,0 +1,304 @@ +import 'package:doctor_app_flutter/core/model/SOAP/allergy/get_allergies_list_vida_plus.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/allergy/get_patient_allergies_list_vida_plus.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_allergy.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/allergies/reactions_selection.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/add_soap_item.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/widgets/SoapDetailItem.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/utils/utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/loader/gif_loader_dialog_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:provider/provider.dart'; +import '../../../../../../core/model/patient/patiant_info_model.dart'; +import '../../../../../../widgets/transitions/fade_page.dart'; +import 'add_allergies.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; + +class UpdateAllergiesWidgetVidaPlus extends StatefulWidget { + List? myAllergiesList; + final PatiantInformtion patientInfo; + + UpdateAllergiesWidgetVidaPlus( + {Key? key, this.myAllergiesList, required this.patientInfo}); + + @override + _UpdateAllergiesWidgetState createState() => _UpdateAllergiesWidgetState(); +} + +bool noKnownAllergies = false; + +enum Severity { mild, moderate, severe } + +class _UpdateAllergiesWidgetState extends State { + SOAPViewModel? model; + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) {}, + builder: (_, model, w) => Column( + children: [ + SizedBox( + height: 20, + ), + AddSoapItem( + title: "${TranslationBase.of(context).addAllergies}", + onAddSoapItemClicked: () { + Navigator.push( + context, + FadePage( + page: AddAllergies( + patientInfo: widget.patientInfo, + // addAllergiesFun: (){ + // print("addAllergies save"); + // }, + ), + ), + ); + }, + ), + SizedBox( + height: 20, + ), + widget.myAllergiesList!.isEmpty + ? Row( + mainAxisSize: MainAxisSize.max, + children: [ + Checkbox( + value: noKnownAllergies, + checkColor: Colors.white, + activeColor: Colors.red, + onChanged: (value) { + noKnownAllergies = value!; + if(value){ + setNoKnownAllergy(model); + } + setState(() { + + }); + }, + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + // Reduces padding around checkbox + visualDensity: + VisualDensity.compact, // Minimizes size further + ), + AppText(TranslationBase.of(context).noKnownAllergies) + ], + ) + : Divider( + thickness: 1, + color: Color(0xffEFEFEF), + ), + ListView( + padding: EdgeInsets.all(10), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + children: widget.myAllergiesList!.map((selectedAllergy) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: AppText( + selectedAllergy.allergyName!, + fontSize: 12, + fontWeight: FontWeight.w800, + letterSpacing: -0.48, + ), + ), + SizedBox( + width: 8, + ), + Status( + status: (selectedAllergy.isActivePatientsAllergy == true ) ? TranslationBase.of(context).active : TranslationBase.of(context).resolved, + ) + ], + ), + selectedAllergy.patientsAllergyReactionsDTOs! + .isNotEmpty && + selectedAllergy.isActivePatientsAllergy! + ? ListView( + shrinkWrap: true, + children: selectedAllergy + .patientsAllergyReactionsDTOs! + .map((PatientsAllergyReactionsDTOs + reaction) => + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + SizedBox( + height: 5, + ), + Row( + children: [ + AppText( + reaction + .allergyReactionName!, + fontSize: 10, + ), + AppText(" - "), + AppText( + Severity + .values[ + reaction.severity! - + 1] + .name, + color: getColor( + reaction.severity!), + fontSize: 10, + fontWeight: FontWeight.w600, + letterSpacing: -0.48, + ) + ], + ) + ], + )) + .toList()) + : selectedAllergy.isActivePatientsAllergy! + ? AppText("----") + : AppText( + TranslationBase.of(context).resolved, + color: Colors.lightBlue, + fontSize: 10, + fontWeight: FontWeight.w600, + letterSpacing: -0.48, + ), + selectedAllergy.isActivePatientsAllergy! && + selectedAllergy.allergyID! != 0 + ? Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton.icon( + onPressed: () { + editAllergy(selectedAllergy, model); + }, + icon: SvgPicture.asset( + "assets/images/svgs/edit-icon.svg", + height: 16, + ), + label: AppText( + TranslationBase.of(context).edit, + fontSize: 12, + ), + ), + TextButton.icon( + onPressed: () { + resolveAllergy( + model, selectedAllergy); + }, + icon: SvgPicture.asset( + "assets/images/svgs/resolve.svg", + height: 18, + ), + label: AppText( + TranslationBase.of(context).resolve, + fontSize: 12, + color: Color(0xff359846))) + ], + ) + : selectedAllergy.allergyID! != 0 + ? Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton.icon( + onPressed: () { + activateAllergy( + model, selectedAllergy); + }, + icon: SvgPicture.asset( + "assets/images/svgs/resolve.svg", + height: 18, + color: Color(0xffD02127), + ), + label: AppText( + TranslationBase.of(context) + .activate, + fontSize: 12, + color: Color(0xffD02127))) + ], + ) + : SizedBox() + ], + ); + }).toList()), + ], + )); + } + + resolveAllergy( + SOAPViewModel model, PatientAllergiesVidaPlus selectedAllergy) async { + GifLoaderDialogUtils.showMyDialog(context); + + await model.resolveAllergies(selectedAllergy, widget.patientInfo); + await model.getAllergiesVidaPlus(widget.patientInfo); + GifLoaderDialogUtils.hideDialog(context); + } + + activateAllergy( + SOAPViewModel model, PatientAllergiesVidaPlus selectedAllergy) async { + GifLoaderDialogUtils.showMyDialog(context); + + await model.updateAllergies(selectedAllergy, widget.patientInfo); + await model.getAllergiesVidaPlus(widget.patientInfo); + GifLoaderDialogUtils.hideDialog(context); + } + + Color getColor(int severity) { + Map color = { + 1: Color(0xff359846), + 2: Color(0xFFCC9B14), + 3: Color(0xffD02127) + }; + return color[severity]; + } + + editAllergy( + PatientAllergiesVidaPlus selectedAllergy, SOAPViewModel model) async { + GifLoaderDialogUtils.showMyDialog(context); + await model.getEditAllergiesVidaPlus(selectedAllergy.allergyID!); + GifLoaderDialogUtils.hideDialog(context); + markSelected(selectedAllergy, model); + Navigator.push( + context, + FadePage( + page: ReactionsSelectionAllergiesWidget( + model: model, + mySelectedAllergy: model.searchAllergiesVidaPlus[0], + editSelectedAllergy: selectedAllergy!, + patientInfo: widget.patientInfo, + isEdit: true, + ))); + } + + markSelected(PatientAllergiesVidaPlus selectedAllergy, SOAPViewModel model) { + model.searchAllergiesVidaPlus[0].allergyReactionDTOs!.forEach((element) { + selectedAllergy.patientsAllergyReactionsDTOs!.forEach((element2) { + if (element.allergyReactionID == element2.allergyReactionID) { + element.isSelected = true; + element.severity =element2.severity; + } + }); + }); + } + + setNoKnownAllergy(SOAPViewModel model) async { + GifLoaderDialogUtils.showMyDialog(context); + AllergiesListVidaPlus request= AllergiesListVidaPlus(); + + + await model!.addAllergies(request, widget.patientInfo, isNoKnown: true); + await model!.getAllergiesVidaPlus(widget.patientInfo); + setState(() { + + }); + GifLoaderDialogUtils.hideDialog(context); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/AddChiefComplaints.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/AddChiefComplaints.dart new file mode 100644 index 00000000..7f94935f --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/AddChiefComplaints.dart @@ -0,0 +1,122 @@ +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/episode_by_chief_complaint_vidaplus.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/get_chief_complaint_vida_plus.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/patient_search/patient_search_header.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/ComplaintSelection.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/previous_cheif_complaints.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/loader/gif_loader_dialog_utils.dart'; +import 'package:flutter/material.dart'; + +class AddChiefComplaint extends StatefulWidget { + final List complaints; + final String selectedType; + final String? firstField; + final String? secondField; + final String? thirdField; + final PatiantInformtion patientInfo; + + const AddChiefComplaint( + {super.key, + required this.complaints, + required this.selectedType, + this.firstField, + this.secondField, + this.thirdField, + required this.patientInfo}); + + @override + State createState() => _AddChiefComplaintState(); +} + +class _AddChiefComplaintState extends State { + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) { + episodeByChiefComplaint(model); + }, + builder: (_, model, w) => AppScaffold( + isShowAppBar: true, + appBar: PatientSearchHeader( + title: TranslationBase.of(context).addChiefComplaint), + body: Padding( + padding: const EdgeInsets.all(20.0), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + ComplaintSelection( + complaints: widget.complaints, + selectedType: widget.selectedType, + firstField: widget.firstField, + secondField: widget.secondField, + thirdField: widget.thirdField, + searchData: model.searchChiefComplaintList, + onSearch: (String value) { + searchChiefComplaint(model, value); + }, + onSave: (String chiefComplaint) { + addChiefComplaint(model, chiefComplaint, context); + }, + onCrossClicked: (GetChiefComplaintVidaPlus chiefComplaint) { + updateChiefComplaint(model, chiefComplaint, context); + }, + ), + SizedBox( + height: 16, + ), + PreviousChiefComplaints( + model.episodeByChiefComplaintListVidaPlus, + (chiefComplains, String) { + var listOfChiefComplaint = [chiefComplains]; + createCCByEpisode(model, listOfChiefComplaint); + }, + ) + ], + ), + ), + ), + ), + ); + } + + addChiefComplaint( + SOAPViewModel model, String CC, BuildContext context) async { + GifLoaderDialogUtils.showMyDialog(context); + await model.saveChiefComplaint(widget.patientInfo, CC); + await model.getChiefComplaint(widget.patientInfo); + GifLoaderDialogUtils.hideDialog(context); + } + + searchChiefComplaint(SOAPViewModel model, String CC) async { + await model.searchChiefComplaint(widget.patientInfo, CC); + } + + updateChiefComplaint(SOAPViewModel model, GetChiefComplaintVidaPlus cc, + BuildContext context) async { + GifLoaderDialogUtils.showMyDialog(context); + await model.updateChiefComplaint(widget.patientInfo, cc); + await model.getChiefComplaint(widget.patientInfo); + GifLoaderDialogUtils.hideDialog(context); + setState(() {}); + } + + episodeByChiefComplaint(SOAPViewModel model) async { + WidgetsBinding.instance.addPostFrameCallback((_) async { + await model.episodeByChiefComplaint(widget.patientInfo); + }); + } + + createCCByEpisode(model, List chiefComplaint) async { + GifLoaderDialogUtils.showMyDialog(context); + var result = + await model.createCCByEpisode(widget.patientInfo, chiefComplaint); + GifLoaderDialogUtils.hideDialog(context); + if (result) Navigator.of(context).pop(); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/chief_complaints.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/chief_complaints.dart new file mode 100644 index 00000000..732fb50f --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/chief_complaints.dart @@ -0,0 +1,80 @@ +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/get_chief_complaint_vida_plus.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/subjective/medication/update_medication_widget.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/AddChiefComplaints.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/add_soap_item.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/complaint_items.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/empty_complaints.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/loader/gif_loader_dialog_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +class UpdateChiefComplaints extends StatelessWidget { + final List complaints; + final PatiantInformtion patientInfo; + + const UpdateChiefComplaints({Key? key, required this.complaints, required this.patientInfo}) + : super(key: key); + + @override + + Widget build(BuildContext context) { + TextEditingController medicationController = TextEditingController(); + return BaseView( + onModelReady: (model){ + WidgetsBinding.instance.addPostFrameCallback((_) { + getChiefComplaints(model); + }); + }, + builder: (_, model, w) => Padding( + padding: const EdgeInsets.all(12.0), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + AddSoapItem( + onAddSoapItemClicked: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (BuildContext context) => AddChiefComplaint( + complaints: model.getChiefComplaintListVidaPlus, + patientInfo: patientInfo, + + selectedType: '', + firstField: '', + secondField: '', + thirdField: ''), + )); + }, + title: TranslationBase.of(context).addChiefComplaint, + ), + SizedBox(height: 16), + if (model.getChiefComplaintListVidaPlus.isEmpty) ...{ + SizedBox( + width: MediaQuery.sizeOf(context).width, + child: EmptyComplaints(), + ) + } else ...{ + Container( + width: MediaQuery.of(context).size.width, + height: 40, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + itemCount: + model.getChiefComplaintListVidaPlus.length, + itemBuilder: (_, index) => ComplaintItems( + complaint: model + .getChiefComplaintListVidaPlus[index]!, + onCrossClicked: (complaints) {}))), + } + ]), + )); + } + getChiefComplaints(SOAPViewModel model){ + model.getChiefComplaint(patientInfo); + } + +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/ComplaintSelection.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/ComplaintSelection.dart new file mode 100644 index 00000000..871537d5 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/ComplaintSelection.dart @@ -0,0 +1,363 @@ +import 'dart:async'; +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/get_chief_complaint_vida_plus.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/search_chief_complaint_vidaplus.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/complaint_items.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; + +class ComplaintSelection extends StatefulWidget { + final List complaints; + final String selectedType; + final String? firstField; + final String? secondField; + final String? thirdField; + final Function(String cheifComplaint)? onSave; + final Function(String value)? onSearch; + final List? searchData; + final Function(GetChiefComplaintVidaPlus)? onCrossClicked; + const ComplaintSelection({super.key, + required this.complaints, + required this.selectedType, + this.firstField, + this.secondField, + this.thirdField, + this.onSave, + this.onSearch, + this.searchData, + this.onCrossClicked + }); + + @override + State createState() => _ComplaintSelectionState(); +} + +class _ComplaintSelectionState extends State { + final TextEditingController firstEditingController = TextEditingController(); + final TextEditingController secondEditingController = TextEditingController(); + final TextEditingController thirdEditingController = TextEditingController(); + OverlayEntry? _overlayEntry; + + @override + void initState() { + super.initState(); + firstEditingController.text = widget.firstField ?? ''; + secondEditingController.text = widget.secondField ?? ''; + thirdEditingController.text = widget.thirdField ?? ''; + _focus.addListener(_onFocusChange); + } + + void _onFocusChange() { + removeOverlay(); + } + + void _showOverlay(BuildContext context) { + print("the function is called"); + + _overlayEntry?.remove(); + + final overlay = Overlay.of(context); + final renderBox = context.findRenderObject() as RenderBox; + final position = renderBox.localToGlobal(Offset.zero); + print( + 'the position is $position and render box is ${renderBox.size.height}'); + _overlayEntry = OverlayEntry( + builder: (context) => + Positioned( + left: position.dx, + top: position.dy + renderBox.size.height - 12, + child: Material( + elevation: 4.0, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + SizedBox(width: MediaQuery + .sizeOf(context) + .width - 50, child: Text("Option 1"),) + ], + ), + ), + ), + ), + ); + + overlay?.insert(_overlayEntry!); + } + + void removeOverlay() { + _overlayEntry?.remove(); + _overlayEntry = null; + } + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model){ + + }, + builder: (_, model, w) => Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + TranslationBase + .of(context) + .addChiefComplaint, + fontSize: 16, + fontWeight: FontWeight.w600, + textAlign: TextAlign.start, + color: Colors.black, + ), + ListTileTheme( + horizontalTitleGap: 0, + child: CheckboxListTile( + value: true, + enabled: false, + checkColor: Colors.white, + activeColor: Color(0xFFD02127), + side: MaterialStateBorderSide.resolveWith( + (Set states) { + if (states.contains(MaterialState.selected)) { + return const BorderSide(color: Color(0xFFD02127)); + } + return const BorderSide(color: Color(0xFFE6E6E6)); + }, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16)), + controlAffinity: ListTileControlAffinity.leading, + onChanged: (bool? value) {}, + title: AppText( + TranslationBase + .of(context) + .addChiefComplaint, + color: Color(0XFF575757), + fontSize: 14, + fontWeight: FontWeight.w400, + ), + contentPadding: EdgeInsets.zero), + ), + ListTileTheme( + horizontalTitleGap: 0, + child: CheckboxListTile( + value: true, + activeColor: Color(0xFFD02127), + checkColor: Colors.white, + + controlAffinity: ListTileControlAffinity.leading, + side: MaterialStateBorderSide.resolveWith( + (Set states) { + if (states.contains(MaterialState.selected)) { + return const BorderSide(color: Color(0xFFD02127)); + } + return const BorderSide(color: Color(0xFFE6E6E6)); + }, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16)), + onChanged: (bool? value) {}, + title: AppText( + TranslationBase + .of(context) + .generalList, + color: Color(0XFF575757), + fontSize: 14, + fontWeight: FontWeight.w400, + ), + contentPadding: EdgeInsets.zero), + ), + ListTileTheme( + horizontalTitleGap: 0, + child: CheckboxListTile( + activeColor: Color(0xFFD02127), + checkColor: Colors.white, + contentPadding: EdgeInsets.zero, + side: MaterialStateBorderSide.resolveWith( + (Set states) { + if (states.contains(MaterialState.selected)) { + return const BorderSide(color: Color(0xFFD02127)); + } + return const BorderSide(color: Color(0xFFE6E6E6)); + }, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16)), + value: false, + controlAffinity: ListTileControlAffinity.leading, + onChanged: (bool? value) {}, + title: AppText( + TranslationBase + .of(context) + .specialList, + color: Color(0XFF575757), + fontSize: 14, + fontWeight: FontWeight.w400, + ), + ), + ), + TextWithSelectedItems(model) + ], + ), + ), + )); + } + + FocusNode _focus = FocusNode(); + Timer? _tTimer; + void _onStopped(String text) { + widget.onSearch!(text); + print(text); + } + + void _onTextChanged(String text) { + + if (_tTimer != null) { + _tTimer!.cancel(); + } + _tTimer = Timer(Duration(milliseconds: 500), (){ + _onStopped(text); + + }); + } + TextEditingController searchController = TextEditingController(); + Widget TextWithSelectedItems(SOAPViewModel model) { + return Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 8,), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: AppText(TranslationBase + .of(context) + .enterChiefCompliants, + fontWeight: FontWeight.w600, + fontSize: 11, + textAlign: TextAlign.start, + ), + ), + SizedBox( + height: 8, + ), + Row( + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.only(left: 10, right: 10), + child: TextFormField( + autofocus: true, + controller: searchController, + textInputAction: TextInputAction.done, + decoration: InputDecoration( + hintText: '', + border: InputBorder.none, + isCollapsed: true, + suffixIcon: model.state == ViewState.BusyLocal + ? Transform.scale( + scale: 0.5, + child: CircularProgressIndicator( + strokeWidth: 2, + ), + ) + :(searchController.text.isNotEmpty) ?IconButton( + icon: Icon( + Icons.save_as_outlined, + color: Colors.red, + size: 25, + ), + onPressed: () { + if(searchController.text.isNotEmpty) { + widget.onSave?.call(searchController.text); + searchController.text =''; + } + }): SizedBox.shrink(), + ), + onChanged: _onTextChanged, + onEditingComplete: (){ + if(searchController.text.isNotEmpty) { + widget.onSave?.call(searchController.text); + searchController.text =''; + } + }, + )), + ) + ], + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Material( + elevation: 4.0, // Optional: for shadow effect + child: + ConstrainedBox( + constraints: BoxConstraints( + minHeight: 0, + maxHeight: 300), + child: + ListView.builder( + shrinkWrap: true, + itemCount: widget.searchData!.length, + itemBuilder: (context, index) { + return ListTile( + + title: InkWell(child:AppText(widget.searchData![index].chiefComplain!), onTap:(){ + var cc = widget.searchData![index].chiefComplain; + model.searchChiefComplaintList!.length =0; + setState((){}); + + widget.onSave!(cc!); + searchController.text =''; + })); + }))), + ), + + SizedBox( + height: 43, + child: Row( + children: [ + + Expanded( + child: ListView.builder(scrollDirection: Axis.horizontal, + itemCount: widget.complaints.length, + itemBuilder: (context, index) { + + return ComplaintItems( + complaint: widget.complaints[index]!, + isDeletable:true, + onCrossClicked: (complaints) { + widget.onCrossClicked!(complaints); + }); + }) + // }), + ), + ], + ), + ), + SizedBox(height: 8,), + ], + ), + ); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/add_soap_item.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/add_soap_item.dart new file mode 100644 index 00000000..ea0cacb9 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/add_soap_item.dart @@ -0,0 +1,35 @@ +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class AddSoapItem extends StatelessWidget{ + final VoidCallback onAddSoapItemClicked; + final String title; + + const AddSoapItem({super.key, required this.onAddSoapItemClicked, required this.title}); + @override + Widget build(BuildContext context) { + return Row( + children: [ + Expanded( + child: AppButton( + + elevation:0, + + icon: SvgPicture.asset('assets/images/svgs/add-square.svg'), + title:this.title, + color: Color(0xffEAEAEA), + fontColor: Colors.black, + fontWeight: FontWeight.w600, + disabled: false, + onPressed: () async { + onAddSoapItemClicked(); + }, + ), + ), + ], + ); + } + +} \ No newline at end of file diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/complaint_items.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/complaint_items.dart new file mode 100644 index 00000000..3fa49ba4 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/complaint_items.dart @@ -0,0 +1,61 @@ +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/get_chief_complaint_vida_plus.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; + +class ComplaintItems extends StatefulWidget { + final GetChiefComplaintVidaPlus complaint; + final Function(GetChiefComplaintVidaPlus) onCrossClicked; + final bool isDeletable; + + const ComplaintItems( + {super.key, required this.complaint, required this.onCrossClicked, this.isDeletable = false}); + + + @override + State createState() => _ComplaintItemsState(); +} + +class _ComplaintItemsState extends State { + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(5.0), + + margin:const EdgeInsets.all(5.0) , + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0xffEAEAEA), + borderRadius: BorderRadius.circular( + 5, + )), + child: Row(children: [ SizedBox( + width: 120, + child: Text( + widget.complaint.chiefComplain!, + style: TextStyle( + overflow: TextOverflow.ellipsis, + fontWeight: FontWeight.w400, + height: 1.2, + fontSize: 14, + color: Color(0xFF575757), + ), + maxLines: 1, + softWrap: false, + textAlign: TextAlign.center, + ), + ), + widget.isDeletable ? InkWell( + onTap: () { + widget.onCrossClicked(widget.complaint); + }, + child: Icon( + Icons.close, + size: 18, + color: Color(0xFFD02127), + ), + ) :SizedBox() + ],), + ); + + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/empty_complaints.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/empty_complaints.dart new file mode 100644 index 00000000..44412e8d --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/empty_complaints.dart @@ -0,0 +1,26 @@ +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import '../../../../../../../utils/translations_delegate_base_utils.dart'; + +class EmptyComplaints extends StatelessWidget{ + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment : MainAxisAlignment.center, + children: [ + SvgPicture.asset('assets/images/svgs/unavailable.svg'), + SizedBox(height: 10,), + AppText( + TranslationBase.of(context).noComplaintsFound, + fontSize: 12, + fontWeight: FontWeight.w400, + textAlign: TextAlign.center, + color: Color(0xFFADADAD), + ) + ], + ); + } + +} \ No newline at end of file diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/listOfComplaints.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/listOfComplaints.dart new file mode 100644 index 00000000..5ca2912d --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/listOfComplaints.dart @@ -0,0 +1,136 @@ +import 'package:flutter/material.dart'; + +import '../../../../../../../utils/translations_delegate_base_utils.dart'; +import '../../../../../../../widgets/shared/app_texts_widget.dart'; +import '../../../../../../../widgets/shared/buttons/app_buttons_widget.dart'; + +class ListOfComplaintsItem extends StatelessWidget { + final String name; + final String createdBy; + final String createdAt; + final VoidCallback onSendClick; + + const ListOfComplaintsItem( + {super.key, + required this.name, + required this.createdBy, + required this.createdAt, + required this.onSendClick}); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Text( + name, + textAlign: TextAlign.start, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + color: Color(0xFF2E303A), + overflow: TextOverflow.clip), + ), + SizedBox( + height: 4, + ), + Row( + children: [ + Text(TranslationBase.of(context).createdBy, + textAlign: TextAlign.start, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 15, + color: Color(0xFF2E303A), + )), + SizedBox( + width: 4, + ), + Expanded( + child: Text(createdBy, + textAlign: TextAlign.start, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 12, + overflow: TextOverflow.ellipsis, + color: Color(0xFF2E303A), + )), + ), + ], + ), + // Row( + // children: [ + // Expanded( + // child: AppText( + // TranslationBase.of(context).createdBy, + // fontWeight: FontWeight.w400, + // fontSize: 15, + // color: Color(0xFF2E303A), + // textAlign: TextAlign.start, + // ), + // ), + // SizedBox( + // width: 4, + // ), + // AppText( + // createdBy, + // fontWeight: FontWeight.w400, + // fontSize: 12, + // textAlign: TextAlign.start, + // textOverflow: TextOverflow.ellipsis, + // color: Color(0xFF2E303A), + // ) + // ], + // ), + SizedBox( + height: 5, + ), + Row( + children: [ + Text(TranslationBase.of(context).createdOn, + textAlign: TextAlign.start, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 15, + color: Color(0xFF2E303A), + )), + SizedBox( + width: 4, + ), + Expanded( + child: Text(createdAt, + textAlign: TextAlign.start, + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 12, + overflow: TextOverflow.ellipsis, + color: Color(0xFF2E303A), + )), + ), + ], + ) + ], + ), + ), + SizedBox( + width: 77, + height: 27, + child: AppButton( + title: TranslationBase.of(context).select, + hPadding: 8, + color: Color(0xFFD02127), + fontColor: Colors.white, + onPressed: () { + onSendClick(); + }, + ), + ), + ], + ); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/previous_cheif_complaints.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/previous_cheif_complaints.dart new file mode 100644 index 00000000..0754e234 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/previous_cheif_complaints.dart @@ -0,0 +1,152 @@ +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/episode_by_chief_complaint_vidaplus.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/chief_complaint/get_chief_complaint_vida_plus.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/listOfComplaints.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:quiver/time.dart'; + +class PreviousChiefComplaints extends StatelessWidget { + final List complaints; + final Function(PatientPomrs , String)? onSendClicked; + + PreviousChiefComplaints( + this.complaints, + this.onSendClicked, { + super.key, + }); + + @override + Widget build(BuildContext context) { + return Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + width: 1, + color: Color(0xFFEFEFEF), + )), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(TranslationBase.of(context).previousChiefCompaints, + textAlign: TextAlign.start, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + color: Color(0xFF2E303A), + )), + SizedBox( + height: 16, + ), + AppText( + TranslationBase.of(context).listOfActiveEpisodes, + fontWeight: FontWeight.w400, + fontSize: 14, + textAlign: TextAlign.start, + color: Color(0xFF575757), + ), + SizedBox( + height: 10, + ), + Flexible( + child: ListView.builder( + shrinkWrap: true, + itemCount: complaints.length, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + return ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: + complaints[index].patientPomrs?.length ?? 0, + itemBuilder: (context, pomrID) { + return ListView.separated( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: complaints[index] + .patientPomrs?[pomrID] + .chiefComplains + ?.length ?? + 0, + separatorBuilder: (context, _) => Column( + children: [ + SizedBox(height: 10,), + Divider(), + SizedBox(height: 10,), + ], + ), + itemBuilder: (context, cheifComplainIndex) { + return ListOfComplaintsItem( + name: complaints[index] + .patientPomrs![pomrID] + .chiefComplains?[ + cheifComplainIndex] + .chiefComplain ?? + '', + // createdBy: getChildValue(complaints[index].patientPomrs!,2), + createdBy: complaints[index] + .patientPomrs![pomrID] + .chiefComplains?[ + cheifComplainIndex] + .createdBy ?? + '', + createdAt: complaints[index] + .patientPomrs![pomrID] + .chiefComplains?[ + cheifComplainIndex] + .createdOn ?? + '', + onSendClick: () { + onSendClicked!( + complaints[index] + .patientPomrs![pomrID] + ,complaints[index] + .patientPomrs?[pomrID].chiefComplainTemplateId?.toString() ??''); + }); + }); + // return Column( + // children: complaints[index].patientPomrs![pomrID].chiefComplains?.map((element)=>ListOfComplaintsItem( + // name: element.chiefComplain ?? '', + // // createdBy: getChildValue(complaints[index].patientPomrs!,2), + // createdBy: element.createdBy ?? '', + // createdAt: element.createdOn ?? '', + // onSendClick: () { + // onSendClicked!(complaints[index].patientPomrs!); + // })).toList()??[], + // ); + }, + ); + // return complaints[index].patientPomrs!.isNotEmpty ? ListOfComplaintsItem( + // name: getChildValue(complaints[index].patientPomrs!, 1), + // createdBy: getChildValue(complaints[index].patientPomrs!,2), + // createdAt: getChildValue(complaints[index].patientPomrs!, 3), + // onSendClick: () { + // onSendClicked!(complaints[index].patientPomrs!); + // }) :SizedBox(); + })) + ], + ), + )); + } + + String getChildValue(List? patientPomrs, int key) { + List value = []; + patientPomrs!.forEach((element) { + if (key == 1) { + element.chiefComplains!.forEach((element2) { + value.add(element2.chiefComplain!); + }); + } else if (key == 2) { + value.add(element.doctorName!); + } else { + value.add(element.createdOn!); + } + }); + + return value.join(" "); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/medication/add_medication.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/medication/add_medication.dart new file mode 100644 index 00000000..9cf67d16 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/medication/add_medication.dart @@ -0,0 +1,454 @@ +// ignore: must_be_immutable +import 'package:autocomplete_textfield/autocomplete_textfield.dart'; +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/home_medication_vp/GetSearchCurrentMedication.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_allergy.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/model/search_drug/get_medication_response_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/medicine/medicine_search_screen.dart'; +import 'package:doctor_app_flutter/screens/patients/patient_search/patient_search_header.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/bottom_sheet_title.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/objective/widget/EmptyExamination.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/medication/dropdown_popup.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/utils/utils.dart'; +import 'package:doctor_app_flutter/widgets/bottom_sheet/custom_bottom_sheet_container.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/dialogs/master_key_dailog.dart'; +import 'package:doctor_app_flutter/widgets/shared/loader/gif_loader_dialog_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/rounded_container_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/auto_complete_text_field.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/text_fields_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:provider/provider.dart'; + +// ignore: must_be_immutable +class AddMedication extends StatefulWidget { + final Function() addMedicationFun; + final PatiantInformtion? patientInfo; + AddMedication({Key? key, required this.addMedicationFun, this.patientInfo}) : super(key: key); + + @override + _AddMedicationState createState() => _AddMedicationState(); +} + +class _AddMedicationState extends State { + int? _selectedMedicationStrength; + int? _selectedMedicationRoute; + int? _selectedMedicationFrequency; + TextEditingController medicationController = TextEditingController(); + + TextEditingController doseController = TextEditingController(); + TextEditingController strengthController = TextEditingController(); + TextEditingController routeController = TextEditingController(); + TextEditingController frequencyController = TextEditingController(); + GetSearchCurrentMedication? _selectedMedication; + TextEditingController remark = TextEditingController(); + bool isVisible = false; + GlobalKey> key = + GlobalKey>(); + bool isFormSubmitted = false; + + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + return BaseView( + onModelReady: (model) async { + // model.onAddMedicationStart(); + }, + builder: (_, model, w) => AppScaffold( + backgroundColor: Colors.white, + baseViewModel: model, + isShowAppBar: true, + appBar: PatientSearchHeader( + title: TranslationBase.of(context).addMedication, + ), + body: Container( + padding: EdgeInsets.all(15), + child: SingleChildScrollView( + child: Column( + children: [ + + AppTextFieldCustom( + height: Utils.getTextFieldHeight(), + controller: medicationController, + hintText: + TranslationBase.of(context).searchMedicineNameHere, + minLines: 1, + maxLines: 1, + isTextFieldHasSuffix: true, + validationError: isFormSubmitted && medicationController.text.isEmpty ? TranslationBase.of(context).emptyMessage : null, + suffixIcon: IconButton( + icon: model.state == ViewState.BusyLocal + ? SizedBox( + child: CircularProgressIndicator( + strokeWidth: 2, + ), + height: 10, + width: 10, + ) + : Icon( + Icons.search, + color: Colors.grey.shade600, + ), + onPressed: () { + searchMedication(model); + }, + ), + onChanged: (value) {}, + onFieldSubmitted: () {}, + ), + // ), + // ), + model.getMedicationListVP!.isNotEmpty & isVisible + ? RoundedContainer( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height * 0.60, + child: model.state == ViewState.Idle + ? ListView.builder( + itemCount: model.getMedicationListVP!.length, + itemBuilder: (context, index) { + return ListTile( + onTap: () { + selectMedication(model, index); + }, + title: AppText( + model.getMedicationListVP![index] + .formularyName!, + )); + }, + ) + : SizedBox()) + : SizedBox(), + + if (_selectedMedication != null) + Column( + children: [ + SizedBox( + height: 3, + ), + Container( + width: MediaQuery.of(context).size.width * 0.9, + child: AppText( + _selectedMedication!.formularyName!, + color: Color(0xFF575757), + fontSize: 10, + fontWeight: FontWeight.w700, + letterSpacing: -0.4, + ), + ), + ], + ), + SizedBox( + height: 5, + ), + + SizedBox( + height: 5, + ), + AppTextFieldCustom( + height: Utils.getTextFieldHeight(), + enabled: true, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + // onClick: model.medicationDoseTimeList != null + // ? () { + // MasterKeyDailog dialog = MasterKeyDailog( + // list: model.medicationDoseTimeList, + // okText: TranslationBase.of(context).ok, + // // selectedValue: _selectedMedicationDose, + // okFunction: (selectedValue) { + // setState(() { + // _selectedMedicationDose = selectedValue; + // + // doseController.text = projectViewModel.isArabic ? _selectedMedicationDose!.nameAr! : _selectedMedicationDose!.nameEn!; + // }); + // }, + // ); + // showDialog( + // barrierDismissible: false, + // context: context, + // builder: (BuildContext context) { + // return dialog; + // }, + // ); + // } + // : null, + hintText: TranslationBase.of(context).doseDetails, + maxLines: 1, + minLines: 1, + + isTextFieldHasSuffix: false, + controller: doseController, + validationError: isFormSubmitted && doseController.text.isEmpty ? TranslationBase.of(context).emptyMessage : null, + onChanged: (value) {}, + onFieldSubmitted: () {}, + ), + SizedBox( + height: 10, + ), + AppTextFieldCustom( + height: Utils.getTextFieldHeight(), + enabled: false, + isTextFieldHasSuffix: true, + onClick: model.getSearchCurrentMedicationDetails! + .isNotEmpty && + model.getSearchCurrentMedicationDetails![0] + .itemStrengthDetailsDto != + null + ? () { + + DropdownPopup dialog = DropdownPopup( + medicationDetails: + model.getSearchCurrentMedicationDetails![0], + isStrength: true, + okText: TranslationBase.of(context).ok, + selectedID:model.getSearchCurrentMedicationDetails![0] + .itemStrengthDetailsDto![0] + .strengthId!, + okFunction: (int id, String value) { + _selectedMedicationStrength = id; + strengthController.text = value; + setState(() {}); + }, + ); + showDialog( + barrierDismissible: false, + context: context, + builder: (BuildContext context) { + return dialog; + }, + ); + } + : null, + hintText: TranslationBase.of(context).strength, + maxLines: 1, + minLines: 1, + controller: strengthController, + // validationError: isFormSubmitted && _selectedMedicationStrength == null ? TranslationBase.of(context).emptyMessage : null, + onChanged: (value) {}, + onFieldSubmitted: () {}, + ), + SizedBox( + height: 5, + ), + SizedBox( + height: 5, + ), + + AppTextFieldCustom( + height: Utils.getTextFieldHeight(), + enabled: false, + isTextFieldHasSuffix: true, + + onClick: model.getSearchCurrentMedicationDetails! + .isNotEmpty && + model.getSearchCurrentMedicationDetails![0] + .genericItemRouteDetailsEntity != + null + ? () { + + DropdownPopup dialog = DropdownPopup( + medicationDetails: + model.getSearchCurrentMedicationDetails![0], + okText: TranslationBase.of(context).ok, + isRoute: true, + selectedID: model + .getSearchCurrentMedicationDetails![0] + .genericItemRouteDetailsEntity![0] + .routeId!, + // selectedText: , + okFunction: (int id, String value) { + setState(() { + _selectedMedicationRoute = id; + routeController.text = value; + }); + }, + ); + showDialog( + barrierDismissible: false, + context: context, + builder: (BuildContext context) { + return dialog; + }, + ); + } + : null, + hintText: TranslationBase.of(context).route, + maxLines: 1, + minLines: 1, + controller: routeController, + // validationError: isFormSubmitted && _selectedMedicationRoute == null ? TranslationBase.of(context).emptyMessage : null, + onChanged: (value) {}, + onFieldSubmitted: () {}, + ), + SizedBox( + height: 10, + ), + + AppTextFieldCustom( + height: Utils.getTextFieldHeight(), + + onClick: model.getSearchCurrentMedicationDetails! + .isNotEmpty && + model.getSearchCurrentMedicationDetails![0] + .genericItemFrequencyDetailsEntity != + null + ? () { + + DropdownPopup dialog = DropdownPopup( + medicationDetails: + model.getSearchCurrentMedicationDetails![0], + okText: TranslationBase.of(context).ok, + selectedID: model + .getSearchCurrentMedicationDetails![0] + .genericItemFrequencyDetailsEntity![0] + .frequencyId! , + okFunction: (int id, String value) { + _selectedMedicationFrequency = id; + frequencyController.text = value; + setState(() {}); + }, + ); + showDialog( + barrierDismissible: false, + context: context, + builder: (BuildContext context) { + return dialog; + }, + ); + } + : null, + hintText: TranslationBase.of(context).frequency, + enabled: false, + maxLines: 1, + minLines: 1, + isTextFieldHasSuffix: true, + controller: frequencyController, + + // validationError: isFormSubmitted && _selectedMedicationFrequency == null ? TranslationBase.of(context).emptyMessage : null, + onChanged: (value) {}, + onFieldSubmitted: () {}, + ), + SizedBox( + height: 10, + ), + AppTextFieldCustom( + hintText: TranslationBase.of(context).remarks, + controller: remark, + maxLines: 4, + minLines: 4, + hasBorder: true, + inputType: TextInputType.multiline, + onClick: () {}, + onChanged: (value) {}, + onFieldSubmitted: () {}, + ) + ], + ), + ), + ), + bottomSheet: + CustomBottomSheetContainer( + label: TranslationBase.of(context).addMedication, + onTap: () { + if(medicationController.text.isNotEmpty && doseController.text.isNotEmpty){ + addMedication(model); + }else { + isFormSubmitted = true; + setState(() { + + }); + } + }, + )), + ); + } + + searchMedication(model) async { + await model.searchCurrentMedication(medicationController.text); + isVisible = true; + setState(() {}); + } + + selectMedication(SOAPViewModel model, int index) { + _selectedMedication = model.getMedicationListVP![index]; + medicationController.text = + model.getMedicationListVP![index].formularyName!; + isVisible = false; + getOtherDetails(model, model.getMedicationListVP![index]); + setState(() {}); + } + + getOtherDetails( + SOAPViewModel model, GetSearchCurrentMedication selectMedicine) async { + GifLoaderDialogUtils.showMyDialog(context); + await model.getCurrentMedicationDetails(selectMedicine.genericFormularyId!); + + GifLoaderDialogUtils.hideDialog(context); + setDefaultValues(model); + } + setDefaultValues(SOAPViewModel model){ + _selectedMedicationStrength = model.getSearchCurrentMedicationDetails![0] + .itemStrengthDetailsDto![0] + .strengthId!; + strengthController.text = model + .getSearchCurrentMedicationDetails![0] + .itemStrengthDetailsDto![0] + .strength!; + + _selectedMedicationRoute = model + .getSearchCurrentMedicationDetails![0] + .genericItemRouteDetailsEntity![0] + .routeId!; + routeController.text= model + .getSearchCurrentMedicationDetails![0] + .genericItemRouteDetailsEntity![0] + .route!; + _selectedMedicationFrequency = model + .getSearchCurrentMedicationDetails![0] + .genericItemFrequencyDetailsEntity![0] + .frequencyId!; + frequencyController.text= model + .getSearchCurrentMedicationDetails![0] + .genericItemFrequencyDetailsEntity![0] + .frequency!; + + } + + addMedication(SOAPViewModel model) async{ + Map request ={ + + "doseQuantity": doseController.text, + "frequencyId": _selectedMedicationFrequency, + "frequencyString":frequencyController.text, + "strengthId": _selectedMedicationStrength, + "strengthString": strengthController.text, + "routeId": _selectedMedicationRoute, + "routeString": routeController.text, + "remarks": remark.text, + "sentence": medicationController.text, + "formularyName": _selectedMedication!.formularyName!, + "genericFormularyId": _selectedMedication!.genericFormularyId!, + + }; + GifLoaderDialogUtils.showMyDialog(context); + + await model.addCurrentMedication(request, widget.patientInfo!); + await model.getHomeMedication(widget.patientInfo!); + GifLoaderDialogUtils.hideDialog(context); + Navigator.of(context).pop(); + + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/medication/dropdown_popup.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/medication/dropdown_popup.dart new file mode 100644 index 00000000..07f7a617 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/medication/dropdown_popup.dart @@ -0,0 +1,150 @@ +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/home_medication_vp/GetSearchCurrentMedicationDetails.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + + +class DropdownPopup extends StatefulWidget { + final GetSearchCurrentMedicationDetails? medicationDetails; + bool isStrength; + bool isRoute; + bool isFrequency; + int? selectedID; + String? selectedText; + final okText; + final Function(int selectedID, String selectedText)? okFunction; + DropdownPopup({this.medicationDetails, this.isStrength = false, this.okFunction, this.okText, this.selectedID, this.isRoute =false, this.isFrequency =false, this.selectedText }); + + @override + _DropdownPopupState createState() => _DropdownPopupState(); +} + +class _DropdownPopupState extends State { + @override + void initState() { + super.initState(); + + } + + @override + Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + return showAlertDialog(context, projectViewModel); + } + + showAlertDialog(BuildContext context, ProjectViewModel projectViewModel) { + // set up the buttons + Widget cancelButton = ElevatedButton( + child: AppText( + TranslationBase.of(context).cancel, + color: Colors.white, + fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * (SizeConfig.isWidthLarge ? 3.5 : 5), + ), + onPressed: () { + Navigator.of(context).pop(); + }); + Widget continueButton = ElevatedButton( + child: AppText( + this.widget.okText, + color: Colors.white, + fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * (SizeConfig.isWidthLarge ? 3.5 : 5), + ), + onPressed: () { + + // this.widget.okFunction(selectedValue); + Navigator.of(context).pop(); + }); +// set up the AlertDialog + AlertDialog alert = AlertDialog( + // title: Text(widget.title), + content: createDialogList(projectViewModel), + actions: [ + cancelButton, + continueButton, + ], + ); + return alert; + } + + Widget createDialogList(ProjectViewModel projectViewModel) { + return Container( + height: MediaQuery.of(context).size.height * 0.5, + child: SingleChildScrollView( + child: widget.isStrength ? Column( + children: [ + + ...widget.medicationDetails!.itemStrengthDetailsDto! + .map((item) => RadioListTile( + title: AppText( + '${item.strength}', + ), + groupValue: widget.selectedID!.toString(), + value: item.strengthId.toString(), + activeColor: Colors.blue.shade700, + selected: item.strengthId.toString() == widget.selectedID!.toString(), + onChanged: (val) { + widget.selectedID = item.strengthId; + widget.selectedText = item.strength; + widget.okFunction!( item.strengthId!, item.strength!); + + }, + )) + .toList() + ], + ) : + + widget.isRoute ? Column( children: [ + + ...widget.medicationDetails!.genericItemRouteDetailsEntity! + .map((item) => RadioListTile( + title: AppText( + '${item.route}', + ), + groupValue: widget.selectedID!.toString(), + value: item.routeId.toString(), + activeColor: Colors.blue.shade700, + selected: item.routeId.toString() == widget.selectedID!.toString(), + onChanged: (val) { + widget.selectedID = item.routeId; + widget.selectedText = item.route; + widget.okFunction!( item.routeId!, item.route!); + + }, + )) + .toList() + ], + ) : Column( children: [ + + ...widget.medicationDetails!.genericItemFrequencyDetailsEntity! + .map((item) => RadioListTile( + title: AppText( + '${item.frequency}', + ), + groupValue: widget.selectedID!.toString(), + value: item.frequencyId.toString(), + activeColor: Colors.blue.shade700, + selected: item.frequencyId.toString() == widget.selectedID!.toString() , + onChanged: (val) { + widget.selectedID = item.frequencyId; + widget.selectedText = item.frequency; + widget.okFunction!( item.frequencyId!, item.frequency!); + setState(() { + + }); + }, + )) + .toList() + ], + ), + ), + ); + } + + static closeAlertDialog(BuildContext context) { + Navigator.of(context).pop(); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/medication/update_medication_widget.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/medication/update_medication_widget.dart new file mode 100644 index 00000000..a0882796 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/medication/update_medication_widget.dart @@ -0,0 +1,96 @@ +import 'package:doctor_app_flutter/core/model/SOAP/home_medication_vp/GetHomeMedication.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_allergy.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/SOAP_open_items.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/chief_complaint/widgets/add_soap_item.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/loader/gif_loader_dialog_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:doctor_app_flutter/widgets/transitions/fade_page.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import 'add_medication.dart'; + +class UpdateMedicationWidget extends StatefulWidget { + final PatiantInformtion patientInfo; + + UpdateMedicationWidget({ + Key? key, + required this.patientInfo, + }); + + @override + _UpdateMedicationWidgetState createState() => _UpdateMedicationWidgetState(); +} + +class _UpdateMedicationWidgetState extends State { + TextEditingController medicationController = TextEditingController(); + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) async { + WidgetsBinding.instance.addPostFrameCallback((_) { + model.getHomeMedication(widget.patientInfo); + }); + }, + builder: (_, model, w) => Column(children: [ + AddSoapItem( + title: "${TranslationBase.of(context).addMedication}", + onAddSoapItemClicked: () { + Navigator.push( + context, + FadePage( + page: AddMedication( + patientInfo: widget.patientInfo, + addMedicationFun: () {}))); + // openMedicationList(context); + }, + ), + SizedBox( + height: 20, + ), + ListView( + padding: EdgeInsets.all(10), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + children: model.getHomeMedicationList!.map((medication) { + return ListTile( + trailing: TextButton.icon( + onPressed: () { + removeMedication(medication, model); + }, + icon: SvgPicture.asset( + "assets/images/svgs/delete.svg", + height: 18, + color: Color(0xffD02127), + ), + label: AppText(TranslationBase.of(context).remove, + fontSize: 12, color: Color(0xffD02127))), + title: AppText( + medication.prescribedItemName!, + fontSize: 12, + fontWeight: FontWeight.w800, + letterSpacing: -0.48, + ), + subtitle: AppText( + '${medication.doseQuantity!} - ${medication.frequencyString!}', + fontSize: 10, + ), + ); + }).toList()), + ])); + } + + removeMedication( + GetHomeMedicationList medication, SOAPViewModel model) async { + GifLoaderDialogUtils.showMyDialog(context); + await model.removeCurrentMedication(medication.id!); + await model.getHomeMedication(widget.patientInfo); + GifLoaderDialogUtils.hideDialog(context); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/present_illness/update_present_illness.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/present_illness/update_present_illness.dart new file mode 100644 index 00000000..70fb1250 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/present_illness/update_present_illness.dart @@ -0,0 +1,277 @@ +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/loader/gif_loader_dialog_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; + + +class UpdatePresentIllness extends StatefulWidget { + PatiantInformtion? patientInfo; + UpdatePresentIllness(this.patientInfo, {Key? key}) : super(key: key); + + @override + State createState() => UpdatePresentIllnessState(); +} + +class UpdatePresentIllnessState extends State { + bool isPatientSelected = true; + bool isFamilySelected = false; + bool isOtherSelected = false; + + final TextEditingController familyController = TextEditingController(); + final TextEditingController otherController = TextEditingController(); + final TextEditingController patientController = TextEditingController(); + @override + void initState() { + + super.initState(); + } + + @override + Widget build(BuildContext context) { + + return BaseView( + onModelReady: (model){ + WidgetsBinding.instance.addPostFrameCallback((_) { + getHopi(model); + }); + }, + builder: (_, model, w) => Column( + // key:UpdatePresentIllness.HopiKey, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 8, + ), + AppText( + TranslationBase.of(context).historyTakenFrom, + fontSize: 14, + fontWeight: FontWeight.w600, + textAlign: TextAlign.start, + color: Colors.black, + ), + + ListTileTheme( + horizontalTitleGap: 0, + child: CheckboxListTile( + value: this.isPatientSelected, + activeColor: Color(0xFFD02127), + checkColor: Colors.white, + controlAffinity: ListTileControlAffinity.leading, + side: MaterialStateBorderSide.resolveWith( + (Set states) { + if (states.contains(MaterialState.selected)) { + return const BorderSide(color: Color(0xFFD02127)); + } + return const BorderSide(color: Color(0xFFE6E6E6)); + }, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16)), + onChanged: (bool? value) { + setState(() { + isPatientSelected = value ?? false; + }); + }, + title: AppText( + TranslationBase.of(context).patient, + color: Color(0XFF575757), + fontSize: 14, + fontWeight: FontWeight.w400, + ), + contentPadding: EdgeInsets.zero), + ), + + ListTileTheme( + horizontalTitleGap: 0, + child: CheckboxListTile( + value: isFamilySelected, + activeColor: Color(0xFFD02127), + checkColor: Colors.white, + controlAffinity: ListTileControlAffinity.leading, + side: MaterialStateBorderSide.resolveWith( + (Set states) { + if (states.contains(MaterialState.selected)) { + return const BorderSide(color: Color(0xFFD02127)); + } + return const BorderSide(color: Color(0xFFE6E6E6)); + }, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16)), + onChanged: (bool? value) { + setState(() { + isFamilySelected = value ?? false; + }); + }, + title: AppText( + TranslationBase.of(context).familySpecify, + color: Color(0XFF575757), + fontSize: 14, + fontWeight: FontWeight.w400, + ), + contentPadding: EdgeInsets.zero), + ), + Visibility( + visible: isFamilySelected, + child: Column(children: [ + AppTextFieldCustom( + hintText: TranslationBase.of(context).remarks, + controller: familyController, + inputType: TextInputType.multiline, + maxLines: 25, + minLines: 3, + hasBorder: true, + isTextFieldHasSuffix: true, + onClick: () {}, + onChanged: (value) {}, + onFieldSubmitted: () {}, + + suffixIcon: IconButton(icon:Icon(Icons.save_as_outlined, color: Colors.red, size: 25,), onPressed: (){ + saveHopi(model); + },), + ), + ])), + + ListTileTheme( + horizontalTitleGap: 0, + child: CheckboxListTile( + value: isOtherSelected, + activeColor: Color(0xFFD02127), + checkColor: Colors.white, + controlAffinity: ListTileControlAffinity.leading, + side: MaterialStateBorderSide.resolveWith( + (Set states) { + if (states.contains(MaterialState.selected)) { + return const BorderSide(color: Color(0xFFD02127)); + } + return const BorderSide(color: Color(0xFFE6E6E6)); + }, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16)), + onChanged: (bool? value) { + setState(() { + isOtherSelected = value ?? false; + }); + }, + title: AppText( + TranslationBase.of(context).otherSpecify, + color: Color(0XFF575757), + fontSize: 14, + fontWeight: FontWeight.w400, + ), + contentPadding: EdgeInsets.zero), + ), + Visibility( + visible: isOtherSelected, + child: Column( + children: [ + AppTextFieldCustom( + hintText: TranslationBase.of(context).remarks, + controller: otherController, + inputType: TextInputType.multiline, + maxLines: 25, + minLines: 3, + hasBorder: true, + isTextFieldHasSuffix: true, + onClick: () {}, + onChanged: (value) {}, + onFieldSubmitted: () {}, suffixIcon: IconButton(icon:Icon(Icons.save_as_outlined, color: Colors.red, size: 25,), onPressed: (){ + saveHopi(model); + },), + ), + ], + ), + ), + + Divider(), + SizedBox( + height: 8, + ), + AppText( + TranslationBase.of(context).historyOfIllness, + fontSize: 14, + fontWeight: FontWeight.w600, + textAlign: TextAlign.start, + color: Colors.black, + ), + SizedBox( + height: 8, + ), + AppTextFieldCustom( + isTextFieldHasSuffix: true, + hintText: TranslationBase.of(context).remarks, + controller: patientController, + inputType: TextInputType.multiline, + maxLines: 25, + minLines: 3, + hasBorder: true, + onClick: () {}, + onChanged: (value) { + print("On Field Changed.."); + }, + onFieldSubmitted: () { + print("---Submit....."); + }, + suffixIcon: IconButton(icon:Icon(Icons.save_as_outlined, color: Colors.red, size: 25,), onPressed: (){ + saveHopi(model); + },), + ), + SizedBox( + height: 8, + ), + + // AppText( + // 'Last saved: 22-10-2024 08:07 am [3 hours ago]', + // fontSize: 10, + // fontWeight: FontWeight.normal, + // textAlign: TextAlign.start, + // color: Color(0XFF575757), + // ), + ], + ), + + ); + } + saveHopi(SOAPViewModel model) async{ + GifLoaderDialogUtils.showMyDialog(context); + if(patientController.text.isEmpty) { + DrAppToastMsg.showErrorToast("Please Enter Remarks"); + return; + } + Map request = { + "hpi": patientController.text, + "isHpiTakenPatient": isPatientSelected, + "isHpiTakenFamily": isFamilySelected, + "isHpiTakenOther": isOtherSelected, + "hpiTakenOtherText": otherController.text, + "hpiTakenFamilyText": familyController.text, + }; + bool result = await model!.saveHopi(request, widget.patientInfo!); + if(result){ + getHopi(model); + } + + GifLoaderDialogUtils.hideDialog(context); + } + getHopi(SOAPViewModel model) async{ + await model!.getHopi(widget.patientInfo!); + setData(model); + } + setData(SOAPViewModel model){ + if(model.getHopiDetails.isNotEmpty) { + patientController.text = model.getHopiDetails[0].hpi!; + familyController.text = model.getHopiDetails[0].hpiTakenFamilyText!; + otherController.text = model.getHopiDetails[0].hpiTakenOtherText!; + isOtherSelected = model.getHopiDetails[0].isHpiTakenOther!; + isFamilySelected = model.getHopiDetails[0].isHpiTakenFamily!; + isPatientSelected = model.getHopiDetails[0].isHpiTakenPatient!; + } + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/subjective/update_subjective_page_vida_plus.dart b/lib/screens/patients/profile/soap_update_vida_plus/subjective/update_subjective_page_vida_plus.dart new file mode 100644 index 00000000..f496ec09 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/subjective/update_subjective_page_vida_plus.dart @@ -0,0 +1,388 @@ +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/enum/master_lookup_key.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/master_key_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_allergy.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_history.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/SOAP_step_header.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/shared_soap_widgets/expandable_SOAP_widget.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/soap_utils.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update/subjective/subjective_call_back.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/medication/update_medication_widget.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/present_illness/update_present_illness.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/utils/utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/text_fields/app-textfield-custom.dart'; +import 'package:flutter/material.dart'; + +import '../../../../../core/model/SOAP/allergy/get_patient_allergies_list_vida_plus.dart'; +import 'allergies/update_allergies_widget.dart'; +import 'chief_complaint/chief_complaints.dart'; + + +class UpdateSubjectivePageVidaPlus extends StatefulWidget { + final Function changePageViewIndex; + final Function changeLoadingState; + final PatiantInformtion patientInfo; + final int currentIndex; + + UpdateSubjectivePageVidaPlus( + {Key? key, required this.changePageViewIndex, required this.patientInfo, required this.changeLoadingState, required this.currentIndex}); + + @override + _UpdateSubjectivePageVidaPlusState createState() => + _UpdateSubjectivePageVidaPlusState(); +} + +class _UpdateSubjectivePageVidaPlusState + extends State + implements SubjectiveCallBack { + bool isChiefExpand = false; + bool isHistoryExpand = false; + bool isAllergiesExpand = false; + bool isMedicationExpand =false; + TextEditingController illnessController = TextEditingController(); + TextEditingController complaintsController = TextEditingController(); + TextEditingController medicationController = TextEditingController(); + + final formKey = GlobalKey(); + List myAllergiesList = []; + List myHistoryList = []; + + // getHistory(SOAPViewModel model) async { + // widget.changeLoadingState(true); + // if (model.patientHistoryList.isNotEmpty) { + // model.patientHistoryList.forEach((element) { + // if (element.historyType == + // MasterKeysService.HistoryFamily.getMasterKeyService()) { + // MasterKeyModel? history = model.getOneMasterKey( + // masterKeys: MasterKeysService.HistoryFamily, + // id: element.historyId, + // ); + // if (history != null) { + // MySelectedHistory mySelectedHistory = SoapUtils + // .generateMySelectedHistory(history: history, + // isChecked: element.isChecked, + // remark: element.remarks, + // isLocal: false); + // myHistoryList.add(mySelectedHistory); + // } + // } + // if (element.historyType == + // MasterKeysService.HistoryMedical.getMasterKeyService()) { + // MasterKeyModel? history = model.getOneMasterKey( + // masterKeys: MasterKeysService.HistoryMedical, + // id: element.historyId, + // ); + // if (history != null) { + // MySelectedHistory mySelectedHistory = SoapUtils + // .generateMySelectedHistory(history: history, + // isChecked: element.isChecked, + // remark: element.remarks, + // isLocal: false); + // myHistoryList.add(mySelectedHistory); + // } + // } + // if (element.historyType == + // MasterKeysService.HistorySports.getMasterKeyService()) { + // MasterKeyModel? history = model.getOneMasterKey( + // masterKeys: MasterKeysService.HistorySports, + // id: element.historyId, + // ); + // if (history != null) { + // MySelectedHistory mySelectedHistory = SoapUtils + // .generateMySelectedHistory(history: history, + // isChecked: element.isChecked, + // remark: element.remarks, + // isLocal: false); + // myHistoryList.add(mySelectedHistory); + // } + // } + // if (element.historyType == + // MasterKeysService.HistorySurgical.getMasterKeyService()) { + // MasterKeyModel? history = model.getOneMasterKey( + // masterKeys: MasterKeysService.HistorySurgical, + // id: element.historyId, + // ); + // if (history != null) { + // MySelectedHistory mySelectedHistory = SoapUtils + // .generateMySelectedHistory(history: history, + // isChecked: element.isChecked, + // remark: element.remarks, + // isLocal: false); + // myHistoryList.add(mySelectedHistory); + // } + // } + // }); + // } + // } + + getAllergies(SOAPViewModel model) async { + await model.getAllergiesVidaPlus(widget.patientInfo); + myAllergiesList = model.patientAllergiesVidaPlus; + // if (model.patientAllergiesList.isNotEmpty) { + // model.patientAllergiesList.forEach((element) { + // MasterKeyModel? selectedAllergy = model.getOneMasterKey(masterKeys: MasterKeysService.Allergies, id: element.allergyDiseaseId, typeId: element.allergyDiseaseType); + // MasterKeyModel? selectedAllergySeverity; + // if (element.severity == 0) { + // selectedAllergySeverity = MasterKeyModel(id: 0, typeId: MasterKeysService.AllergySeverity.getMasterKeyService(), nameAr: '', nameEn: ''); + // } else { + // selectedAllergySeverity = model.getOneMasterKey( + // masterKeys: MasterKeysService.AllergySeverity, + // id: element.severity, + // )!; + // } + // + // MySelectedAllergy mySelectedAllergy = SoapUtils.generateMySelectedAllergy( + // allergy: selectedAllergy, isChecked: element.isChecked, createdBy: element.createdBy!, remark: element.remarks, isLocal: false, allergySeverity: selectedAllergySeverity); + // + // if (selectedAllergy != null && selectedAllergySeverity != null) myAllergiesList.add(mySelectedAllergy); + // }); + // } + } + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) async { + WidgetsBinding.instance.addPostFrameCallback((_) async { + myAllergiesList.clear(); + myHistoryList.clear(); + model.setSubjectiveCallBack(this); + // await model.onUpdateSubjectStepStart(widget.patientInfo); + + if (model.patientChiefComplaintList.isNotEmpty) { + isChiefExpand = true; + complaintsController.text = Utils.parseHtmlString( + model.patientChiefComplaintList[0].chiefComplaint!); + illnessController.text = model.patientChiefComplaintList[0].hopi!; + medicationController.text = + model.patientChiefComplaintList[0].currentMedication != null + ? !(model.patientChiefComplaintList[0].currentMedication!) + .isNotEmpty + ? model.patientChiefComplaintList[0].currentMedication! + + '\n \n' + : model.patientChiefComplaintList[0].currentMedication! + : ""; + } + if (widget.patientInfo.admissionNo == null) { + // await getHistory(model); + + await getAllergies(model); + } + + widget.changeLoadingState(false); + }); + }, + builder: (_, model, w) => + AppScaffold( + isShowAppBar: false, + backgroundColor: Theme + .of(context) + .scaffoldBackgroundColor, + body: SingleChildScrollView( + physics: ScrollPhysics(), + child: Center( + child: FractionallySizedBox( + widthFactor: 0.9, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SOAPStepHeader( + currentIndex: widget.currentIndex, + changePageViewIndex: widget.changePageViewIndex, + patientInfo: widget.patientInfo, + ), + ExpandableSOAPWidget( + headerTitle: TranslationBase + .of(context) + .chiefComplaints, + onTap: () { + setState(() { + isChiefExpand = !isChiefExpand; + }); + }, + child: UpdateChiefComplaints( + complaints: [], + patientInfo: widget.patientInfo, + ), + isExpanded: isChiefExpand, + ), + SizedBox( + height: SizeConfig.heightMultiplier! * + (SizeConfig.isHeightVeryShort ? 4 : 2), + ), + if (widget.patientInfo.admissionNo == null) + ExpandableSOAPWidget( + headerTitle: TranslationBase + .of(context) + .historyOfIllness, + isRequired: false, + onTap: () { + setState(() { + isHistoryExpand = !isHistoryExpand; + }); + }, + child: Column( + children: [UpdatePresentIllness(widget.patientInfo)], + ), + isExpanded: isHistoryExpand, + ), + SizedBox( + height: SizeConfig.heightMultiplier! * + (SizeConfig.isHeightVeryShort ? 4 : 2), + ), + if (widget.patientInfo.admissionNo == null) + ExpandableSOAPWidget( + headerTitle: TranslationBase + .of(context) + .allergiesSoap, + isRequired: false, + onTap: () { + setState(() { + isAllergiesExpand = !isAllergiesExpand; + }); + }, + child: Column( + children: [ + UpdateAllergiesWidgetVidaPlus( + myAllergiesList: myAllergiesList, + patientInfo: widget.patientInfo + ), + SizedBox( + height: 30, + ), + ], + ), + isExpanded: isAllergiesExpand, + ), + SizedBox( + height: SizeConfig.heightMultiplier! * + (SizeConfig.isHeightVeryShort ? 4 : 2), + ), + ExpandableSOAPWidget( + headerTitle: TranslationBase + .of(context) + .currentMedications, + onTap: () { + setState(() { + isMedicationExpand = !isMedicationExpand; + }); + }, + child: Column(children: [ + SizedBox( + height: SizeConfig.heightMultiplier! * + (SizeConfig.isHeightVeryShort ? 4 : 2), + ), + UpdateMedicationWidget( + patientInfo: widget.patientInfo, + ), + SizedBox( + height: 10, + ), + + ],), + isExpanded: isMedicationExpand, + ), + SizedBox( + height: SizeConfig.heightMultiplier! * + (SizeConfig.isHeightVeryShort ? 20 : 10), + ), + ], + ), + ), + ), + ), + ), + ); + } + + addSubjectiveInfo({required SOAPViewModel model, required List< + MySelectedAllergy> myAllergiesList, required List< + MySelectedHistory> myHistoryList}) async { + if (FocusScope + .of(context) + .hasFocus) FocusScope.of(context).unfocus(); + widget.changeLoadingState(true); + formKey.currentState!.save(); + formKey.currentState!.validate(); + + model.complaintsControllerError = ''; + model.medicationControllerError = ''; + model.illnessControllerError = ''; + if (complaintsController.text.isNotEmpty && + illnessController.text.isNotEmpty) { + await model.postSubjectServices( + patientInfo: widget.patientInfo, + complaintsText: complaintsController.text, + medicationText: medicationController.text, + illnessText: illnessController.text, + myHistoryList: myHistoryList, + myAllergiesList: myAllergiesList, + ); + + widget.changeLoadingState(true); + + widget.changePageViewIndex(1); + } else { + setState(() { + if (complaintsController.text.isEmpty) { + model.complaintsControllerError = TranslationBase + .of(context) + .emptyMessage; + } + + if (illnessController.text.isEmpty) { + model.illnessControllerError = TranslationBase + .of(context) + .emptyMessage; + } + + if (medicationController.text.isEmpty) { + model.medicationControllerError = TranslationBase + .of(context) + .emptyMessage; + } + }); + + widget.changeLoadingState(false); + Utils.showErrorToast(TranslationBase + .of(context) + .chiefComplaintErrorMsg); + } + } + + + Function nextFunction(model) { + //need to be implemented .. + return (){}; + } + +} + +// +// UpdateMedicationWidget( +// medicationController: medicationController, +// ), +// SizedBox( +// height: 10, +// ), +// AppTextFieldCustom( +// hintText: TranslationBase.of(context).currentMedications, +// controller: medicationController, +// maxLines: 25, +// minLines: 7, +// hasBorder: true, +// inputType: TextInputType.multiline, +// // validationError: medicationControllerError != '' ? medicationControllerError : "", +// onClick: () {}, +// onChanged: (value) {}, +// onFieldSubmitted: () {}, +// ), +// SizedBox( +// height: 10, +// ) \ No newline at end of file diff --git a/lib/screens/patients/profile/soap_update_vida_plus/update_soap_index_vida_plus.dart b/lib/screens/patients/profile/soap_update_vida_plus/update_soap_index_vida_plus.dart new file mode 100644 index 00000000..315021a7 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/update_soap_index_vida_plus.dart @@ -0,0 +1,308 @@ +import 'package:doctor_app_flutter/config/config.dart'; +import 'package:doctor_app_flutter/config/size_config.dart'; +import 'package:doctor_app_flutter/core/enum/view_state.dart'; +import 'package:doctor_app_flutter/core/viewModel/SOAP_view_model.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_allergy.dart'; +import 'package:doctor_app_flutter/core/model/SOAP/selected_items/my_selected_history.dart'; +import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart'; +import 'package:doctor_app_flutter/screens/base/base_view.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/objective/update_objective_page_vida_plus.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/plan/update_plan_page_vida_plus.dart'; +import 'package:doctor_app_flutter/screens/patients/profile/soap_update_vida_plus/subjective/update_subjective_page_vida_plus.dart'; +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/patients/profile/app_bar/patient-profile-app-bar.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart'; +import 'package:doctor_app_flutter/widgets/shared/buttons/app_buttons_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; + +import 'assessment/update_assessment_page.dart'; + +class UpdateSoapIndexVidaPlus extends StatefulWidget { + final bool isUpdate; + + const UpdateSoapIndexVidaPlus({Key? key, this.isUpdate = false}) + : super(key: key); + + @override + _UpdateSoapIndexVidaPlusState createState() => + _UpdateSoapIndexVidaPlusState(); +} + +class _UpdateSoapIndexVidaPlusState extends State + with TickerProviderStateMixin { + PageController? _controller; + int _currentIndex = 0; + List myAllergiesList = []; + List myHistoryList = []; + + changePageViewIndex(pageIndex, {isChangeState = true}) { + if (pageIndex != _currentIndex && isChangeState) changeLoadingState(true); + _controller!.jumpToPage(pageIndex); + setState(() { + _currentIndex = pageIndex; + }); + } + + bool _isLoading = true; + + @override + void initState() { + _controller = new PageController(); + + super.initState(); + } + + void changeLoadingState(isLoading) { + setState(() { + _isLoading = isLoading; + }); + } + + void changeStateFun() { + setState(() {}); + } + + @override + Widget build(BuildContext context) { + final routeArgs = ModalRoute.of(context)!.settings.arguments as Map; + PatiantInformtion patient = routeArgs['patient']; + return BaseView( + builder: (_, model, w) => AppScaffold( + isLoading: _isLoading, + isShowAppBar: true, + appBar: PatientProfileAppBar(patient), + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + decoration: BoxDecoration( + boxShadow: [], + color: Theme.of(context).scaffoldBackgroundColor), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + color: Theme.of(context).scaffoldBackgroundColor, + height: MediaQuery.of(context).size.height * 0.73, + child: PageView( + physics: NeverScrollableScrollPhysics(), + controller: _controller, + onPageChanged: (index) { + setState(() { + _currentIndex = index; + }); + }, + scrollDirection: Axis.horizontal, + children: [ + UpdateSubjectivePageVidaPlus( + changePageViewIndex: changePageViewIndex, + currentIndex: _currentIndex, + patientInfo: patient, + changeLoadingState: changeLoadingState), + UpdateObjectivePageVidaPlus( + changePageViewIndex: changePageViewIndex, + currentIndex: _currentIndex, + patientInfo: patient, + changeLoadingState: changeLoadingState), + UpdateAssessmentPage( + changePageViewIndex: changePageViewIndex, + currentIndex: _currentIndex, + patientInfo: patient, + changeLoadingState: changeLoadingState, + ), + UpdatePlanPageVidaPlus( + changePageViewIndex: changePageViewIndex, + currentIndex: _currentIndex, + patientInfo: patient, + changeLoadingState: changeLoadingState, + sOAPViewModel: model, + changeStateFun: changeStateFun, + ), + + ], + ), + ) + ], + ), + ), + ], + ), + ), + bottomSheet: _isLoading + ? Container( + height: 0, + ) + : Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(0.0), + ), + border: Border.all(color: HexColor('#707070'), width: 0), + ), + height: SizeConfig.heightMultiplier! * + (SizeConfig.isHeightVeryShort ? 12 : 10), + width: double.infinity, + child: Column( + children: [ + SizedBox( + height: 10, + ), + Container( + child: FractionallySizedBox( + widthFactor: .9, + child: getBottomSheet(model, patient)), + ), + SizedBox( + height: 5, + ), + ], + ), + ), + ), + ); + } + + Widget getBottomSheet(SOAPViewModel model, PatiantInformtion patient) { + switch (_currentIndex) { + case 0: + { + return Center( + child: AppButton( + title: TranslationBase.of(context).next, + fontWeight: FontWeight.w600, + disabled: !model.isSubjectiveAssesmentCompleted(), + color: Colors.red[700]!, + onPressed: () async { + changePageViewIndex(1); + }, + ), + ); + } + break; + case 1: + { + return Center( + child: Row( + children: [ + Expanded( + child: AppButton( + title: TranslationBase.of(context).previous, + color: Colors.grey[300]!, + // height: SizeConfig.heightMultiplier! * + // (SizeConfig.isHeightVeryShort ? 8 : 6), + // padding: 10, + fontColor: Colors.black, + fontWeight: FontWeight.w600, + onPressed: () { + changePageViewIndex(0); + }, + ), + ), + SizedBox( + width: 5, + ), + Expanded( + child: AppButton( + title: patient.admissionNo != null && + patient.admissionNo!.isNotEmpty && + !model.isAddExamInProgress + ? TranslationBase.of(context).finish + : TranslationBase.of(context).next, + fontWeight: FontWeight.w600, + color: Colors.red[700]!, + // height: SizeConfig.heightMultiplier! * + // (SizeConfig.isHeightVeryShort ? 8 : 6), + // padding: 10, + disabled: model.state == ViewState.BusyLocal || !model.isPhysicalExaminationAdded(), + onPressed: () async { + changePageViewIndex(2); + // await model.nextOnObjectivePage(model); + }, + ), + ), + ], + ), + ); + } + break; + case 2: + { + return Center( + child: Row( + children: [ + Expanded( + child: AppButton( + title: TranslationBase.of(context).previous, + color: Colors.grey[300]!, + fontColor: Colors.black, + fontWeight: FontWeight.w600, + disabled: model.state == ViewState.BusyLocal, + onPressed: () async { + changePageViewIndex(1); + }, + ), + ), + SizedBox( + width: 5, + ), + Expanded( + child: AppButton( + title: TranslationBase.of(context).next, + fontWeight: FontWeight.w600, + color: Colors.red[700]!, + disabled: model.state == ViewState.BusyLocal || !model.isDiagnosticsAdded(), + onPressed: () async { + changePageViewIndex(3); + }, + ), + ), + ], + ), + ); + } + break; + case 3: + { + return Center( + child: Row( + children: [ + Expanded( + child: AppButton( + title: TranslationBase.of(context).previous, + color: Colors.grey[300]!, + fontColor: Colors.black, + fontWeight: FontWeight.w600, + disabled: model.state == ViewState.BusyLocal, + onPressed: () async { + changePageViewIndex(2); + }, + ), + ), + SizedBox( + width: 5, + ), + Expanded( + child: AppButton( + title: TranslationBase.of(context).submit, + fontWeight: FontWeight.w600, + color: AppGlobal.appGreenColor, + disabled: !model.isProgressAdded(), + onPressed: () async { + Navigator.pop(context); + }, + ), + ), + ], + ), + ); + } + break; + } + return SizedBox(); + } +} diff --git a/lib/screens/patients/profile/soap_update_vida_plus/widgets/SoapDetailItem.dart b/lib/screens/patients/profile/soap_update_vida_plus/widgets/SoapDetailItem.dart new file mode 100644 index 00000000..26b2d8f2 --- /dev/null +++ b/lib/screens/patients/profile/soap_update_vida_plus/widgets/SoapDetailItem.dart @@ -0,0 +1,233 @@ +import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; +import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; + +typedef OnSoapDetailActionClicked = Function(SoapDetailItemActions); + +class SoapDetailItem extends StatelessWidget { + final String title; + final String condition; + final String status; + final String remarks; + final String? type; + final bool showActions; + final OnSoapDetailActionClicked onSoapDetailActionClicked; + + const SoapDetailItem( + {super.key, + required this.title, + required this.condition, + required this.remarks, + required this.onSoapDetailActionClicked, + required this.status, + this.type, + this.showActions = true}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppText( + title, + color: Color(0XFF2B353E), + fontSize: 12, + fontWeight: FontWeight.bold, + ), + Row( + children: [ + AppText( + "${TranslationBase.of(context).condition}:", + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + SizedBox( + width: 4, + ), + AppText( + condition, + color: Color(0xffD02127), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ], + ), + Visibility( + visible: type?.isNotEmpty == true, + child: Row( + children: [ + AppText( + "${TranslationBase.of(context).diagnoseType}:", + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + SizedBox( + width: 4, + ), + AppText( + type ?? '', + color: Color(0xff359846), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ], + ), + ), + Visibility( + visible: remarks.isNotEmpty, + child: Column( + children: [ + SizedBox( + height: 8, + ), + AppText( + remarks, + color: Color(0XFF2B353E), + fontSize: 10, + fontWeight: FontWeight.w400, + ), + ], + )) + ], + ), + ), + Status(status: status) + ], + ), + SizedBox( + height: 16, + ), + Visibility( + visible: showActions, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => + onSoapDetailActionClicked(SoapDetailItemActions.EDIT), + child: SoapDetailItemActionsView( + icon: 'assets/images/svgs/edit.svg', + fontColor: Color(0XFF2B353E), + text: TranslationBase.of(context).edit, + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => + onSoapDetailActionClicked(SoapDetailItemActions.RESOLVE), + child: SoapDetailItemActionsView( + icon: 'assets/images/svgs/resolve.svg', + fontColor: Color(0XFF359846), + text: TranslationBase.of(context).resolve, + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => + onSoapDetailActionClicked(SoapDetailItemActions.AUDIT), + child: SoapDetailItemActionsView( + icon: 'assets/images/svgs/audit.svg', + fontColor: Color(0XFF2B353E), + text: TranslationBase.of(context).audit, + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => + onSoapDetailActionClicked(SoapDetailItemActions.REMOVE), + child: SoapDetailItemActionsView( + icon: 'assets/images/svgs/delete.svg', + fontColor: Color(0XFFD02127), + text: TranslationBase.of(context).delete, + ), + ), + ], + ), + ) + ], + ), + ); + } +} + +class SoapDetailItemActionsView extends StatelessWidget { + final String icon; + final String text; + final Color fontColor; + + const SoapDetailItemActionsView( + {super.key, + required this.icon, + required this.text, + required this.fontColor}); + + @override + Widget build(BuildContext context) => Row( + children: [ + SvgPicture.asset(icon), + SizedBox( + width: 8, + ), + AppText( + text, + color: fontColor, + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ], + ); +} + +class Status extends StatelessWidget { + final String status; + + const Status({super.key, required this.status}); + + @override + Widget build(BuildContext context) { + return Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(3), + ), + // color: Color(0xFF359846), + color: (status.toLowerCase() == + TranslationBase.of(context).active.toLowerCase() || + status.toLowerCase() == + TranslationBase.of(context).stable.toLowerCase()) + ? Color(0xFFD8E8DB) + : (status.toLowerCase() == + TranslationBase.of(context).resolved.toLowerCase()) + ? Colors.lightBlue + : Color(0x98d02127), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + child: AppText( + status, + color: (status.toLowerCase() == + TranslationBase.of(context).active.toLowerCase() || + status.toLowerCase() == + TranslationBase.of(context).stable.toLowerCase()) + ? Color(0xFF359846) + : Colors.white, + fontSize: 8, + fontWeight: FontWeight.w600, + ), + )); + } +} + +enum SoapDetailItemActions { EDIT, RESOLVE, AUDIT, REMOVE, CHANGE_STATUS } diff --git a/lib/screens/patients/profile/soap_update_vida_plus/widgets/previous_data_item.dart b/lib/screens/patients/profile/soap_update_vida_plus/widgets/previous_data_item.dart new file mode 100644 index 00000000..e69de29b diff --git a/lib/screens/patients/register_patient/VerifyMethodPage.dart b/lib/screens/patients/register_patient/VerifyMethodPage.dart index 45359dea..9e9659cd 100644 --- a/lib/screens/patients/register_patient/VerifyMethodPage.dart +++ b/lib/screens/patients/register_patient/VerifyMethodPage.dart @@ -434,7 +434,7 @@ class _ActivationPageState extends State { ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10.0)), - borderSide: BorderSide(color: Theme.of(context).errorColor), + borderSide: BorderSide(color: Colors.red), ), ); } diff --git a/lib/screens/prescription/add_prescription/prescription_form_widget.dart b/lib/screens/prescription/add_prescription/prescription_form_widget.dart index 53616188..7aefa133 100644 --- a/lib/screens/prescription/add_prescription/prescription_form_widget.dart +++ b/lib/screens/prescription/add_prescription/prescription_form_widget.dart @@ -252,7 +252,7 @@ getIcdCodeData() async{ hintText: TranslationBase.of(context).frequency, elementError: frequencyError, // element: frequency, - element: widget.medicineViewModel.itemMedicineListRoute.length == 1 ? frequency = widget.medicineViewModel.itemMedicineListRoute[0] : frequency, + element: widget.medicineViewModel.medicationFrequencyList.length == 1 ? frequency = widget.medicineViewModel.medicationFrequencyList[0] : frequency, elementList: widget.medicineViewModel.itemMedicineList, keyId: 'parameterCode', keyName: 'description', diff --git a/lib/screens/prescription/new_prescriptions_page.dart b/lib/screens/prescription/new_prescriptions_page.dart index efd6f5fe..c69d50f6 100644 --- a/lib/screens/prescription/new_prescriptions_page.dart +++ b/lib/screens/prescription/new_prescriptions_page.dart @@ -27,9 +27,9 @@ class NewPrescriptionsPage extends StatelessWidget { bool isFromLiveCare = routeArgs['isFromLiveCare']; return BaseView( onModelReady: (model) async { - await model.getPrescriptionListNew( - mrn: patient.patientMRN, appNo: patient.appointmentNo??0); - await model.isPrincipalCovered(patient: patient); + await model.getPrescriptionListNew(mrn: patient.patientMRN, appNo: patient.appointmentNo == null ? 0 : int.parse(patient.appointmentNo.toString())); + await model.isPrincipalCovered(patient: patient); + }, builder: (_, model, w) => AppScaffold( baseViewModel: model, @@ -48,8 +48,6 @@ class NewPrescriptionsPage extends StatelessWidget { SizedBox( height: 12, ), - - Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -62,11 +60,18 @@ class NewPrescriptionsPage extends StatelessWidget { ], ), ), - !model.isPrincipalCovered_ ? Center(child: AppText(TranslationBase.of(context).principalCoveredOrNot,color: Colors.red, textAlign: TextAlign.center, )) :SizedBox(), - SizedBox(height: 20,), - if ((patient.patientStatusType != null && - patient.patientStatusType == 43) || - (isFromLiveCare && patient.appointmentNo != null)) + !model.isPrincipalCovered_ + ? Center( + child: AppText( + TranslationBase.of(context).principalCoveredOrNot, + color: Colors.red, + textAlign: TextAlign.center, + )) + : SizedBox(), + SizedBox( + height: 20, + ), + if ((patient.patientStatusType != null && patient.patientStatusType == 43) || (isFromLiveCare && patient.appointmentNo != null)) AddNewOrder( onTap: () { Navigator.push( diff --git a/lib/screens/procedures/procedure_screen.dart b/lib/screens/procedures/procedure_screen.dart index 447de6f9..2cf35779 100644 --- a/lib/screens/procedures/procedure_screen.dart +++ b/lib/screens/procedures/procedure_screen.dart @@ -39,16 +39,10 @@ class ProcedureScreen extends StatelessWidget { bool isInpatient = routeArgs['isInpatient']; return BaseView( onModelReady: (model) { - model.getProcedure( - mrn: patient.patientId, - patientType: patientType, - appointmentNo: patient.appointmentNo); + model.getProcedure(mrn: patient.patientId, patientType: patientType, appointmentNo: patient.appointmentNo); model.isPrincipalCovered(patient: patient); - }, - - builder: (BuildContext context, ProcedureViewModel model, Widget? child) => - AppScaffold( + builder: (BuildContext context, ProcedureViewModel model, Widget? child) => AppScaffold( isShowAppBar: true, backgroundColor: Colors.grey[100]!, baseViewModel: model, @@ -64,23 +58,16 @@ class ProcedureScreen extends StatelessWidget { SizedBox( height: 12, ), - if ((model.procedureList.length == 0 && - patient.patientStatusType != 43) || - patient.patientStatusType != null && - patient.patientStatusType == 43) + if ((model.procedureList.length == 0 && patient.patientStatusType != 43) || patient.patientStatusType != null && patient.patientStatusType == 43) ServiceTitle( title: TranslationBase.of(context).orderTestOr, subTitle: TranslationBase.of(context).procedure, ), - if ((patient.patientStatusType != null && - patient.patientStatusType == 43) || - (isFromLiveCare && patient.appointmentNo != null)) + if ((patient.patientStatusType != null && patient.patientStatusType == 43) || (isFromLiveCare && patient.appointmentNo != null)) AddNewOrder( onTap: () async { GifLoaderDialogUtils.showMyDialog(context); - await model.getProcedureTemplate( - categoryID: ProcedureType.PROCEDURE.getCategoryId(), - isLocalBusy: true); + await model.getProcedureTemplate(categoryID: ProcedureType.PROCEDURE.getCategoryId(), isLocalBusy: true); GifLoaderDialogUtils.hideDialog(context); Navigator.push( @@ -96,9 +83,17 @@ class ProcedureScreen extends StatelessWidget { }, label: TranslationBase.of(context).addMoreProcedure, ), - - !model.isPrincipalCovered_ ? Center(child: AppText(TranslationBase.of(context).principalCoveredOrNot,color: Colors.red, textAlign: TextAlign.center, )) :SizedBox(), - SizedBox(height: 20,), + !model.isPrincipalCovered_ + ? Center( + child: AppText( + TranslationBase.of(context).principalCoveredOrNot, + color: Colors.red, + textAlign: TextAlign.center, + )) + : SizedBox(), + SizedBox( + height: 20, + ), if (model.procedureList.isNotEmpty) ListView.builder( scrollDirection: Axis.vertical, @@ -107,45 +102,28 @@ class ProcedureScreen extends StatelessWidget { physics: BouncingScrollPhysics(), itemBuilder: (BuildContext ctxt, int index) { return ProcedureCard( - categoryID: model - .procedureList[0].entityList![index].categoryID, + categoryID: model.procedureList[0].entityList![index].categoryID, entityList: model.procedureList[0].entityList![index], onTap: () { - if (model.procedureList[0].entityList![index] - .categoryID == - 2 || - model.procedureList[0].entityList![index] - .categoryID == - 4) + if (model.procedureList[0].entityList![index].categoryID == 2 || model.procedureList[0].entityList![index].categoryID == 4) updateProcedureForm( context, model: model, patient: patient, - remarks: model.procedureList[0] - .entityList![index].remarks!, - orderType: model.procedureList[0] - .entityList![index].orderType - .toString(), - orderNo: model.procedureList[0] - .entityList![index].orderNo!, - procedureName: model.procedureList[0] - .entityList![index].procedureName!, - categoreId: model.procedureList[0] - .entityList![index].categoryID - .toString(), - procedureId: model.procedureList[0] - .entityList![index].procedureId!, - limetNo: model.procedureList[0] - .entityList![index].lineItemNo!, + remarks: model.procedureList[0].entityList![index].remarks!, + orderType: model.procedureList[0].entityList![index].orderType.toString(), + orderNo: model.procedureList[0].entityList![index].orderNo!, + procedureName: model.procedureList[0].entityList![index].procedureName!, + categoreId: model.procedureList[0].entityList![index].categoryID.toString(), + procedureId: model.procedureList[0].entityList![index].procedureId!, + limetNo: model.procedureList[0].entityList![index].lineItemNo!, ); }, patient: patient, doctorID: model.doctorProfile?.doctorID, ); }), - if (model.state == ViewState.ErrorLocal || - (model.procedureList.isNotEmpty && - model.procedureList[0].entityList!.isEmpty)) + if (model.state == ViewState.ErrorLocal || (model.procedureList.isNotEmpty && model.procedureList[0].entityList!.isEmpty)) Center( child: ErrorMessage( error: TranslationBase.of(context).noDataAvailable, diff --git a/lib/screens/video_call_zoom/zoom_video_call.dart b/lib/screens/video_call_zoom/zoom_video_call.dart index 0887e122..747a3a91 100644 --- a/lib/screens/video_call_zoom/zoom_video_call.dart +++ b/lib/screens/video_call_zoom/zoom_video_call.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'package:doctor_app_flutter/screens/video_call_zoom/video_view.dart'; import 'package:events_emitter/events_emitter.dart'; import 'package:flutter/cupertino.dart'; diff --git a/lib/utils/exception_report.dart b/lib/utils/exception_report.dart new file mode 100644 index 00000000..2e039703 --- /dev/null +++ b/lib/utils/exception_report.dart @@ -0,0 +1,19 @@ +// import 'package:cloud_firestore/cloud_firestore.dart'; + +void postFailureResponse({ + required dynamic doctorId, + required String url, + required String request, + required String response, + required String exception, +}) async { + // Map data = { + // "url" : url, + // "request" : request, + // "response" : response, + // "exception" : exception + // }; + // final firestore = FirebaseFirestore.instance; + // final collectionRef = firestore.collection(doctorId.toString()); + // await collectionRef.doc(DateTime.now().toIso8601String()).set(data); +} \ No newline at end of file diff --git a/lib/utils/translations_delegate_base_utils.dart b/lib/utils/translations_delegate_base_utils.dart index e2579e3d..eba08a2a 100644 --- a/lib/utils/translations_delegate_base_utils.dart +++ b/lib/utils/translations_delegate_base_utils.dart @@ -13,11 +13,13 @@ class TranslationBase { return Localizations.of(context, TranslationBase)!; } - String get dashboardScreenToolbarTitle => localizedValues['dashboardScreenToolbarTitle']![locale.languageCode]!; + String get dashboardScreenToolbarTitle => + localizedValues['dashboardScreenToolbarTitle']![locale.languageCode]!; String get settings => localizedValues['settings']![locale.languageCode]!; - String get areYouSureYouWantTo => localizedValues['areYouSureYouWantTo']![locale.languageCode]!; + String get areYouSureYouWantTo => + localizedValues['areYouSureYouWantTo']![locale.languageCode]!; String get language => localizedValues['language']![locale.languageCode]!; @@ -35,39 +37,52 @@ class TranslationBase { String get mobileNo => localizedValues['mobileNo']![locale.languageCode]!; - String get replySuccessfully => localizedValues['replySuccessfully']![locale.languageCode]!; + String get replySuccessfully => + localizedValues['replySuccessfully']![locale.languageCode]!; - String get messagesScreenToolbarTitle => localizedValues['messagesScreenToolbarTitle']![locale.languageCode]!; + String get messagesScreenToolbarTitle => + localizedValues['messagesScreenToolbarTitle']![locale.languageCode]!; String get mySchedule => localizedValues['mySchedule']![locale.languageCode]!; - String get errorNoSchedule => localizedValues['errorNoSchedule']![locale.languageCode]!; + String get errorNoSchedule => + localizedValues['errorNoSchedule']![locale.languageCode]!; String get verify => localizedValues['verify']![locale.languageCode]!; - String get referralDoctor => localizedValues['referralDoctor']![locale.languageCode]!; + String get referralDoctor => + localizedValues['referralDoctor']![locale.languageCode]!; - String get referringClinic => localizedValues['referringClinic']![locale.languageCode]!; + String get referringClinic => + localizedValues['referringClinic']![locale.languageCode]!; String get frequency => localizedValues['frequency']![locale.languageCode]!; String get priority => localizedValues['priority']![locale.languageCode]!; - String get maxResponseTime => localizedValues['maxResponseTime']![locale.languageCode]!; + String get maxResponseTime => + localizedValues['maxResponseTime']![locale.languageCode]!; - String get clinicDetailsandRemarks => localizedValues['clinicDetailsandRemarks']![locale.languageCode]!; + String get clinicDetailsandRemarks => + localizedValues['clinicDetailsandRemarks']![locale.languageCode]!; - String get answerSuggestions => localizedValues['answerSuggestions']![locale.languageCode]!; + String get answerSuggestions => + localizedValues['answerSuggestions']![locale.languageCode]!; - String get outPatients => localizedValues['outPatients']![locale.languageCode]!; + String get outPatients => + localizedValues['outPatients']![locale.languageCode]!; - String get searchPatient => localizedValues['searchPatient']![locale.languageCode]!; + String get searchPatient => + localizedValues['searchPatient']![locale.languageCode]!; - String get searchPatientDashBoard => localizedValues['searchPatientDashBoard']![locale.languageCode]!; + String get searchPatientDashBoard => + localizedValues['searchPatientDashBoard']![locale.languageCode]!; - String get searchPatientName => localizedValues['searchPatient-name']![locale.languageCode]!; + String get searchPatientName => + localizedValues['searchPatient-name']![locale.languageCode]!; - String get searchAbout => localizedValues['searchAbout']![locale.languageCode]!; + String get searchAbout => + localizedValues['searchAbout']![locale.languageCode]!; String get patient => localizedValues['patient']![locale.languageCode]!; @@ -75,9 +90,11 @@ class TranslationBase { String get labResult => localizedValues['labResult']![locale.languageCode]!; - String get todayStatistics => localizedValues['todayStatistics']![locale.languageCode]!; + String get todayStatistics => + localizedValues['todayStatistics']![locale.languageCode]!; - String get familyMedicine => localizedValues['familyMedicine']![locale.languageCode]!; + String get familyMedicine => + localizedValues['familyMedicine']![locale.languageCode]!; String get arrived => localizedValues['arrived']![locale.languageCode]!; @@ -95,71 +112,92 @@ class TranslationBase { String get inPatient => localizedValues['inPatient']![locale.languageCode]!; - String get myInPatient => localizedValues['myInPatient']![locale.languageCode]!; + String get myInPatient => + localizedValues['myInPatient']![locale.languageCode]!; - String get myInPatientTitle => localizedValues['myInPatientTitle']![locale.languageCode]!; + String get myInPatientTitle => + localizedValues['myInPatientTitle']![locale.languageCode]!; - String get inPatientLabel => localizedValues['inPatientLabel']![locale.languageCode]!; + String get inPatientLabel => + localizedValues['inPatientLabel']![locale.languageCode]!; - String get inPatientAll => localizedValues['inPatientAll']![locale.languageCode]!; + String get inPatientAll => + localizedValues['inPatientAll']![locale.languageCode]!; String get operations => localizedValues['operations']![locale.languageCode]!; - String get patientServices => localizedValues['patientServices']![locale.languageCode]!; + String get patientServices => + localizedValues['patientServices']![locale.languageCode]!; - String get searchMedicine => localizedValues['searchMedicine']![locale.languageCode]!; + String get searchMedicine => + localizedValues['searchMedicine']![locale.languageCode]!; - String get searchMedicineDashboard => localizedValues['searchMedicineDashboard']![locale.languageCode]!; + String get searchMedicineDashboard => + localizedValues['searchMedicineDashboard']![locale.languageCode]!; - String get myReferralPatient => localizedValues['myReferralPatient']![locale.languageCode]!; + String get myReferralPatient => + localizedValues['myReferralPatient']![locale.languageCode]!; - String get referPatient => localizedValues['referPatient']![locale.languageCode]!; + String get referPatient => + localizedValues['referPatient']![locale.languageCode]!; String get myReferral => localizedValues['myReferral']![locale.languageCode]!; - String get myReferredPatient => localizedValues['myReferredPatient']![locale.languageCode]!; + String get myReferredPatient => + localizedValues['myReferredPatient']![locale.languageCode]!; - String get referredPatient => localizedValues['referredPatient']![locale.languageCode]!; + String get referredPatient => + localizedValues['referredPatient']![locale.languageCode]!; String get referredOn => localizedValues['referredOn']![locale.languageCode]!; String get firstName => localizedValues['firstName']![locale.languageCode]!; - String get firstNameInAr => localizedValues['firstNameInAr']![locale.languageCode]!; + String get firstNameInAr => + localizedValues['firstNameInAr']![locale.languageCode]!; String get middleName => localizedValues['middleName']![locale.languageCode]!; - String get middleNameInAr => localizedValues['middleNameInAr']![locale.languageCode]!; + String get middleNameInAr => + localizedValues['middleNameInAr']![locale.languageCode]!; String get lastName => localizedValues['lastName']![locale.languageCode]!; - String get lastNameInAr => localizedValues['lastNameInAr']![locale.languageCode]!; + String get lastNameInAr => + localizedValues['lastNameInAr']![locale.languageCode]!; - String get phoneNumber => localizedValues['phoneNumber']![locale.languageCode]!; + String get phoneNumber => + localizedValues['phoneNumber']![locale.languageCode]!; String get patientID => localizedValues['patientID']![locale.languageCode]!; - String get patientFile => localizedValues['patientFile']![locale.languageCode]!; + String get patientFile => + localizedValues['patientFile']![locale.languageCode]!; String get search => localizedValues['search']![locale.languageCode]!; - String get onlyArrivedPatient => localizedValues['onlyArrivedPatient']![locale.languageCode]!; + String get onlyArrivedPatient => + localizedValues['onlyArrivedPatient']![locale.languageCode]!; - String get searchMedicineNameHere => localizedValues['searchMedicineNameHere']![locale.languageCode]!; + String get searchMedicineNameHere => + localizedValues['searchMedicineNameHere']![locale.languageCode]!; String get youCanFind => localizedValues['youCanFind']![locale.languageCode]!; - String get medicineSearchResult => localizedValues['medicineSearchResult']![locale.languageCode]!; + String get medicineSearchResult => + localizedValues['medicineSearchResult']![locale.languageCode]!; String get qr => localizedValues['qr']![locale.languageCode]!; String get reader => localizedValues['reader']![locale.languageCode]!; - String get startScanning => localizedValues['startScanning']![locale.languageCode]!; + String get startScanning => + localizedValues['startScanning']![locale.languageCode]!; String get scanQrCode => localizedValues['scanQrCode']![locale.languageCode]!; - String get scanERQrCode => localizedValues['scanERQrCode']![locale.languageCode]!; + String get scanERQrCode => + localizedValues['scanERQrCode']![locale.languageCode]!; String get scanQr => localizedValues['scanQr']![locale.languageCode]!; @@ -169,17 +207,21 @@ class TranslationBase { String get clinic => localizedValues['clinic']![locale.languageCode]!; - String get clinicSelect => localizedValues['clinicSelect']![locale.languageCode]!; + String get clinicSelect => + localizedValues['clinicSelect']![locale.languageCode]!; - String get doctorSelect => localizedValues['doctorSelect']![locale.languageCode]!; + String get doctorSelect => + localizedValues['doctorSelect']![locale.languageCode]!; String get hospital => localizedValues['hospital']![locale.languageCode]!; String get speciality => localizedValues['speciality']![locale.languageCode]!; - String get errorMessage => localizedValues['errorMessage']![locale.languageCode]!; + String get errorMessage => + localizedValues['errorMessage']![locale.languageCode]!; - String get patientProfile => localizedValues['patientProfile']![locale.languageCode]!; + String get patientProfile => + localizedValues['patientProfile']![locale.languageCode]!; String get vitalSign => localizedValues['vitalSign']![locale.languageCode]!; @@ -195,43 +237,56 @@ class TranslationBase { String get medicines => localizedValues['medicines']![locale.languageCode]!; - String get prescription => localizedValues['prescription']![locale.languageCode]!; + String get prescription => + localizedValues['prescription']![locale.languageCode]!; - String get insuranceApprovals => localizedValues['insuranceApprovals']![locale.languageCode]!; + String get insuranceApprovals => + localizedValues['insuranceApprovals']![locale.languageCode]!; String get insurance => localizedValues['insurance']![locale.languageCode]!; String get approvals => localizedValues['approvals']![locale.languageCode]!; - String get bodyMeasurements => localizedValues['bodyMeasurements']![locale.languageCode]!; + String get bodyMeasurements => + localizedValues['bodyMeasurements']![locale.languageCode]!; - String get temperature => localizedValues['temperature']![locale.languageCode]!; + String get temperature => + localizedValues['temperature']![locale.languageCode]!; String get pulse => localizedValues['pulse']![locale.languageCode]!; - String get respiration => localizedValues['respiration']![locale.languageCode]!; + String get respiration => + localizedValues['respiration']![locale.languageCode]!; - String get bloodPressure => localizedValues['bloodPressure']![locale.languageCode]!; + String get bloodPressure => + localizedValues['bloodPressure']![locale.languageCode]!; - String get oxygenation => localizedValues['oxygenation']![locale.languageCode]!; + String get oxygenation => + localizedValues['oxygenation']![locale.languageCode]!; String get painScale => localizedValues['painScale']![locale.languageCode]!; - String get errorNoVitalSign => localizedValues['errorNoVitalSign']![locale.languageCode]!; + String get errorNoVitalSign => + localizedValues['errorNoVitalSign']![locale.languageCode]!; String get labOrders => localizedValues['labOrders']![locale.languageCode]!; - String get errorNoLabOrders => localizedValues['errorNoLabOrders']![locale.languageCode]!; + String get errorNoLabOrders => + localizedValues['errorNoLabOrders']![locale.languageCode]!; - String get answerThePatient => localizedValues['answerThePatient']![locale.languageCode]!; + String get answerThePatient => + localizedValues['answerThePatient']![locale.languageCode]!; - String get pleaseEnterAnswer => localizedValues['pleaseEnterAnswer']![locale.languageCode]!; + String get pleaseEnterAnswer => + localizedValues['pleaseEnterAnswer']![locale.languageCode]!; String get replay => localizedValues['replay']![locale.languageCode]!; - String get progressNote => localizedValues['progressNote']![locale.languageCode]!; + String get progressNote => + localizedValues['progressNote']![locale.languageCode]!; - String get operationReports => localizedValues['operationReports']![locale.languageCode]!; + String get operationReports => + localizedValues['operationReports']![locale.languageCode]!; String get reports => localizedValues['reports']![locale.languageCode]!; @@ -243,15 +298,18 @@ class TranslationBase { String get searchNote => localizedValues['searchNote']![locale.languageCode]!; - String get errorNoProgressNote => localizedValues['errorNoProgressNote']![locale.languageCode]!; + String get errorNoProgressNote => + localizedValues['errorNoProgressNote']![locale.languageCode]!; String get invoiceNo => localizedValues['invoiceNo:']![locale.languageCode]!; String get orderNo => localizedValues['orderNo']![locale.languageCode]!; - String get generalResult => localizedValues['generalResult']![locale.languageCode]!; + String get generalResult => + localizedValues['generalResult']![locale.languageCode]!; - String get description => localizedValues['description']![locale.languageCode]!; + String get description => + localizedValues['description']![locale.languageCode]!; String get value => localizedValues['value']![locale.languageCode]!; @@ -259,23 +317,30 @@ class TranslationBase { String get enterId => localizedValues['enterId']![locale.languageCode]!; - String get pleaseEnterYourID => localizedValues['pleaseEnterYourID']![locale.languageCode]!; + String get pleaseEnterYourID => + localizedValues['pleaseEnterYourID']![locale.languageCode]!; - String get enterPassword => localizedValues['enterPassword']![locale.languageCode]!; + String get enterPassword => + localizedValues['enterPassword']![locale.languageCode]!; - String get pleaseEnterPassword => localizedValues['pleaseEnterPassword']![locale.languageCode]!; + String get pleaseEnterPassword => + localizedValues['pleaseEnterPassword']![locale.languageCode]!; - String get selectYourProject => localizedValues['selectYourProject']![locale.languageCode]!; + String get selectYourProject => + localizedValues['selectYourProject']![locale.languageCode]!; - String get pleaseEnterYourProject => localizedValues['pleaseEnterYourProject']![locale.languageCode]!; + String get pleaseEnterYourProject => + localizedValues['pleaseEnterYourProject']![locale.languageCode]!; String get login => localizedValues['login']![locale.languageCode]!; - String get drSulaimanAlHabib => localizedValues['drSulaimanAlHabib']![locale.languageCode]!; + String get drSulaimanAlHabib => + localizedValues['drSulaimanAlHabib']![locale.languageCode]!; String get welcomeTo => localizedValues['welcomeTo']![locale.languageCode]!; - String get welcomeBackTo => localizedValues['welcomeBackTo']![locale.languageCode]!; + String get welcomeBackTo => + localizedValues['welcomeBackTo']![locale.languageCode]!; String get home => localizedValues['home']![locale.languageCode]!; @@ -283,7 +348,8 @@ class TranslationBase { String get sms => localizedValues['sms']![locale.languageCode]!; - String get fingerprint => localizedValues['fingerprint']![locale.languageCode]!; + String get fingerprint => + localizedValues['fingerprint']![locale.languageCode]!; String get faceId => localizedValues['faceId']![locale.languageCode]!; @@ -291,41 +357,51 @@ class TranslationBase { String get whatsAppBy => localizedValues['whatsAppBy']![locale.languageCode]!; - String get pleaseChoose => localizedValues['pleaseChoose']![locale.languageCode]!; + String get pleaseChoose => + localizedValues['pleaseChoose']![locale.languageCode]!; String get choose => localizedValues['choose']![locale.languageCode]!; - String get verification => localizedValues['verification']![locale.languageCode]!; + String get verification => + localizedValues['verification']![locale.languageCode]!; String get firstStep => localizedValues['firstStep']![locale.languageCode]!; - String get yourAccount => localizedValues['yourAccount!']![locale.languageCode]!; + String get yourAccount => + localizedValues['yourAccount!']![locale.languageCode]!; String get verify1 => localizedValues['verify1']![locale.languageCode]!; - String get youWillReceiveA => localizedValues['youWillReceiveA']![locale.languageCode]!; + String get youWillReceiveA => + localizedValues['youWillReceiveA']![locale.languageCode]!; String get loginCode => localizedValues['loginCode']![locale.languageCode]!; String get smsBy => localizedValues['smsBy']![locale.languageCode]!; - String get pleaseEnterTheCode => localizedValues['pleaseEnterTheCode']![locale.languageCode]!; + String get pleaseEnterTheCode => + localizedValues['pleaseEnterTheCode']![locale.languageCode]!; - String get youDontHaveAnyPatient => localizedValues['youDontHaveAnyPatient']![locale.languageCode]!; + String get youDontHaveAnyPatient => + localizedValues['youDontHaveAnyPatient']![locale.languageCode]!; - String get youDoNotHaveAnyItem => localizedValues['youDoNotHaveAnyItem']![locale.languageCode]!; + String get youDoNotHaveAnyItem => + localizedValues['youDoNotHaveAnyItem']![locale.languageCode]!; String get age => localizedValues['age']![locale.languageCode]!; - String get nationality => localizedValues['nationality']![locale.languageCode]!; + String get nationality => + localizedValues['nationality']![locale.languageCode]!; String get occupation => localizedValues['occupation']![locale.languageCode]!; String get healthID => localizedValues['healthID']![locale.languageCode]!; - String get identityNumber => localizedValues['identityNumber']![locale.languageCode]!; + String get identityNumber => + localizedValues['identityNumber']![locale.languageCode]!; - String get maritalStatus => localizedValues['maritalStatus']![locale.languageCode]!; + String get maritalStatus => + localizedValues['maritalStatus']![locale.languageCode]!; String get today => localizedValues['today']![locale.languageCode]!; @@ -337,15 +413,18 @@ class TranslationBase { String get yesterday => localizedValues['yesterday']![locale.languageCode]!; - String get errorNoInsuranceApprovals => localizedValues['errorNoInsuranceApprovals']![locale.languageCode]!; + String get errorNoInsuranceApprovals => + localizedValues['errorNoInsuranceApprovals']![locale.languageCode]!; - String get searchInsuranceApprovals => localizedValues['searchInsuranceApprovals']![locale.languageCode]!; + String get searchInsuranceApprovals => + localizedValues['searchInsuranceApprovals']![locale.languageCode]!; String get status => localizedValues['status']![locale.languageCode]!; String get expiryDate => localizedValues['expiryDate']![locale.languageCode]!; - String get producerName => localizedValues['producerName']![locale.languageCode]!; + String get producerName => + localizedValues['producerName']![locale.languageCode]!; String get receiptOn => localizedValues['receiptOn']![locale.languageCode]!; @@ -363,11 +442,14 @@ class TranslationBase { String get send => localizedValues['send']![locale.languageCode]!; - String get referralFrequency => localizedValues['referralFrequency']![locale.languageCode]!; + String get referralFrequency => + localizedValues['referralFrequency']![locale.languageCode]!; - String get selectReferralFrequency => localizedValues['selectReferralFrequency']![locale.languageCode]!; + String get selectReferralFrequency => + localizedValues['selectReferralFrequency']![locale.languageCode]!; - String get clinicalDetailsAndRemarks => localizedValues['clinicalDetailsAndRemarks']![locale.languageCode]!; + String get clinicalDetailsAndRemarks => + localizedValues['clinicalDetailsAndRemarks']![locale.languageCode]!; String get remarks => localizedValues['remarks']![locale.languageCode]!; @@ -375,33 +457,43 @@ class TranslationBase { String get replay2 => localizedValues['replay2']![locale.languageCode]!; - String get outPatient => localizedValues['outPatients']![locale.languageCode]!; + String get outPatient => + localizedValues['outPatients']![locale.languageCode]!; - String get myOutPatient => localizedValues['myOutPatient']![locale.languageCode]!; + String get myOutPatient => + localizedValues['myOutPatient']![locale.languageCode]!; - String get myOutPatient_2lines => localizedValues['myOutPatient_2lines']![locale.languageCode]!; + String get myOutPatient_2lines => + localizedValues['myOutPatient_2lines']![locale.languageCode]!; String get logout => localizedValues['logout']![locale.languageCode]!; - String get pharmaciesList => localizedValues['pharmaciesList']![locale.languageCode]!; + String get pharmaciesList => + localizedValues['pharmaciesList']![locale.languageCode]!; String get price => localizedValues['price']![locale.languageCode]!; - String get youCanFindItIn => localizedValues['youCanFindItIn']![locale.languageCode]!; + String get youCanFindItIn => + localizedValues['youCanFindItIn']![locale.languageCode]!; - String get radiologyReport => localizedValues['radiologyReport']![locale.languageCode]!; + String get radiologyReport => + localizedValues['radiologyReport']![locale.languageCode]!; String get orders => localizedValues['orders']![locale.languageCode]!; String get list => localizedValues['list']![locale.languageCode]!; - String get searchOrders => localizedValues['searchOrders']![locale.languageCode]!; + String get searchOrders => + localizedValues['searchOrders']![locale.languageCode]!; - String get prescriptionDetails => localizedValues['prescriptionDetails']![locale.languageCode]!; + String get prescriptionDetails => + localizedValues['prescriptionDetails']![locale.languageCode]!; - String get prescriptionInfo => localizedValues['prescriptionInfo']![locale.languageCode]!; + String get prescriptionInfo => + localizedValues['prescriptionInfo']![locale.languageCode]!; - String get errorNoOrders => localizedValues['errorNoOrders']![locale.languageCode]!; + String get errorNoOrders => + localizedValues['errorNoOrders']![locale.languageCode]!; String get livecare => localizedValues['livecare']![locale.languageCode]!; @@ -410,22 +502,27 @@ class TranslationBase { String get beingGreat => localizedValues['beingGreat']![locale.languageCode]!; String get cancel => localizedValues['cancel']![locale.languageCode]!; + String get cancelSmall => localizedValues['cancelSmall']![locale.languageCode]!; + String get saveSmall => localizedValues['saveSmall']![locale.languageCode]!; String get ok => localizedValues['ok']![locale.languageCode]!; String get done => localizedValues['done']![locale.languageCode]!; - String get searchMedicineImageCaption => localizedValues['searchMedicineImageCaption']![locale.languageCode]!; + String get searchMedicineImageCaption => + localizedValues['searchMedicineImageCaption']![locale.languageCode]!; String get type => localizedValues['type']![locale.languageCode]!; String get resumecall => localizedValues['resumecall']![locale.languageCode]!; - String get endcallwithcharge => localizedValues['endcallwithcharge']![locale.languageCode]!; + String get endcallwithcharge => + localizedValues['endcallwithcharge']![locale.languageCode]!; String get endcall => localizedValues['endcall']![locale.languageCode]!; - String get transfertoadmin => localizedValues['transfertoadmin']![locale.languageCode]!; + String get transfertoadmin => + localizedValues['transfertoadmin']![locale.languageCode]!; String get fromDate => localizedValues['fromDate']![locale.languageCode]!; @@ -435,15 +532,19 @@ class TranslationBase { String get toTime => localizedValues['toTime']![locale.languageCode]!; - String get searchPatientImageCaptionTitle => localizedValues['searchPatientImageCaptionTitle']![locale.languageCode]!; + String get searchPatientImageCaptionTitle => + localizedValues['searchPatientImageCaptionTitle']![locale.languageCode]!; - String get searchPatientImageCaptionBody => localizedValues['searchPatientImageCaptionBody']![locale.languageCode]!; + String get searchPatientImageCaptionBody => + localizedValues['searchPatientImageCaptionBody']![locale.languageCode]!; String get welcome => localizedValues['welcome']![locale.languageCode]!; - String get typeMedicineName => localizedValues['typeMedicineName']![locale.languageCode]!; + String get typeMedicineName => + localizedValues['typeMedicineName']![locale.languageCode]!; - String get moreThan3Letter => localizedValues['moreThan3Letter']![locale.languageCode]!; + String get moreThan3Letter => + localizedValues['moreThan3Letter']![locale.languageCode]!; String get gender2 => localizedValues['gender2']![locale.languageCode]!; @@ -451,7 +552,8 @@ class TranslationBase { String get sickleave => localizedValues['sick-leaves']![locale.languageCode]!; - String get patientSick => localizedValues['patient-sick']![locale.languageCode]!; + String get patientSick => + localizedValues['patient-sick']![locale.languageCode]!; String get leave => localizedValues['leave']![locale.languageCode]!; @@ -461,17 +563,21 @@ class TranslationBase { String get clinicName => localizedValues['clinicname']![locale.languageCode]!; - String get sickLeaveDate => localizedValues['sick-leave-date']![locale.languageCode]!; + String get sickLeaveDate => + localizedValues['sick-leave-date']![locale.languageCode]!; - String get sickLeaveDays => localizedValues['sick-leave-days']![locale.languageCode]!; + String get sickLeaveDays => + localizedValues['sick-leave-days']![locale.languageCode]!; - String get admissionDetail => localizedValues['admissionDetail']![locale.languageCode]!; + String get admissionDetail => + localizedValues['admissionDetail']![locale.languageCode]!; String get dateTime => localizedValues['dateTime']![locale.languageCode]!; String get date => localizedValues['date']![locale.languageCode]!; - String get admissionNo => localizedValues['admissionNo']![locale.languageCode]!; + String get admissionNo => + localizedValues['admissionNo']![locale.languageCode]!; String get losNo => localizedValues['losNo']![locale.languageCode]!; @@ -481,21 +587,27 @@ class TranslationBase { String get bed => localizedValues['bed']![locale.languageCode]!; - String get previousSickLeaveIssue => localizedValues['prevoius-sickleave-issed']![locale.languageCode]!; + String get previousSickLeaveIssue => + localizedValues['prevoius-sickleave-issed']![locale.languageCode]!; - String get noSickLeaveApplied => localizedValues['no-sickleve-applied']![locale.languageCode]!; + String get noSickLeaveApplied => + localizedValues['no-sickleve-applied']![locale.languageCode]!; String get applyNow => localizedValues['applynow']![locale.languageCode]!; - String get addSickLeave => localizedValues['add-sickleave']![locale.languageCode]!; + String get addSickLeave => + localizedValues['add-sickleave']![locale.languageCode]!; - String get pharmacyIntervention => localizedValues['pharmacy-intervention']![locale.languageCode]!; + String get pharmacyIntervention => + localizedValues['pharmacy-intervention']![locale.languageCode]!; String get add => localizedValues['add']![locale.languageCode]!; - String get addSickLeaverequest => localizedValues['addSickLeaveRequest']![locale.languageCode]!; + String get addSickLeaverequest => + localizedValues['addSickLeaveRequest']![locale.languageCode]!; - String get extendSickLeaverequest => localizedValues['extendSickLeaveRequest']![locale.languageCode]!; + String get extendSickLeaverequest => + localizedValues['extendSickLeaveRequest']![locale.languageCode]!; String get approved => localizedValues['approved']![locale.languageCode]!; @@ -503,17 +615,22 @@ class TranslationBase { String get pending => localizedValues['pending']![locale.languageCode]!; - String get leaveStartDate => localizedValues['leave-start-date']![locale.languageCode]!; + String get leaveStartDate => + localizedValues['leave-start-date']![locale.languageCode]!; - String get daysSickleave => localizedValues['days-sick-leave']![locale.languageCode]!; + String get daysSickleave => + localizedValues['days-sick-leave']![locale.languageCode]!; String get extend => localizedValues['extend']![locale.languageCode]!; - String get extendSickLeave => localizedValues['extend-sickleave']![locale.languageCode]!; + String get extendSickLeave => + localizedValues['extend-sickleave']![locale.languageCode]!; - String get targetPatient => localizedValues['patient-target']![locale.languageCode]!; + String get targetPatient => + localizedValues['patient-target']![locale.languageCode]!; - String get noPrescription => localizedValues['no-priscription-listed']![locale.languageCode]!; + String get noPrescription => + localizedValues['no-priscription-listed']![locale.languageCode]!; String get next => localizedValues['next']![locale.languageCode]!; @@ -521,23 +638,29 @@ class TranslationBase { String get previous => localizedValues['previous']![locale.languageCode]!; - String get emptyMessage => localizedValues['empty-message']![locale.languageCode]!; + String get emptyMessage => + localizedValues['empty-message']![locale.languageCode]!; - String get healthRecordInformation => localizedValues['healthRecordInformation']![locale.languageCode]!; + String get healthRecordInformation => + localizedValues['healthRecordInformation']![locale.languageCode]!; - String get chiefComplaintLength => localizedValues['chiefComplaintLength']![locale.languageCode]!; + String get chiefComplaintLength => + localizedValues['chiefComplaintLength']![locale.languageCode]!; String get referTo => localizedValues['referTo']![locale.languageCode]!; - String get referredFrom => localizedValues['referredFrom']![locale.languageCode]!; + String get referredFrom => + localizedValues['referredFrom']![locale.languageCode]!; String get refClinic => localizedValues['refClinic']![locale.languageCode]!; String get branch => localizedValues['branch']![locale.languageCode]!; - String get chooseAppointment => localizedValues['chooseAppointment']![locale.languageCode]!; + String get chooseAppointment => + localizedValues['chooseAppointment']![locale.languageCode]!; - String get appointmentNo => localizedValues['appointmentNo']![locale.languageCode]!; + String get appointmentNo => + localizedValues['appointmentNo']![locale.languageCode]!; String get refer => localizedValues['refer']![locale.languageCode]!; @@ -545,23 +668,29 @@ class TranslationBase { String get sameBranch => localizedValues['sameBranch']![locale.languageCode]!; - String get otherBranch => localizedValues['otherBranch']![locale.languageCode]!; + String get otherBranch => + localizedValues['otherBranch']![locale.languageCode]!; String get dr => localizedValues['dr']![locale.languageCode]!; - String get previewHealth => localizedValues['previewHealth']![locale.languageCode]!; + String get previewHealth => + localizedValues['previewHealth']![locale.languageCode]!; - String get summaryReport => localizedValues['summaryReport']![locale.languageCode]!; + String get summaryReport => + localizedValues['summaryReport']![locale.languageCode]!; String get accept => localizedValues['accept']![locale.languageCode]!; String get reject => localizedValues['reject']![locale.languageCode]!; - String get noAppointmentsErrorMsg => localizedValues['noAppointmentsErrorMsg']![locale.languageCode]!; + String get noAppointmentsErrorMsg => + localizedValues['noAppointmentsErrorMsg']![locale.languageCode]!; - String get referralPatient => localizedValues['referralPatient']![locale.languageCode]!; + String get referralPatient => + localizedValues['referralPatient']![locale.languageCode]!; - String get noPrescriptionListed => localizedValues['noPrescriptionListed']![locale.languageCode]!; + String get noPrescriptionListed => + localizedValues['noPrescriptionListed']![locale.languageCode]!; String get addNow => localizedValues['addNow']![locale.languageCode]!; @@ -575,19 +704,24 @@ class TranslationBase { String get duration => localizedValues['duration']![locale.languageCode]!; - String get instruction => localizedValues['instruction']![locale.languageCode]!; + String get instruction => + localizedValues['instruction']![locale.languageCode]!; - String get rescheduleLeaves => localizedValues['reschedule-leave']![locale.languageCode]!; + String get rescheduleLeaves => + localizedValues['reschedule-leave']![locale.languageCode]!; - String get applyOrRescheduleLeave => localizedValues['applyOrRescheduleLeave']![locale.languageCode]!; + String get applyOrRescheduleLeave => + localizedValues['applyOrRescheduleLeave']![locale.languageCode]!; String get myQRCode => localizedValues['myQRCode']![locale.languageCode]!; - String get addMedication => localizedValues['addMedication']![locale.languageCode]!; + String get addMedication => + localizedValues['addMedication']![locale.languageCode]!; String get route => localizedValues['route']![locale.languageCode]!; - String get noReScheduleLeave => localizedValues['no-reschedule-leave']![locale.languageCode]!; + String get noReScheduleLeave => + localizedValues['no-reschedule-leave']![locale.languageCode]!; String get weight => localizedValues['weight']![locale.languageCode]!; @@ -597,7 +731,8 @@ class TranslationBase { String get cm => localizedValues['cm']![locale.languageCode]!; - String get idealBodyWeight => localizedValues['idealBodyWeight']![locale.languageCode]!; + String get idealBodyWeight => + localizedValues['idealBodyWeight']![locale.languageCode]!; String get waistSize => localizedValues['waistSize']![locale.languageCode]!; @@ -605,21 +740,27 @@ class TranslationBase { String get headCircum => localizedValues['headCircum']![locale.languageCode]!; - String get leanBodyWeight => localizedValues['leanBodyWeight']![locale.languageCode]!; + String get leanBodyWeight => + localizedValues['leanBodyWeight']![locale.languageCode]!; - String get bodyMassIndex => localizedValues['bodyMassIndex']![locale.languageCode]!; + String get bodyMassIndex => + localizedValues['bodyMassIndex']![locale.languageCode]!; - String get yourBodyMassIndex => localizedValues['yourBodyMassIndex']![locale.languageCode]!; + String get yourBodyMassIndex => + localizedValues['yourBodyMassIndex']![locale.languageCode]!; - String get bmiUnderWeight => localizedValues['bmiUnderWeight']![locale.languageCode]!; + String get bmiUnderWeight => + localizedValues['bmiUnderWeight']![locale.languageCode]!; String get bmiHealthy => localizedValues['bmiHealthy']![locale.languageCode]!; - String get bmiOverWeight => localizedValues['bmiOverWeight']![locale.languageCode]!; + String get bmiOverWeight => + localizedValues['bmiOverWeight']![locale.languageCode]!; String get bmiObese => localizedValues['bmiObese']![locale.languageCode]!; - String get bmiObeseExtreme => localizedValues['bmiObeseExtreme']![locale.languageCode]!; + String get bmiObeseExtreme => + localizedValues['bmiObeseExtreme']![locale.languageCode]!; String get method => localizedValues['method']![locale.languageCode]!; @@ -629,35 +770,45 @@ class TranslationBase { String get respBeats => localizedValues['respBeats']![locale.languageCode]!; - String get patternOfRespiration => localizedValues['patternOfRespiration']![locale.languageCode]!; + String get patternOfRespiration => + localizedValues['patternOfRespiration']![locale.languageCode]!; - String get bloodPressureDiastoleAndSystole => localizedValues['bloodPressureDiastoleAndSystole']![locale.languageCode]!; + String get bloodPressureDiastoleAndSystole => + localizedValues['bloodPressureDiastoleAndSystole']![locale.languageCode]!; - String get cuffLocation => localizedValues['cuffLocation']![locale.languageCode]!; + String get cuffLocation => + localizedValues['cuffLocation']![locale.languageCode]!; String get cuffSize => localizedValues['cuffSize']![locale.languageCode]!; - String get patientPosition => localizedValues['patientPosition']![locale.languageCode]!; + String get patientPosition => + localizedValues['patientPosition']![locale.languageCode]!; String get fio2 => localizedValues['fio2']![locale.languageCode]!; String get sao2 => localizedValues['sao2']![locale.languageCode]!; - String get painManagement => localizedValues['painManagement']![locale.languageCode]!; + String get painManagement => + localizedValues['painManagement']![locale.languageCode]!; String get holiday => localizedValues['holiday']![locale.languageCode]!; String get to => localizedValues['to']![locale.languageCode]!; - String get coveringDoctor => localizedValues['coveringDoctor']![locale.languageCode]!; + String get coveringDoctor => + localizedValues['coveringDoctor']![locale.languageCode]!; - String get requestLeave => localizedValues['requestLeave']![locale.languageCode]!; + String get requestLeave => + localizedValues['requestLeave']![locale.languageCode]!; - String get pleaseEnterDate => localizedValues['pleaseEnterDate']![locale.languageCode]!; + String get pleaseEnterDate => + localizedValues['pleaseEnterDate']![locale.languageCode]!; - String get pleaseEnterNoOfDays => localizedValues['pleaseEnterNoOfDays']![locale.languageCode]!; + String get pleaseEnterNoOfDays => + localizedValues['pleaseEnterNoOfDays']![locale.languageCode]!; - String get pleaseEnterRemarks => localizedValues['pleaseEnterRemarks']![locale.languageCode]!; + String get pleaseEnterRemarks => + localizedValues['pleaseEnterRemarks']![locale.languageCode]!; String get update => localizedValues['update']![locale.languageCode]!; @@ -665,69 +816,94 @@ class TranslationBase { String get request => localizedValues['request']![locale.languageCode]!; - String get admissionRequest => localizedValues['admissionRequest']![locale.languageCode]!; + String get admissionRequest => + localizedValues['admissionRequest']![locale.languageCode]!; - String get patientDetails => localizedValues['patientDetails']![locale.languageCode]!; + String get patientDetails => + localizedValues['patientDetails']![locale.languageCode]!; - String get specialityAndDoctorDetail => localizedValues['specialityAndDoctorDetail']![locale.languageCode]!; + String get specialityAndDoctorDetail => + localizedValues['specialityAndDoctorDetail']![locale.languageCode]!; - String get referringDate => localizedValues['referringDate']![locale.languageCode]!; + String get referringDate => + localizedValues['referringDate']![locale.languageCode]!; - String get referringDoctor => localizedValues['referringDoctor']![locale.languageCode]!; + String get referringDoctor => + localizedValues['referringDoctor']![locale.languageCode]!; - String get otherInformation => localizedValues['otherInformation']![locale.languageCode]!; + String get otherInformation => + localizedValues['otherInformation']![locale.languageCode]!; - String get expectedDays => localizedValues['expectedDays']![locale.languageCode]!; + String get expectedDays => + localizedValues['expectedDays']![locale.languageCode]!; - String get expectedAdmissionDate => localizedValues['expectedAdmissionDate']![locale.languageCode]!; + String get expectedAdmissionDate => + localizedValues['expectedAdmissionDate']![locale.languageCode]!; - String get emergencyAdmission => localizedValues['emergencyAdmission']![locale.languageCode]!; + String get emergencyAdmission => + localizedValues['emergencyAdmission']![locale.languageCode]!; - String get isSickLeaveRequired => localizedValues['isSickLeaveRequired']![locale.languageCode]!; + String get isSickLeaveRequired => + localizedValues['isSickLeaveRequired']![locale.languageCode]!; - String get patientPregnant => localizedValues['patientPregnant']![locale.languageCode]!; + String get patientPregnant => + localizedValues['patientPregnant']![locale.languageCode]!; - String get treatmentLine => localizedValues['treatmentLine']![locale.languageCode]!; + String get treatmentLine => + localizedValues['treatmentLine']![locale.languageCode]!; String get ward => localizedValues['ward']![locale.languageCode]!; - String get preAnesthesiaReferred => localizedValues['preAnesthesiaReferred']![locale.languageCode]!; + String get preAnesthesiaReferred => + localizedValues['preAnesthesiaReferred']![locale.languageCode]!; - String get admissionType => localizedValues['admissionType']![locale.languageCode]!; + String get admissionType => + localizedValues['admissionType']![locale.languageCode]!; String get diagnosis => localizedValues['diagnosis']![locale.languageCode]!; String get allergies => localizedValues['allergies']![locale.languageCode]!; - String get preOperativeOrders => localizedValues['preOperativeOrders']![locale.languageCode]!; + String get preOperativeOrders => + localizedValues['preOperativeOrders']![locale.languageCode]!; - String get elementForImprovement => localizedValues['elementForImprovement']![locale.languageCode]!; + String get elementForImprovement => + localizedValues['elementForImprovement']![locale.languageCode]!; - String get dischargeDate => localizedValues['dischargeDate']![locale.languageCode]!; + String get dischargeDate => + localizedValues['dischargeDate']![locale.languageCode]!; String get dietType => localizedValues['dietType']![locale.languageCode]!; - String get dietTypeRemarks => localizedValues['dietTypeRemarks']![locale.languageCode]!; + String get dietTypeRemarks => + localizedValues['dietTypeRemarks']![locale.languageCode]!; String get save => localizedValues['save']![locale.languageCode]!; - String get postPlansEstimatedCost => localizedValues['postPlansEstimatedCost']![locale.languageCode]!; + String get postPlansEstimatedCost => + localizedValues['postPlansEstimatedCost']![locale.languageCode]!; String get postPlans => localizedValues['postPlans']![locale.languageCode]!; String get ucaf => localizedValues['ucaf']![locale.languageCode]!; - String get emergencyCase => localizedValues['emergencyCase']![locale.languageCode]!; + String get emergencyCase => + localizedValues['emergencyCase']![locale.languageCode]!; - String get durationOfIllness => localizedValues['durationOfIllness']![locale.languageCode]!; + String get durationOfIllness => + localizedValues['durationOfIllness']![locale.languageCode]!; - String get chiefComplaintsAndSymptoms => localizedValues['chiefComplaintsAndSymptoms']![locale.languageCode]!; + String get chiefComplaintsAndSymptoms => + localizedValues['chiefComplaintsAndSymptoms']![locale.languageCode]!; - String get patientFeelsPainInHisBackAndCough => localizedValues['patientFeelsPainInHisBackAndCough']![locale.languageCode]!; + String get patientFeelsPainInHisBackAndCough => localizedValues[ + 'patientFeelsPainInHisBackAndCough']![locale.languageCode]!; - String get additionalTextComplaints => localizedValues['additionalTextComplaints']![locale.languageCode]!; + String get additionalTextComplaints => + localizedValues['additionalTextComplaints']![locale.languageCode]!; - String get otherConditions => localizedValues['otherConditions']![locale.languageCode]!; + String get otherConditions => + localizedValues['otherConditions']![locale.languageCode]!; String get other => localizedValues['other']![locale.languageCode]!; @@ -737,11 +913,14 @@ class TranslationBase { String get where => localizedValues['where']![locale.languageCode]!; - String get specifyPossibleLineManagement => localizedValues['specifyPossibleLineManagement']![locale.languageCode]!; + String get specifyPossibleLineManagement => + localizedValues['specifyPossibleLineManagement']![locale.languageCode]!; - String get significantSigns => localizedValues['significantSigns']![locale.languageCode]!; + String get significantSigns => + localizedValues['significantSigns']![locale.languageCode]!; - String get backAbdomen => localizedValues['backAbdomen']![locale.languageCode]!; + String get backAbdomen => + localizedValues['backAbdomen']![locale.languageCode]!; String get reasons => localizedValues['reasons']![locale.languageCode]!; @@ -749,53 +928,72 @@ class TranslationBase { String get episode => localizedValues['episode']![locale.languageCode]!; - String get medications => localizedValues['medications']![locale.languageCode]!; + String get medications => + localizedValues['medications']![locale.languageCode]!; String get medication => localizedValues['medication']![locale.languageCode]!; - String get doctorComments => localizedValues['doctorComments']![locale.languageCode]!; + String get doctorComments => + localizedValues['doctorComments']![locale.languageCode]!; - String get statusDescription => localizedValues['statusDescription']![locale.languageCode]!; + String get statusDescription => + localizedValues['statusDescription']![locale.languageCode]!; - String get createdByName => localizedValues['createdByName']![locale.languageCode]!; + String get createdByName => + localizedValues['createdByName']![locale.languageCode]!; String get procedures => localizedValues['procedures']![locale.languageCode]!; - String get chiefComplaints => localizedValues['chiefComplaints']![locale.languageCode]!; + String get chiefComplaints => + localizedValues['chiefComplaints']![locale.languageCode]!; String get histories => localizedValues['histories']![locale.languageCode]!; - String get allergiesSoap => localizedValues['allergiesSoap']![locale.languageCode]!; + String get allergiesSoap => + localizedValues['allergiesSoap']![locale.languageCode]!; - String get addChiefComplaints => localizedValues['addChiefComplaints']![locale.languageCode]!; + String get addChiefComplaints => + localizedValues['addChiefComplaints']![locale.languageCode]!; - String get historyOfPresentIllness => localizedValues['historyOfPresentIllness']![locale.languageCode]!; + String get historyOfPresentIllness => + localizedValues['historyOfPresentIllness']![locale.languageCode]!; - String get requiredMsg => localizedValues['requiredMsg']![locale.languageCode]!; + String get requiredMsg => + localizedValues['requiredMsg']![locale.languageCode]!; String get addHistory => localizedValues['addHistory']![locale.languageCode]!; - String get searchHistory => localizedValues['searchHistory']![locale.languageCode]!; + String get searchHistory => + localizedValues['searchHistory']![locale.languageCode]!; - String get addSelectedHistories => localizedValues['addSelectedHistories']![locale.languageCode]!; + String get addSelectedHistories => + localizedValues['addSelectedHistories']![locale.languageCode]!; - String get addAllergies => localizedValues['addAllergies']![locale.languageCode]!; + String get addAllergies => + localizedValues['addAllergies']![locale.languageCode]!; String get itemExist => localizedValues['itemExist']![locale.languageCode]!; - String get selectAllergy => localizedValues['selectAllergy']![locale.languageCode]!; + String get selectAllergy => + localizedValues['selectAllergy']![locale.languageCode]!; - String get selectSeverity => localizedValues['selectSeverity']![locale.languageCode]!; + String get selectSeverity => + localizedValues['selectSeverity']![locale.languageCode]!; - String get leaveCreated => localizedValues['leaveCreated']![locale.languageCode]!; + String get leaveCreated => + localizedValues['leaveCreated']![locale.languageCode]!; - String get vitalSignEmptyMsg => localizedValues['vitalSignEmptyMsg']![locale.languageCode]!; + String get vitalSignEmptyMsg => + localizedValues['vitalSignEmptyMsg']![locale.languageCode]!; - String get referralEmptyMsg => localizedValues['referralEmptyMsg']![locale.languageCode]!; + String get referralEmptyMsg => + localizedValues['referralEmptyMsg']![locale.languageCode]!; - String get referralSuccessMsg => localizedValues['referralSuccessMsg']![locale.languageCode]!; + String get referralSuccessMsg => + localizedValues['referralSuccessMsg']![locale.languageCode]!; - String get diagnoseType => localizedValues['diagnoseType']![locale.languageCode]!; + String get diagnoseType => + localizedValues['diagnoseType']![locale.languageCode]!; String get condition => localizedValues['condition']![locale.languageCode]!; @@ -809,53 +1007,76 @@ class TranslationBase { String get covered => localizedValues['covered']![locale.languageCode]!; - String get approvalRequired => localizedValues['approvalRequired']![locale.languageCode]!; + String get approvalRequired => + localizedValues['approvalRequired']![locale.languageCode]!; - String get uncoveredByDoctor => localizedValues['uncoveredByDoctor']![locale.languageCode]!; + String get uncoveredByDoctor => + localizedValues['uncoveredByDoctor']![locale.languageCode]!; - String get chiefComplaintEmptyMsg => localizedValues['chiefComplaintEmptyMsg']![locale.languageCode]!; + String get chiefComplaintEmptyMsg => + localizedValues['chiefComplaintEmptyMsg']![locale.languageCode]!; - String get moreVerification => localizedValues['more-verify']![locale.languageCode]!; + String get moreVerification => + localizedValues['more-verify']![locale.languageCode]!; - String get welcomeBack => localizedValues['welcome-back']![locale.languageCode]!; + String get welcomeBack => + localizedValues['welcome-back']![locale.languageCode]!; - String get accountInfo => localizedValues['account-info']![locale.languageCode]!; + String get accountInfo => + localizedValues['account-info']![locale.languageCode]!; - String get useAnotherAccount => localizedValues['another-acc']![locale.languageCode]!; + String get useAnotherAccount => + localizedValues['another-acc']![locale.languageCode]!; - String get verifyLoginWith => localizedValues['verify-login-with']![locale.languageCode]!; + String get verifyLoginWith => + localizedValues['verify-login-with']![locale.languageCode]!; - String get register => localizedValues['register-user']![locale.languageCode]!; + String get register => + localizedValues['register-user']![locale.languageCode]!; - String get verifyFingerprint => localizedValues['verify-with-fingerprint']![locale.languageCode]!; + String get verifyFingerprint => + localizedValues['verify-with-fingerprint']![locale.languageCode]!; - String get verifyFaceID => localizedValues['verify-with-faceid']![locale.languageCode]!; + String get verifyFaceID => + localizedValues['verify-with-faceid']![locale.languageCode]!; - String get verifySMS => localizedValues['verify-with-sms']![locale.languageCode]!; + String get verifySMS => + localizedValues['verify-with-sms']![locale.languageCode]!; - String get verifyWith => localizedValues['verify-with']![locale.languageCode]!; + String get verifyWith => + localizedValues['verify-with']![locale.languageCode]!; - String get verifyWhatsApp => localizedValues['verify-with-whatsapp']![locale.languageCode]!; + String get verifyWhatsApp => + localizedValues['verify-with-whatsapp']![locale.languageCode]!; - String get lastLoginAt => localizedValues['last-login']![locale.languageCode]!; + String get lastLoginAt => + localizedValues['last-login']![locale.languageCode]!; - String get lastLoginWith => localizedValues['last-login-with']![locale.languageCode]!; + String get lastLoginWith => + localizedValues['last-login-with']![locale.languageCode]!; - String get verifyFingerprint2 => localizedValues['verify-fingerprint']![locale.languageCode]!; + String get verifyFingerprint2 => + localizedValues['verify-fingerprint']![locale.languageCode]!; - String get verificationMessage => localizedValues['verification_message']![locale.languageCode]!; + String get verificationMessage => + localizedValues['verification_message']![locale.languageCode]!; - String get validationMessage => localizedValues['validation_message']![locale.languageCode]!; + String get validationMessage => + localizedValues['validation_message']![locale.languageCode]!; - String get addAssessment => localizedValues['addAssessment']![locale.languageCode]!; + String get addAssessment => + localizedValues['addAssessment']![locale.languageCode]!; String get assessment => localizedValues['assessment']![locale.languageCode]!; - String get physicalSystemExamination => localizedValues['physicalSystemExamination']![locale.languageCode]!; + String get physicalSystemExamination => + localizedValues['physicalSystemExamination']![locale.languageCode]!; - String get searchExamination => localizedValues['searchExamination']![locale.languageCode]!; + String get searchExamination => + localizedValues['searchExamination']![locale.languageCode]!; - String get addExamination => localizedValues['addExamination']![locale.languageCode]!; + String get addExamination => + localizedValues['addExamination']![locale.languageCode]!; String get doc => localizedValues['doc']![locale.languageCode]!; @@ -863,15 +1084,19 @@ class TranslationBase { String get normal => localizedValues['normal']![locale.languageCode]!; - String get notExamined => localizedValues['notExamined']![locale.languageCode]!; + String get notExamined => + localizedValues['notExamined']![locale.languageCode]!; String get abnormal => localizedValues['abnormal']![locale.languageCode]!; - String get patientNoDetailErrMsg => localizedValues['patientNoDetailErrMsg']![locale.languageCode]!; + String get patientNoDetailErrMsg => + localizedValues['patientNoDetailErrMsg']![locale.languageCode]!; - String get systolicLng => localizedValues['systolic-lng']![locale.languageCode]!; + String get systolicLng => + localizedValues['systolic-lng']![locale.languageCode]!; - String get diastolicLng => localizedValues['diastolic-lng']![locale.languageCode]!; + String get diastolicLng => + localizedValues['diastolic-lng']![locale.languageCode]!; String get mass => localizedValues['mass']![locale.languageCode]!; @@ -879,85 +1104,112 @@ class TranslationBase { String get bpm => localizedValues['bpm']![locale.languageCode]!; - String get respirationSigns => localizedValues['respiration-signs']![locale.languageCode]!; + String get respirationSigns => + localizedValues['respiration-signs']![locale.languageCode]!; String get sysDias => localizedValues['sys-dias']![locale.languageCode]!; String get body => localizedValues['body']![locale.languageCode]!; - String get respirationRate => localizedValues['respirationRate']![locale.languageCode]!; + String get respirationRate => + localizedValues['respirationRate']![locale.languageCode]!; String get heart => localizedValues['heart']![locale.languageCode]!; - String get medicalReport => localizedValues['medicalReport']![locale.languageCode]!; + String get medicalReport => + localizedValues['medicalReport']![locale.languageCode]!; String get visitDate => localizedValues['visitDate']![locale.languageCode]!; String get test => localizedValues['test']![locale.languageCode]!; - String get addMoreProcedure => localizedValues['addMoreProcedure']![locale.languageCode]!; + String get addMoreProcedure => + localizedValues['addMoreProcedure']![locale.languageCode]!; String get regular => localizedValues['regular']![locale.languageCode]!; - String get searchProcedures => localizedValues['searchProcedures']![locale.languageCode]!; + String get searchProcedures => + localizedValues['searchProcedures']![locale.languageCode]!; - String get procedureCategorise => localizedValues['procedureCategorise']![locale.languageCode]!; + String get procedureCategorise => + localizedValues['procedureCategorise']![locale.languageCode]!; - String get selectProcedures => localizedValues['selectProcedures']![locale.languageCode]!; + String get selectProcedures => + localizedValues['selectProcedures']![locale.languageCode]!; - String get addSelectedProcedures => localizedValues['addSelectedProcedures']![locale.languageCode]!; + String get addSelectedProcedures => + localizedValues['addSelectedProcedures']![locale.languageCode]!; - String get addProcedures => localizedValues['addProcedures']![locale.languageCode]!; + String get addProcedures => + localizedValues['addProcedures']![locale.languageCode]!; - String get updateProcedure => localizedValues['updateProcedure']![locale.languageCode]!; + String get updateProcedure => + localizedValues['updateProcedure']![locale.languageCode]!; - String get orderProcedure => localizedValues['orderProcedure']![locale.languageCode]!; + String get orderProcedure => + localizedValues['orderProcedure']![locale.languageCode]!; String get nameOrICD => localizedValues['nameOrICD']![locale.languageCode]!; String get dType => localizedValues['dType']![locale.languageCode]!; - String get addAssessmentDetails => localizedValues['addAssessmentDetails']![locale.languageCode]!; + String get addAssessmentDetails => + localizedValues['addAssessmentDetails']![locale.languageCode]!; - String get progressNoteSOAP => localizedValues['progressNoteSOAP']![locale.languageCode]!; + String get progressNoteSOAP => + localizedValues['progressNoteSOAP']![locale.languageCode]!; - String get addProgressNote => localizedValues['addProgressNote']![locale.languageCode]!; + String get addProgressNote => + localizedValues['addProgressNote']![locale.languageCode]!; String get createdBy => localizedValues['createdBy']![locale.languageCode]!; + String get createdOn => localizedValues['createdOn']![locale.languageCode]!; + String get riskScore => localizedValues['riskScore']![locale.languageCode]!; String get editedBy => localizedValues['editedBy']![locale.languageCode]!; - String get currentMedications => localizedValues['currentMedications']![locale.languageCode]!; + String get currentMedications => + localizedValues['currentMedications']![locale.languageCode]!; String get noItem => localizedValues['noItem']![locale.languageCode]!; - String get postUcafSuccessMsg => localizedValues['postUcafSuccessMsg']![locale.languageCode]!; + String get postUcafSuccessMsg => + localizedValues['postUcafSuccessMsg']![locale.languageCode]!; - String get vitalSignDetailEmpty => localizedValues['vitalSignDetailEmpty']![locale.languageCode]!; + String get vitalSignDetailEmpty => + localizedValues['vitalSignDetailEmpty']![locale.languageCode]!; - String get onlyOfftimeHoliday => localizedValues['onlyOfftimeHoliday']![locale.languageCode]!; + String get onlyOfftimeHoliday => + localizedValues['onlyOfftimeHoliday']![locale.languageCode]!; String get active => localizedValues['active']![locale.languageCode]!; + String get stable => localizedValues['stable']![locale.languageCode]!; String get hold => localizedValues['hold']![locale.languageCode]!; String get loading => localizedValues['loading']![locale.languageCode]!; - String get assessmentErrorMsg => localizedValues['assessmentErrorMsg']![locale.languageCode]!; + String get assessmentErrorMsg => + localizedValues['assessmentErrorMsg']![locale.languageCode]!; - String get examinationErrorMsg => localizedValues['examinationErrorMsg']![locale.languageCode]!; + String get examinationErrorMsg => + localizedValues['examinationErrorMsg']![locale.languageCode]!; - String get progressNoteErrorMsg => localizedValues['progressNoteErrorMsg']![locale.languageCode]!; + String get progressNoteErrorMsg => + localizedValues['progressNoteErrorMsg']![locale.languageCode]!; - String get chiefComplaintErrorMsg => localizedValues['chiefComplaintErrorMsg']![locale.languageCode]!; + String get chiefComplaintErrorMsg => + localizedValues['chiefComplaintErrorMsg']![locale.languageCode]!; String get ICDName => localizedValues['ICDName']![locale.languageCode]!; - String get referralStatus => localizedValues['referralStatus']![locale.languageCode]!; + String get referralStatus => + localizedValues['referralStatus']![locale.languageCode]!; - String get referralRemark => localizedValues['referralRemark']![locale.languageCode]!; + String get referralRemark => + localizedValues['referralRemark']![locale.languageCode]!; String get offTime => localizedValues['offTime']![locale.languageCode]!; @@ -973,71 +1225,101 @@ class TranslationBase { String get years => localizedValues['years']![locale.languageCode]!; - String get referralStatusHold => localizedValues['referralStatusHold']![locale.languageCode]!; + String get referralStatusHold => + localizedValues['referralStatusHold']![locale.languageCode]!; - String get referralStatusActive => localizedValues['referralStatusActive']![locale.languageCode]!; + String get referralStatusActive => + localizedValues['referralStatusActive']![locale.languageCode]!; - String get referralStatusCancelled => localizedValues['referralStatusCancelled']![locale.languageCode]!; + String get referralStatusCancelled => + localizedValues['referralStatusCancelled']![locale.languageCode]!; - String get referralStatusCompleted => localizedValues['referralStatusCompleted']![locale.languageCode]!; + String get referralStatusCompleted => + localizedValues['referralStatusCompleted']![locale.languageCode]!; - String get referralStatusNotSeen => localizedValues['referralStatusNotSeen']![locale.languageCode]!; + String get referralStatusNotSeen => + localizedValues['referralStatusNotSeen']![locale.languageCode]!; - String get clinicSearch => localizedValues['clinicSearch']![locale.languageCode]!; + String get clinicSearch => + localizedValues['clinicSearch']![locale.languageCode]!; - String get doctorSearch => localizedValues['doctorSearch']![locale.languageCode]!; + String get doctorSearch => + localizedValues['doctorSearch']![locale.languageCode]!; - String get referralResponse => localizedValues['referralResponse']![locale.languageCode]!; + String get referralResponse => + localizedValues['referralResponse']![locale.languageCode]!; - String get estimatedCost => localizedValues['estimatedCost']![locale.languageCode]!; + String get estimatedCost => + localizedValues['estimatedCost']![locale.languageCode]!; - String get diagnosisDetail => localizedValues['diagnosisDetail']![locale.languageCode]!; + String get diagnosisDetail => + localizedValues['diagnosisDetail']![locale.languageCode]!; - String get referralSuccessMsgAccept => localizedValues['referralSuccessMsgAccept']![locale.languageCode]!; + String get referralSuccessMsgAccept => + localizedValues['referralSuccessMsgAccept']![locale.languageCode]!; - String get referralSuccessMsgReject => localizedValues['referralSuccessMsgReject']![locale.languageCode]!; + String get referralSuccessMsgReject => + localizedValues['referralSuccessMsgReject']![locale.languageCode]!; - String get patientName => localizedValues['patient-name']![locale.languageCode]!; + String get patientName => + localizedValues['patient-name']![locale.languageCode]!; - String get appointmentNumber => localizedValues['appointmentNumber']![locale.languageCode]!; + String get appointmentNumber => + localizedValues['appointmentNumber']![locale.languageCode]!; - String get sickLeaveComments => localizedValues['sickLeaveComments']![locale.languageCode]!; + String get sickLeaveComments => + localizedValues['sickLeaveComments']![locale.languageCode]!; - String get pastMedicalHistory => localizedValues['pastMedicalHistory']![locale.languageCode]!; + String get pastMedicalHistory => + localizedValues['pastMedicalHistory']![locale.languageCode]!; - String get pastSurgicalHistory => localizedValues['pastSurgicalHistory']![locale.languageCode]!; + String get pastSurgicalHistory => + localizedValues['pastSurgicalHistory']![locale.languageCode]!; - String get complications => localizedValues['complications']![locale.languageCode]!; + String get complications => + localizedValues['complications']![locale.languageCode]!; String get floor => localizedValues['floor']![locale.languageCode]!; - String get roomCategory => localizedValues['roomCategory']![locale.languageCode]!; + String get roomCategory => + localizedValues['roomCategory']![locale.languageCode]!; - String get otherDepartmentsInterventions => localizedValues['otherDepartmentsInterventions']![locale.languageCode]!; + String get otherDepartmentsInterventions => + localizedValues['otherDepartmentsInterventions']![locale.languageCode]!; - String get otherProcedure => localizedValues['otherProcedure']![locale.languageCode]!; + String get otherProcedure => + localizedValues['otherProcedure']![locale.languageCode]!; - String get admissionRequestSuccessMsg => localizedValues['admissionRequestSuccessMsg']![locale.languageCode]!; + String get admissionRequestSuccessMsg => + localizedValues['admissionRequestSuccessMsg']![locale.languageCode]!; String get infoStatus => localizedValues['infoStatus']![locale.languageCode]!; - String get doctorResponse => localizedValues['doctorResponse']![locale.languageCode]!; + String get doctorResponse => + localizedValues['doctorResponse']![locale.languageCode]!; - String get sickleaveonhold => localizedValues['sickleaveonhold']![locale.languageCode]!; + String get sickleaveonhold => + localizedValues['sickleaveonhold']![locale.languageCode]!; String get noClinic => localizedValues['no-clinic']![locale.languageCode]!; - String get otherStatistic => localizedValues['otherStatistic']![locale.languageCode]!; + String get otherStatistic => + localizedValues['otherStatistic']![locale.languageCode]!; - String get patientsreferral => localizedValues['ptientsreferral']![locale.languageCode]!; + String get patientsreferral => + localizedValues['ptientsreferral']![locale.languageCode]!; - String get myPatientsReferral => localizedValues['myPatientsReferral']![locale.languageCode]!; + String get myPatientsReferral => + localizedValues['myPatientsReferral']![locale.languageCode]!; - String get arrivalpatient => localizedValues['arrivalpatient']![locale.languageCode]!; + String get arrivalpatient => + localizedValues['arrivalpatient']![locale.languageCode]!; - String get searchmedicinepatient => localizedValues['searchmedicinepatient']![locale.languageCode]!; + String get searchmedicinepatient => + localizedValues['searchmedicinepatient']![locale.languageCode]!; - String get appointmentDate => localizedValues['appointmentDate']![locale.languageCode]!; + String get appointmentDate => + localizedValues['appointmentDate']![locale.languageCode]!; String get arrivedP => localizedValues['arrived_p']![locale.languageCode]!; @@ -1045,7 +1327,8 @@ class TranslationBase { String get liveCare => localizedValues['liveCare']![locale.languageCode]!; - String get outpatient => localizedValues['out-patient']![locale.languageCode]!; + String get outpatient => + localizedValues['out-patient']![locale.languageCode]!; String get billNo => localizedValues['BillNo']![locale.languageCode]!; @@ -1053,15 +1336,19 @@ class TranslationBase { String get sendSuc => localizedValues['sendSuc']![locale.languageCode]!; - String get specialResult => localizedValues['SpecialResult']![locale.languageCode]!; + String get specialResult => + localizedValues['SpecialResult']![locale.languageCode]!; - String get noDataAvailable => localizedValues['noDataAvailable']![locale.languageCode]!; + String get noDataAvailable => + localizedValues['noDataAvailable']![locale.languageCode]!; - String get showMoreBtn => localizedValues['show-more-btn']![locale.languageCode]!; + String get showMoreBtn => + localizedValues['show-more-btn']![locale.languageCode]!; String get showDetail => localizedValues['showDetail']![locale.languageCode]!; - String get viewProfile => localizedValues['viewProfile']![locale.languageCode]!; + String get viewProfile => + localizedValues['viewProfile']![locale.languageCode]!; String get fileNumber => localizedValues['fileNumber']![locale.languageCode]!; @@ -1071,37 +1358,49 @@ class TranslationBase { String get openRad => localizedValues['open-rad']![locale.languageCode]!; - String get totalApproval => localizedValues['totalApproval']![locale.languageCode]!; + String get totalApproval => + localizedValues['totalApproval']![locale.languageCode]!; - String get procedureStatus => localizedValues['procedureStatus']![locale.languageCode]!; + String get procedureStatus => + localizedValues['procedureStatus']![locale.languageCode]!; - String get unusedCount => localizedValues['unusedCount']![locale.languageCode]!; + String get unusedCount => + localizedValues['unusedCount']![locale.languageCode]!; - String get companyName => localizedValues['companyName']![locale.languageCode]!; + String get companyName => + localizedValues['companyName']![locale.languageCode]!; - String get procedureName => localizedValues['procedureName']![locale.languageCode]!; + String get procedureName => + localizedValues['procedureName']![locale.languageCode]!; - String get usageStatus => localizedValues['usageStatus']![locale.languageCode]!; + String get usageStatus => + localizedValues['usageStatus']![locale.languageCode]!; - String get prescriptions => localizedValues['prescriptions']![locale.languageCode]!; + String get prescriptions => + localizedValues['prescriptions']![locale.languageCode]!; String get notes => localizedValues['notes']![locale.languageCode]!; String get dailyDoses => localizedValues['dailyDoses']![locale.languageCode]!; - String get searchWithOther => localizedValues['searchWithOther']![locale.languageCode]!; + String get searchWithOther => + localizedValues['searchWithOther']![locale.languageCode]!; - String get hideOtherCriteria => localizedValues['hideOtherCriteria']![locale.languageCode]!; + String get hideOtherCriteria => + localizedValues['hideOtherCriteria']![locale.languageCode]!; - String get applyForReschedule => localizedValues['applyForReschedule']![locale.languageCode]!; + String get applyForReschedule => + localizedValues['applyForReschedule']![locale.languageCode]!; String get startDate => localizedValues['startDate']![locale.languageCode]!; String get endDate => localizedValues['endDate']![locale.languageCode]!; - String get addReschedule => localizedValues['add-reschedule']![locale.languageCode]!; + String get addReschedule => + localizedValues['add-reschedule']![locale.languageCode]!; - String get updateReschedule => localizedValues['update-reschedule']![locale.languageCode]!; + String get updateReschedule => + localizedValues['update-reschedule']![locale.languageCode]!; String get sickLeave => localizedValues['sick_leave']![locale.languageCode]!; @@ -1113,7 +1412,8 @@ class TranslationBase { String get replied => localizedValues['replied']![locale.languageCode]!; - String get typeHereToReply => localizedValues['typeHereToReply']![locale.languageCode]!; + String get typeHereToReply => + localizedValues['typeHereToReply']![locale.languageCode]!; String get searchHere => localizedValues['searchHere']![locale.languageCode]!; @@ -1127,45 +1427,60 @@ class TranslationBase { String get step => localizedValues['step']![locale.languageCode]!; - String get fieldRequired => localizedValues['fieldRequired']![locale.languageCode]!; + String get fieldRequired => + localizedValues['fieldRequired']![locale.languageCode]!; - String get noSickLeave => localizedValues['no-sickleve']![locale.languageCode]!; + String get noSickLeave => + localizedValues['no-sickleve']![locale.languageCode]!; - String get changeOfSchedule => localizedValues['changeOfSchedule']![locale.languageCode]!; + String get changeOfSchedule => + localizedValues['changeOfSchedule']![locale.languageCode]!; - String get newSchedule => localizedValues['newSchedule']![locale.languageCode]!; + String get newSchedule => + localizedValues['newSchedule']![locale.languageCode]!; - String get enterCredentials => localizedValues['enter_credentials']![locale.languageCode]!; + String get enterCredentials => + localizedValues['enter_credentials']![locale.languageCode]!; - String get patpatientIDMobilenationalientID => localizedValues['patientIDMobilenational']![locale.languageCode]!; + String get patpatientIDMobilenationalientID => + localizedValues['patientIDMobilenational']![locale.languageCode]!; String get updateNow => localizedValues['updateNow']![locale.languageCode]!; - String get updateTheApp => localizedValues['updateTheApp']![locale.languageCode]!; + String get updateTheApp => + localizedValues['updateTheApp']![locale.languageCode]!; - String get admissionDate => localizedValues['admission-date']![locale.languageCode]!; + String get admissionDate => + localizedValues['admission-date']![locale.languageCode]!; String get noOfDays => localizedValues['noOfDays']![locale.languageCode]!; String get numOfDays => localizedValues['numOfDays']![locale.languageCode]!; - String get replayBefore => localizedValues['replayBefore']![locale.languageCode]!; + String get replayBefore => + localizedValues['replayBefore']![locale.languageCode]!; String get trySaying => localizedValues["try-saying"]![locale.languageCode]!; - String get acknowledged => localizedValues['acknowledged']![locale.languageCode]!; + String get acknowledged => + localizedValues['acknowledged']![locale.languageCode]!; String get didntCatch => localizedValues["didntCatch"]![locale.languageCode]!; - String get pleaseEnterProcedure => localizedValues["pleaseEnterProcedure"]![locale.languageCode]!; + String get pleaseEnterProcedure => + localizedValues["pleaseEnterProcedure"]![locale.languageCode]!; - String get fillTheMandatoryProcedureDetails => localizedValues["fillTheMandatoryProcedureDetails"]![locale.languageCode]!; + String get fillTheMandatoryProcedureDetails => localizedValues[ + "fillTheMandatoryProcedureDetails"]![locale.languageCode]!; - String get atLeastThreeCharacters => localizedValues["atLeastThreeCharacters"]![locale.languageCode]!; + String get atLeastThreeCharacters => + localizedValues["atLeastThreeCharacters"]![locale.languageCode]!; - String get searchProcedureHere => localizedValues["searchProcedureHere"]![locale.languageCode]!; + String get searchProcedureHere => + localizedValues["searchProcedureHere"]![locale.languageCode]!; - String get noInsuranceApprovalFound => localizedValues["noInsuranceApprovalFound"]![locale.languageCode]!; + String get noInsuranceApprovalFound => + localizedValues["noInsuranceApprovalFound"]![locale.languageCode]!; String get procedure => localizedValues["procedure"]![locale.languageCode]!; @@ -1177,31 +1492,43 @@ class TranslationBase { String get refill => localizedValues["refill"]![locale.languageCode]!; - String get medicationHasBeenAdded => localizedValues["medicationHasBeenAdded"]![locale.languageCode]!; + String get medicationHasBeenAdded => + localizedValues["medicationHasBeenAdded"]![locale.languageCode]!; - String get newPrescriptionOrder => localizedValues["newPrescriptionOrder"]![locale.languageCode]!; + String get newPrescriptionOrder => + localizedValues["newPrescriptionOrder"]![locale.languageCode]!; - String get pleaseFillAllFields => localizedValues["pleaseFillAllFields"]![locale.languageCode]!; + String get pleaseFillAllFields => + localizedValues["pleaseFillAllFields"]![locale.languageCode]!; - String get narcoticMedicineCanOnlyBePrescribedFromVida => localizedValues["narcoticMedicineCanOnlyBePrescribedFromVida"]![locale.languageCode]!; + String get narcoticMedicineCanOnlyBePrescribedFromVida => localizedValues[ + "narcoticMedicineCanOnlyBePrescribedFromVida"]![locale.languageCode]!; - String get only5DigitsAllowedForStrength => localizedValues["only5DigitsAllowedForStrength"]![locale.languageCode]!; + String get only5DigitsAllowedForStrength => + localizedValues["only5DigitsAllowedForStrength"]![locale.languageCode]!; String get unit => localizedValues["unit"]![locale.languageCode]!; - String get boxQuantity => localizedValues["boxQuantity"]![locale.languageCode]!; + String get boxQuantity => + localizedValues["boxQuantity"]![locale.languageCode]!; - String get orderTestOr => localizedValues["orderTestOr"]![locale.languageCode]!; + String get orderTestOr => + localizedValues["orderTestOr"]![locale.languageCode]!; - String get applyForRadiologyOrder => localizedValues["applyForRadiologyOrder"]![locale.languageCode]!; + String get applyForRadiologyOrder => + localizedValues["applyForRadiologyOrder"]![locale.languageCode]!; - String get applyForNewLabOrder => localizedValues["applyForNewLabOrder"]![locale.languageCode]!; + String get applyForNewLabOrder => + localizedValues["applyForNewLabOrder"]![locale.languageCode]!; - String get addLabOrder => localizedValues["addLabOrder"]![locale.languageCode]!; + String get addLabOrder => + localizedValues["addLabOrder"]![locale.languageCode]!; - String get addRadiologyOrder => localizedValues["addRadiologyOrder"]![locale.languageCode]!; + String get addRadiologyOrder => + localizedValues["addRadiologyOrder"]![locale.languageCode]!; - String get newRadiologyOrder => localizedValues["newRadiologyOrder"]![locale.languageCode]!; + String get newRadiologyOrder => + localizedValues["newRadiologyOrder"]![locale.languageCode]!; String get orderDate => localizedValues["orderDate"]![locale.languageCode]!; @@ -1211,35 +1538,47 @@ class TranslationBase { String get summary => localizedValues["summary"]![locale.languageCode]!; - String get applyForNewPrescriptionsOrder => localizedValues["applyForNewPrescriptionsOrder"]![locale.languageCode]!; + String get applyForNewPrescriptionsOrder => + localizedValues["applyForNewPrescriptionsOrder"]![locale.languageCode]!; - String get noPrescriptionsFound => localizedValues["noPrescriptionsFound"]![locale.languageCode]!; + String get noPrescriptionsFound => + localizedValues["noPrescriptionsFound"]![locale.languageCode]!; - String get noMedicalFileFound => localizedValues["noMedicalFileFound"]![locale.languageCode]!; + String get noMedicalFileFound => + localizedValues["noMedicalFileFound"]![locale.languageCode]!; - String get insurance22 => localizedValues["insurance22"]![locale.languageCode]!; + String get insurance22 => + localizedValues["insurance22"]![locale.languageCode]!; - String get approvals22 => localizedValues["approvals22"]![locale.languageCode]!; + String get approvals22 => + localizedValues["approvals22"]![locale.languageCode]!; String get severe => localizedValues["severe"]![locale.languageCode]!; - String get graphDetails => localizedValues["graphDetails"]![locale.languageCode]!; + String get graphDetails => + localizedValues["graphDetails"]![locale.languageCode]!; String get discharged => localizedValues["discharged"]![locale.languageCode]!; - String get addNewOrderSheet => localizedValues["addNewOrderSheet"]![locale.languageCode]!; + String get addNewOrderSheet => + localizedValues["addNewOrderSheet"]![locale.languageCode]!; - String get addNewProgressNote => localizedValues["addNewProgressNote"]![locale.languageCode]!; + String get addNewProgressNote => + localizedValues["addNewProgressNote"]![locale.languageCode]!; - String get notePending => localizedValues["notePending"]![locale.languageCode]!; + String get notePending => + localizedValues["notePending"]![locale.languageCode]!; - String get noteCanceled => localizedValues["noteCanceled"]![locale.languageCode]!; + String get noteCanceled => + localizedValues["noteCanceled"]![locale.languageCode]!; - String get noteVerified => localizedValues["noteVerified"]![locale.languageCode]!; + String get noteVerified => + localizedValues["noteVerified"]![locale.languageCode]!; String get noteVerify => localizedValues["noteVerify"]![locale.languageCode]!; - String get noteConfirm => localizedValues["noteConfirm"]![locale.languageCode]!; + String get noteConfirm => + localizedValues["noteConfirm"]![locale.languageCode]!; String get noteAdd => localizedValues["noteAdd"]![locale.languageCode]!; @@ -1259,17 +1598,21 @@ class TranslationBase { String get none => localizedValues["none"]![locale.languageCode]!; - String get notRepliedYet => localizedValues["notRepliedYet"]![locale.languageCode]!; + String get notRepliedYet => + localizedValues["notRepliedYet"]![locale.languageCode]!; String get clearText => localizedValues["clearText"]![locale.languageCode]!; - String get medicalReportAdd => localizedValues['medicalReportAdd']![locale.languageCode]!; + String get medicalReportAdd => + localizedValues['medicalReportAdd']![locale.languageCode]!; - String get medicalReportVerify => localizedValues['medicalReportVerify']![locale.languageCode]!; + String get medicalReportVerify => + localizedValues['medicalReportVerify']![locale.languageCode]!; String get comments => localizedValues['comments']![locale.languageCode]!; - String get initiateCall => localizedValues['initiateCall']![locale.languageCode]!; + String get initiateCall => + localizedValues['initiateCall']![locale.languageCode]!; String get endCall => localizedValues['endCall']![locale.languageCode]!; @@ -1277,115 +1620,153 @@ class TranslationBase { String get admin => localizedValues['admin']![locale.languageCode]!; - String get instructions => localizedValues['instructions']![locale.languageCode]!; + String get instructions => + localizedValues['instructions']![locale.languageCode]!; String get sendLC => localizedValues['sendLC']![locale.languageCode]!; String get endLC => localizedValues['endLC']![locale.languageCode]!; - String get consultation => localizedValues['consultation']![locale.languageCode]!; + String get consultation => + localizedValues['consultation']![locale.languageCode]!; String get resume => localizedValues['resume']![locale.languageCode]!; String get theCall => localizedValues['theCall']![locale.languageCode]!; - String get createNewMedicalReport => localizedValues['createNewMedicalReport']![locale.languageCode]!; + String get createNewMedicalReport => + localizedValues['createNewMedicalReport']![locale.languageCode]!; - String get historyPhysicalFinding => localizedValues['historyPhysicalFinding']![locale.languageCode]!; + String get historyPhysicalFinding => + localizedValues['historyPhysicalFinding']![locale.languageCode]!; - String get laboratoryPhysicalData => localizedValues['laboratoryPhysicalData']![locale.languageCode]!; + String get laboratoryPhysicalData => + localizedValues['laboratoryPhysicalData']![locale.languageCode]!; - String get impressionRecommendation => localizedValues['impressionRecommendation']![locale.languageCode]!; + String get impressionRecommendation => + localizedValues['impressionRecommendation']![locale.languageCode]!; String get onHold => localizedValues['onHold']![locale.languageCode]!; String get verified => localizedValues['verified']![locale.languageCode]!; - String get favoriteTemplates => localizedValues['favoriteTemplates']![locale.languageCode]!; + String get favoriteTemplates => + localizedValues['favoriteTemplates']![locale.languageCode]!; - String get allProcedures => localizedValues['allProcedures']![locale.languageCode]!; + String get allProcedures => + localizedValues['allProcedures']![locale.languageCode]!; - String get allRadiology => localizedValues['allRadiology']![locale.languageCode]!; + String get allRadiology => + localizedValues['allRadiology']![locale.languageCode]!; String get allLab => localizedValues['allLab']![locale.languageCode]!; - String get allPrescription => localizedValues['allPrescription']![locale.languageCode]!; + String get allPrescription => + localizedValues['allPrescription']![locale.languageCode]!; - String get addPrescription => localizedValues['addPrescription']![locale.languageCode]!; + String get addPrescription => + localizedValues['addPrescription']![locale.languageCode]!; String get edit => localizedValues['edit']![locale.languageCode]!; - String get summeryReply => localizedValues['summeryReply']![locale.languageCode]!; + String get summeryReply => + localizedValues['summeryReply']![locale.languageCode]!; - String get severityValidationError => localizedValues['severityValidationError']![locale.languageCode]!; + String get severityValidationError => + localizedValues['severityValidationError']![locale.languageCode]!; - String get textCopiedSuccessfully => localizedValues['textCopiedSuccessfully']![locale.languageCode]!; + String get textCopiedSuccessfully => + localizedValues['textCopiedSuccessfully']![locale.languageCode]!; String get roomNo => localizedValues['roomNo']![locale.languageCode]!; String get seeMore => localizedValues['seeMore']![locale.languageCode]!; - String get replayCallStatus => localizedValues['replayCallStatus']![locale.languageCode]!; + String get replayCallStatus => + localizedValues['replayCallStatus']![locale.languageCode]!; - String get patientArrived => localizedValues['patientArrived']![locale.languageCode]!; + String get patientArrived => + localizedValues['patientArrived']![locale.languageCode]!; - String get calledAndNoResponse => localizedValues['calledAndNoResponse']![locale.languageCode]!; + String get calledAndNoResponse => + localizedValues['calledAndNoResponse']![locale.languageCode]!; - String get underProcess => localizedValues['underProcess']![locale.languageCode]!; + String get underProcess => + localizedValues['underProcess']![locale.languageCode]!; - String get textResponse => localizedValues['textResponse']![locale.languageCode]!; + String get textResponse => + localizedValues['textResponse']![locale.languageCode]!; String get special => localizedValues['special']![locale.languageCode]!; - String get requestType => localizedValues['requestType']![locale.languageCode]!; + String get requestType => + localizedValues['requestType']![locale.languageCode]!; String get allClinic => localizedValues['allClinic']![locale.languageCode]!; String get notReplied => localizedValues['notReplied']![locale.languageCode]!; - String get registerNewPatient => localizedValues['registerNewPatient']![locale.languageCode]!; + String get registerNewPatient => + localizedValues['registerNewPatient']![locale.languageCode]!; - String get registeraPatient => localizedValues['registeraPatient']![locale.languageCode]!; + String get registeraPatient => + localizedValues['registeraPatient']![locale.languageCode]!; - String get operationTimeStart => localizedValues['operationTimeStart']![locale.languageCode]!; + String get operationTimeStart => + localizedValues['operationTimeStart']![locale.languageCode]!; - String get operationDate => localizedValues['operationDate']![locale.languageCode]!; + String get operationDate => + localizedValues['operationDate']![locale.languageCode]!; - String get reservation => localizedValues['reservation']![locale.languageCode]!; + String get reservation => + localizedValues['reservation']![locale.languageCode]!; - String get anesthetist => localizedValues['anesthetist']![locale.languageCode]!; + String get anesthetist => + localizedValues['anesthetist']![locale.languageCode]!; - String get bloodTransfusedDetail => localizedValues['bloodTransfusedDetail']![locale.languageCode]!; + String get bloodTransfusedDetail => + localizedValues['bloodTransfusedDetail']![locale.languageCode]!; - String get circulatingNurse => localizedValues['circulatingNurse']![locale.languageCode]!; + String get circulatingNurse => + localizedValues['circulatingNurse']![locale.languageCode]!; String get scrubNurse => localizedValues['scrubNurse']![locale.languageCode]!; - String get otherSpecimen => localizedValues['otherSpecimen']![locale.languageCode]!; + String get otherSpecimen => + localizedValues['otherSpecimen']![locale.languageCode]!; - String get microbiologySpecimen => localizedValues['microbiologySpecimen']![locale.languageCode]!; + String get microbiologySpecimen => + localizedValues['microbiologySpecimen']![locale.languageCode]!; - String get histopathSpecimen => localizedValues['histopathSpecimen']![locale.languageCode]!; + String get histopathSpecimen => + localizedValues['histopathSpecimen']![locale.languageCode]!; - String get bloodLossDetail => localizedValues['bloodLossDetail']![locale.languageCode]!; + String get bloodLossDetail => + localizedValues['bloodLossDetail']![locale.languageCode]!; - String get complicationDetails1 => localizedValues['complicationDetails1']![locale.languageCode]!; + String get complicationDetails1 => + localizedValues['complicationDetails1']![locale.languageCode]!; - String get postOperationInstruction => localizedValues['postOperationInstruction']![locale.languageCode]!; + String get postOperationInstruction => + localizedValues['postOperationInstruction']![locale.languageCode]!; - String get surgeryProcedure => localizedValues['surgeryProcedure']![locale.languageCode]!; + String get surgeryProcedure => + localizedValues['surgeryProcedure']![locale.languageCode]!; String get finding => localizedValues['finding']![locale.languageCode]!; - String get preOperationDiagnosis => localizedValues['preOperationDiagnosis']![locale.languageCode]!; + String get preOperationDiagnosis => + localizedValues['preOperationDiagnosis']![locale.languageCode]!; - String get postOperationDiagnosis => localizedValues['postOperationDiagnosis']![locale.languageCode]!; + String get postOperationDiagnosis => + localizedValues['postOperationDiagnosis']![locale.languageCode]!; String get surgeon => localizedValues['surgeon']![locale.languageCode]!; String get assistant => localizedValues['assistant']![locale.languageCode]!; - String get askForIdentification => localizedValues['askForIdentification']![locale.languageCode]!; + String get askForIdentification => + localizedValues['askForIdentification']![locale.languageCode]!; String get iDNumber => localizedValues['iDNumber']![locale.languageCode]!; @@ -1399,70 +1780,184 @@ class TranslationBase { String get activation => localizedValues['activation']![locale.languageCode]!; - String get confirmation => localizedValues['confirmation']![locale.languageCode]!; + String get confirmation => + localizedValues['confirmation']![locale.languageCode]!; String get diabetic => localizedValues['diabetic']![locale.languageCode]!; String get pharmacy => localizedValues['pharmacy']![locale.languageCode]!; - String get intervention => localizedValues['intervention']![locale.languageCode]!; + String get intervention => + localizedValues['intervention']![locale.languageCode]!; String get chart => localizedValues['chart']![locale.languageCode]!; - String get investigation => localizedValues['investigation']![locale.languageCode]!; + String get investigation => + localizedValues['investigation']![locale.languageCode]!; - String get conditionOnDischarge => localizedValues['conditionOnDischarge']![locale.languageCode]!; + String get conditionOnDischarge => + localizedValues['conditionOnDischarge']![locale.languageCode]!; - String get planedProcedure => localizedValues['planedProcedure']![locale.languageCode]!; + String get planedProcedure => + localizedValues['planedProcedure']![locale.languageCode]!; - String get moreDetails => localizedValues['moreDetails']![locale.languageCode]!; + String get moreDetails => + localizedValues['moreDetails']![locale.languageCode]!; String get VTE_Type => localizedValues['VTE_Type']![locale.languageCode]!; - String get pharmacology => localizedValues['pharmacology']![locale.languageCode]!; + String get pharmacology => + localizedValues['pharmacology']![locale.languageCode]!; - String get reasonsThrombo => localizedValues['reasonsThrombo']![locale.languageCode]!; + String get reasonsThrombo => + localizedValues['reasonsThrombo']![locale.languageCode]!; - String get youDoNotHaveFavoriteTemplate => localizedValues['youDoNotHaveFavoriteTemplate']![locale.languageCode]!; + String get youDoNotHaveFavoriteTemplate => + localizedValues['youDoNotHaveFavoriteTemplate']![locale.languageCode]!; - String get pleaseSelectItem => localizedValues['pleaseSelectItem']![locale.languageCode]!; + String get pleaseSelectItem => + localizedValues['pleaseSelectItem']![locale.languageCode]!; - String get searchFavoriteTemplate => localizedValues['searchFavoriteTemplate']![locale.languageCode]!; + String get searchFavoriteTemplate => + localizedValues['searchFavoriteTemplate']![locale.languageCode]!; - String get sorryNoMatch => localizedValues['sorryNoMatch']![locale.languageCode]!; + String get sorryNoMatch => + localizedValues['sorryNoMatch']![locale.languageCode]!; - String get thousandIsTheMAXForTheStrength => localizedValues['thousandIsTheMAXForTheStrength']![locale.languageCode]!; + String get thousandIsTheMAXForTheStrength => + localizedValues['thousandIsTheMAXForTheStrength']![locale.languageCode]!; - String get strengthCanNotBeZero => localizedValues['strengthCanNotBeZero']![locale.languageCode]!; + String get strengthCanNotBeZero => + localizedValues['strengthCanNotBeZero']![locale.languageCode]!; String get old => localizedValues['old']![locale.languageCode]!; - String get orderTypeDescription => localizedValues['orderTypeDescription']![locale.languageCode]!; + String get orderTypeDescription => + localizedValues['orderTypeDescription']![locale.languageCode]!; - String get doseDetails => localizedValues['doseDetails']![locale.languageCode]!; + String get doseDetails => + localizedValues['doseDetails']![locale.languageCode]!; - String get selectCondition => localizedValues['selectCondition']![locale.languageCode]!; + String get selectCondition => + localizedValues['selectCondition']![locale.languageCode]!; - String get yourOrderAddedSuccessfully => localizedValues['yourOrderAddedSuccessfully']![locale.languageCode]!; + String get yourOrderAddedSuccessfully => + localizedValues['yourOrderAddedSuccessfully']![locale.languageCode]!; - String get youCannotAddOnlySpaces => localizedValues['youCannotAddOnlySpaces']![locale.languageCode]!; + String get youCannotAddOnlySpaces => + localizedValues['youCannotAddOnlySpaces']![locale.languageCode]!; - String get conditionDescription => localizedValues['conditionDescription']![locale.languageCode]!; + String get conditionDescription => + localizedValues['conditionDescription']![locale.languageCode]!; - String get doctorSchedule => localizedValues['doctorSchedule']![locale.languageCode]!; + String get doctorSchedule => + localizedValues['doctorSchedule']![locale.languageCode]!; String get doctorRota => localizedValues['doctorRota']![locale.languageCode]!; String get dateFrom => localizedValues['dateFrom']![locale.languageCode]!; - String get searchFindSchedule => localizedValues['searchFindSchedule']![locale.languageCode]!; - String get onePrimaryDiagnosis => localizedValues['onePrimaryDiagnosis']![locale.languageCode]!; - String get principalDiagnosisCannot => localizedValues['principalDiagnosisCannot']![locale.languageCode]!; - String get afterOrderCreation => localizedValues['afterOrderCreation']![locale.languageCode]!; - String get principalCoveredOrNot => localizedValues['principalCoveredOrNot']![locale.languageCode]!; - String get complexDiagnosis => localizedValues['complexDiagnosis']![locale.languageCode]!; + String get searchFindSchedule => + localizedValues['searchFindSchedule']![locale.languageCode]!; + + String get onePrimaryDiagnosis => + localizedValues['onePrimaryDiagnosis']![locale.languageCode]!; + + String get principalDiagnosisCannot => + localizedValues['principalDiagnosisCannot']![locale.languageCode]!; + + String get afterOrderCreation => + localizedValues['afterOrderCreation']![locale.languageCode]!; + + String get principalCoveredOrNot => + localizedValues['principalCoveredOrNot']![locale.languageCode]!; + + String get complexDiagnosis => + localizedValues['complexDiagnosis']![locale.languageCode]!; + String get updateAssessmentDetails => localizedValues['updateAssessmentDetails']![locale.languageCode]!; + + String get noComplaintsFound => + localizedValues['noComplaintsFound']![locale.languageCode]!; + + String get addChiefComplaint => + localizedValues['addChiefComplaint']![locale.languageCode]!; + + String get generalList => + localizedValues['generalList']![locale.languageCode]!; + + String get specialList => + localizedValues['specialList']![locale.languageCode]!; + + String get enterChiefCompliants => + localizedValues['enterChiefCompliants']![locale.languageCode]!; + + String get previousChiefCompaints => + localizedValues['previousChiefCompaints']![locale.languageCode]!; + + String get listOfActiveEpisodes => + localizedValues['listOfActiveEpisodes']![locale.languageCode]!; + + String get select => localizedValues['select']![locale.languageCode]!; + + String get noKnownAllergies => localizedValues['noKnownAllergies']![locale.languageCode]!; + String get historyTakenFrom => localizedValues['historyTakenFrom']![locale.languageCode]!; + String get familySpecify => localizedValues['familySpecify']![locale.languageCode]!; + String get otherSpecify => localizedValues['otherSpecify']![locale.languageCode]!; + String get historyOfIllness => localizedValues['historyOfIllness']![locale.languageCode]!; + String get physicalExamination => localizedValues['physicalExamination']![locale.languageCode]!; + String get addPhysicalExamination => localizedValues['addPhysicalExamination']![locale.languageCode]!; + String get noPhysicalExamination => localizedValues['noPhysicalExamination']![locale.languageCode]!; + String get examinationPart => localizedValues['examinationPart']![locale.languageCode]!; + String get resolve => localizedValues['resolve']![locale.languageCode]!; + String get audit => localizedValues['audit']![locale.languageCode]!; + String get delete => localizedValues['delete']![locale.languageCode]!; + String get noProgressNote => localizedValues['noProgressNote']![locale.languageCode]!; + String get patientCondition => localizedValues['patientCondition']![locale.languageCode]!; + String get doctorProgressNote => localizedValues['doctorProgressNote']![locale.languageCode]!; + String get nurseNote => localizedValues['nurseNote']![locale.languageCode]!; + String get progressNoteType => localizedValues['progressNoteType']![locale.languageCode]!; + String get addYourNote => localizedValues['addYourNote']![locale.languageCode]!; + String get saveAsDraft => localizedValues['saveAsDraft']![locale.languageCode]!; + String get mild => localizedValues['mild']![locale.languageCode]!; + String get moderate => localizedValues['moderate']![locale.languageCode]!; + String get currentDiagnosis => localizedValues['currentDiagnosis']![locale.languageCode]!; + String get addNewDiagnosis => localizedValues['addNewDiagnosis']![locale.languageCode]!; + String get noDiagnosisFound => localizedValues['noDiagnosisFound']![locale.languageCode]!; + String get makeCurrentDiagnosis => localizedValues['makeCurrentDiagnosis']![locale.languageCode]!; + String get mappedDiagnosis => localizedValues['mappedDiagnosis']![locale.languageCode]!; + String get previousDiagnosis => localizedValues['previousDiagnosis']![locale.languageCode]!; + String get addDiagnosis => localizedValues['addDiagnosis']![locale.languageCode]!; + String get showAllDiagnosis => localizedValues['showAllDiagnosis']![locale.languageCode]!; + String get acute => localizedValues['acute']![locale.languageCode]!; + String get subAcute => localizedValues['subAcute']![locale.languageCode]!; + String get chronic => localizedValues['chronic']![locale.languageCode]!; + + String get addToFavorite => localizedValues['addToFavorite']![locale.languageCode]!; + String get favoriteDiagnosis => localizedValues['favoriteDiagnosis']![locale.languageCode]!; + String get areYouSureYouWantToDeleteDiagnosis => localizedValues['areYouSureYouWantToDeleteDiagnosis']![locale.languageCode]!; + String get fieldName => localizedValues['fieldName']![locale.languageCode]!; + String get oldValue => localizedValues['oldValue']![locale.languageCode]!; + String get newValue => localizedValues['newValue']![locale.languageCode]!; + String get event => localizedValues['event']![locale.languageCode]!; + String get deletedRemarks => localizedValues['deletedRemarks']![locale.languageCode]!; + String get noRemarks => localizedValues['noRemarks']![locale.languageCode]!; + + String get kindlySelectCategory => localizedValues['kindlySelectCategory']![locale.languageCode]!; + String get remarksCanNotBeEmpty => localizedValues['remarksCanNotBeEmpty']![locale.languageCode]!; + String get selectedDiagnosis => localizedValues['selectedDiagnosis']![locale.languageCode]!; + String get selectConditionFirst => localizedValues['selectConditionFirst']![locale.languageCode]!; + String get editDiagnosis => localizedValues['editDiagnosis']![locale.languageCode]!; + String get noChangeRecorded => localizedValues['noChangeRecorded']![locale.languageCode]!; + + String get activate => localizedValues['activate']![locale.languageCode]!; + String get resolved => localizedValues['resolved']![locale.languageCode]!; + String get selectReaction => localizedValues['selectReaction']![locale.languageCode]!; + String get progressNoteCanNotBeEmpty => localizedValues['progressNoteCanNotBeEmpty']![locale.languageCode]!; + String get diagnosisAlreadyResolved => localizedValues['diagnosisAlreadyResolved']![locale.languageCode]!; + String get diagnosisAlreadyDeleted => localizedValues['diagnosisAlreadyDeleted']![locale.languageCode]!; + } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 148474f0..1db194da 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -349,4 +349,14 @@ class Utils { }); return isVidaPlus; } + + static bool isVidaPlusInPatientProject(ProjectViewModel projectViewModel, int projectID) { + bool isVidaPlusInPatientProject = false; + projectViewModel.vidaPlusInPatientsProjectListModel.forEach((element) { + if (element.projectID == projectID) { + isVidaPlusInPatientProject = true; + } + }); + return isVidaPlusInPatientProject; + } } diff --git a/lib/widgets/auth/sms-popup.dart b/lib/widgets/auth/sms-popup.dart index d555cd56..87f341eb 100644 --- a/lib/widgets/auth/sms-popup.dart +++ b/lib/widgets/auth/sms-popup.dart @@ -7,6 +7,8 @@ import 'package:doctor_app_flutter/icons_app/doctor_app_icons.dart'; import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart'; import 'package:flutter/material.dart'; +import '../../config/config.dart'; +import 'package:cloudflare_turnstile/cloudflare_turnstile.dart'; class SMSOTP { final AuthMethodTypes type; @@ -46,11 +48,20 @@ class SMSOTP { late ProjectViewModel projectProvider; String displayTime = ''; bool isClosed = false; + final TurnstileController _controller = TurnstileController(); + final TurnstileOptions _options = TurnstileOptions( + size: TurnstileSize.normal, + theme: TurnstileTheme.light, + refreshExpired: TurnstileRefreshExpired.manual, + language: 'en', + retryAutomatically: false, + ); + String? _token; displayDialog(BuildContext context) async { double dialogWidth = MediaQuery.of(context).size.width * 0.90; double dialogInputWidth = (dialogWidth / 4) - (SizeConfig.isWidthLarge ? SizeConfig.getWidthMultiplier(width: dialogWidth) * 4.5 : 20); - double dialogHeight = SizeConfig.isHeightVeryShort ? MediaQuery.of(context).size.height * 0.50 : MediaQuery.of(context).size.height * 0.40; + double dialogHeight = SizeConfig.isHeightVeryShort ? MediaQuery.of(context).size.height * 0.60 : MediaQuery.of(context).size.height * 0.50; return showDialog( context: context, builder: (ctx) => Center( @@ -126,7 +137,7 @@ class SMSOTP { children: [ Container( width: dialogInputWidth, - height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 30, + height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 25, margin: EdgeInsets.symmetric(vertical: 2, horizontal: 5), child: TextFormField( textInputAction: TextInputAction.next, @@ -153,7 +164,7 @@ class SMSOTP { ), Container( width: dialogInputWidth, - height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 30, + height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 25, margin: EdgeInsets.symmetric(vertical: 2, horizontal: 5), child: TextFormField( focusNode: focusD2, @@ -183,7 +194,7 @@ class SMSOTP { Container( margin: EdgeInsets.symmetric(vertical: 2, horizontal: 5), width: dialogInputWidth, - height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 30, + height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 25, child: TextFormField( focusNode: focusD3, textInputAction: TextInputAction.next, @@ -211,7 +222,7 @@ class SMSOTP { Container( margin: EdgeInsets.symmetric(vertical: 2, horizontal: 5), width: dialogInputWidth, - height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 30, + height: SizeConfig.getHeightMultiplier(height: dialogHeight) * 25, child: TextFormField( focusNode: focusD4, maxLength: 1, @@ -235,6 +246,7 @@ class SMSOTP { )), ), ), + Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ AppText( TranslationBase.of(context).validationMessage + ' ', @@ -251,7 +263,35 @@ class SMSOTP { fontWeight: FontWeight.bold, fontSize: SizeConfig.getTextMultiplierBasedOnWidth(width: dialogWidth) * 3.5, ) - ]) + ]), + SizedBox(height: 10,), + Column(children: [ + CloudflareTurnstile( + siteKey: '0x4AAAAAAAkmbvEy63pcxBBt', + baseUrl: BASE_URL, + options: _options, + controller: _controller, + onTokenReceived: (token) { + setState(() { + print("Cloudflare token: $token"); + //todo pass this token to checkActivcationCode + _token = token; + checkValue(); + }); + }, + // onTokenRecived: (token) { + // setState(() { + // print("Cloudflare token: $token"); + // _token = token; + // }); + // }, + onTokenExpired: () {}, + // mode: TurnstileMode.managed, + // errorBuilder: (context, error) { + // return Text(error.message); + // }, + ), + ],), ], ), ), @@ -304,7 +344,7 @@ class SMSOTP { } checkValue() async { - if (verifyAccountForm.currentState!.validate()) { + if (verifyAccountForm.currentState!.validate() ) { //&& _token !=null removed cloud flare for vida plus // if (digit1.text.isNotEmpty && digit2.text.isNotEmpty && digit3.text.isNotEmpty && digit4.text.isNotEmpty) { onSuccess(digit1.text.toString() + digit2.text.toString() + digit3.text.toString() + digit4.text.toString()); this.isClosed = true; diff --git a/lib/widgets/bottom_sheet/custom_bottom_sheet_container.dart b/lib/widgets/bottom_sheet/custom_bottom_sheet_container.dart index 2f5e7c62..52e2a1d7 100644 --- a/lib/widgets/bottom_sheet/custom_bottom_sheet_container.dart +++ b/lib/widgets/bottom_sheet/custom_bottom_sheet_container.dart @@ -8,10 +8,12 @@ import '../../config/config.dart'; class CustomBottomSheetContainer extends StatelessWidget { final Function() onTap; final String label; - + final Color? buttonColor; + final Color? fontColor; + final double? widthFactor; double headerHeight = SizeConfig.heightMultiplier! * 12; - CustomBottomSheetContainer({Key? key, required this.onTap, required this.label}) : super(key: key); + CustomBottomSheetContainer({Key? key, required this.onTap, required this.label, this.buttonColor = const Color(0xFF359846) , this.fontColor = Colors.white, this.widthFactor = .80 }) : super(key: key); @override Widget build(BuildContext context) { @@ -30,11 +32,12 @@ class CustomBottomSheetContainer extends StatelessWidget { Container( margin: EdgeInsets.only(top: headerHeight * (SizeConfig.isWidthLarge ? 0.3 : 0.2)), child: FractionallySizedBox( - widthFactor: .80, + widthFactor: widthFactor, child: Center( child: AppButton( + fontColor: fontColor!, title: label, - color: AppGlobal.appGreenColor, + color: this.buttonColor , onPressed: onTap, ), ), diff --git a/lib/widgets/data_display/list/flexible_container.dart b/lib/widgets/data_display/list/flexible_container.dart index 4e4d63b3..7bd95a5b 100644 --- a/lib/widgets/data_display/list/flexible_container.dart +++ b/lib/widgets/data_display/list/flexible_container.dart @@ -34,7 +34,7 @@ class FlexibleContainer extends StatelessWidget { child: ClipRRect( borderRadius: BorderRadius.circular(8.0), child: Material( - color: Theme.of(context).backgroundColor, + // color: Theme.of(context).backgroundColor, child: Container( padding: padding, width: double.infinity, diff --git a/lib/widgets/dialog/AskPermissionDialog.dart b/lib/widgets/dialog/AskPermissionDialog.dart index 8b7eacb3..3c3d74ba 100644 --- a/lib/widgets/dialog/AskPermissionDialog.dart +++ b/lib/widgets/dialog/AskPermissionDialog.dart @@ -70,7 +70,7 @@ class _AskPermissionDialogState extends State { height: MediaQuery.of(context).size.height / 6, ), AppButton( - fontColor: Theme.of(context).backgroundColor, + // fontColor: Theme.of(context).backgroundColor, color: Colors.red[700]!, title: "Turn On Camera, Microphone", onPressed: () async { diff --git a/lib/widgets/patients/profile/profile_medical_info_widget_search.dart b/lib/widgets/patients/profile/profile_medical_info_widget_search.dart index d20a414a..464fb689 100644 --- a/lib/widgets/patients/profile/profile_medical_info_widget_search.dart +++ b/lib/widgets/patients/profile/profile_medical_info_widget_search.dart @@ -62,7 +62,9 @@ class _ProfileMedicalInfoWidgetSearchState extends State { TextStyle? _getFontStyle() { switch (widget.style) { case "headline2": - return Theme.of(context).textTheme.headline2; + return Theme.of(context).textTheme.headlineSmall; case "headline3": - return Theme.of(context).textTheme.headline3; + return Theme.of(context).textTheme.headlineSmall; case "headline4": - return Theme.of(context).textTheme.headline4; + return Theme.of(context).textTheme.headlineMedium; case "headline5": - return Theme.of(context).textTheme.headline5; + return Theme.of(context).textTheme.headlineMedium; case "headline6": - return Theme.of(context).textTheme.headline6; + return Theme.of(context).textTheme.headlineLarge; case "bodyText2": - return Theme.of(context).textTheme.bodyText2; + return Theme.of(context).textTheme.bodyMedium; case "bodyText_15": - return Theme.of(context).textTheme.bodyText2!.copyWith(fontSize: 15.0); + return Theme.of(context).textTheme.bodyLarge!.copyWith(fontSize: 15.0); case "bodyText1": - return Theme.of(context).textTheme.bodyText1; + return Theme.of(context).textTheme.bodySmall; case "caption": - return Theme.of(context).textTheme.caption; + return Theme.of(context).textTheme.displayMedium; case "overline": - return Theme.of(context).textTheme.overline; + return Theme.of(context).textTheme.displaySmall; case "button": - return Theme.of(context).textTheme.button; + return Theme.of(context).textTheme.displayMedium; default: return TextStyle(fontSize: 5); } diff --git a/lib/widgets/shared/buttons/app_buttons_widget.dart b/lib/widgets/shared/buttons/app_buttons_widget.dart index a30f0193..0ab825f8 100644 --- a/lib/widgets/shared/buttons/app_buttons_widget.dart +++ b/lib/widgets/shared/buttons/app_buttons_widget.dart @@ -22,7 +22,7 @@ class AppButton extends StatefulWidget { final double vPadding; final double hPadding; final double height; - + final double elevation; AppButton({ required this.onPressed, this.title = '', @@ -41,6 +41,7 @@ class AppButton extends StatefulWidget { this.hasBorder = false, this.borderColor = Colors.white, this.height = 50, + this.elevation =2.0 }); _AppButtonState createState() => _AppButtonState(); @@ -69,6 +70,7 @@ class _AppButtonState extends State { child: IgnorePointer( ignoring: widget.loading || widget.disabled, child: RawMaterialButton( + elevation: widget.elevation, fillColor: widget.disabled ? Colors.grey : widget.color != null diff --git a/lib/widgets/shared/loader/gif_loader_container.dart b/lib/widgets/shared/loader/gif_loader_container.dart index 8f315d6a..3871892f 100644 --- a/lib/widgets/shared/loader/gif_loader_container.dart +++ b/lib/widgets/shared/loader/gif_loader_container.dart @@ -14,8 +14,7 @@ class _GifLoaderContainerState extends State with TickerProv controller1 = GifController(vsync: this); WidgetsBinding.instance.addPostFrameCallback((_) { - // controller1.repeat( - // min: 0, max: 11, period: Duration(milliseconds: 750), reverse: true); + controller1.repeat(period: Duration(milliseconds: 750), reverse: true); }); super.initState(); } diff --git a/lib/widgets/shared/text_fields/TextFields.dart b/lib/widgets/shared/text_fields/TextFields.dart index 7e4a832e..8bf82589 100644 --- a/lib/widgets/shared/text_fields/TextFields.dart +++ b/lib/widgets/shared/text_fields/TextFields.dart @@ -251,7 +251,7 @@ class _TextFieldsState extends State { autofocus: widget.autoFocus ?? false, validator: widget.validator, onSaved: widget.onSaved, - style: Theme.of(context).textTheme.bodyText1!.copyWith(fontSize: widget.fontSize, fontWeight: widget.fontWeight), + style: Theme.of(context).textTheme.bodySmall!.copyWith(fontSize: widget.fontSize, fontWeight: widget.fontWeight), inputFormatters: widget.keyboardType == TextInputType.phone ? [ // WhitelistingTextInputFormatter.digitsOnly, @@ -274,16 +274,16 @@ class _TextFieldsState extends State { ), contentPadding: widget.padding != null ? widget.padding : EdgeInsets.symmetric(vertical: (widget.bare && !widget.keepPadding) ? 0.0 : 10.0, horizontal: 16.0), filled: true, - fillColor: widget.bare ? Colors.transparent : Theme.of(context).backgroundColor, + // fillColor: widget.bare ? Colors.transparent : Theme.of(context).backgroundColor, suffixIcon: _buildSuffixIcon(), prefixIcon: widget.prefixIcon, errorStyle: TextStyle(fontSize: 12.0, fontWeight: widget.fontWeight, height: widget.borderOnlyError ? 0.0 : null), errorBorder: OutlineInputBorder( - borderSide: widget.hasBorder ? BorderSide(color: Theme.of(context).errorColor.withOpacity(widget.bare ? 0.0 : 0.5), width: 1.0) : BorderSide(color: Colors.transparent, width: 0), + borderSide: widget.hasBorder ? BorderSide(color:Colors.red.withOpacity(widget.bare ? 0.0 : 0.5), width: 1.0) : BorderSide(color: Colors.transparent, width: 0), borderRadius: widget.hasBorder ? BorderRadius.circular(widget.bare ? 0.0 : widget.borderRadius) : BorderRadius.circular(0.0), ), focusedErrorBorder: OutlineInputBorder( - borderSide: widget.hasBorder ? BorderSide(color: Theme.of(context).errorColor.withOpacity(widget.bare ? 0.0 : 0.5), width: 1.0) : BorderSide(color: Colors.transparent, width: 0), + borderSide: widget.hasBorder ? BorderSide(color: Colors.red.withOpacity(widget.bare ? 0.0 : 0.5), width: 1.0) : BorderSide(color: Colors.transparent, width: 0), borderRadius: BorderRadius.circular(widget.bare ? 0.0 : widget.borderRadius)), focusedBorder: OutlineInputBorder( borderSide: widget.hasBorder ? BorderSide(color: widget.borderColor!, width: widget.borderWidth) : BorderSide(color: Colors.transparent, width: 0), diff --git a/lib/widgets/shared/text_fields/app-textfield-custom.dart b/lib/widgets/shared/text_fields/app-textfield-custom.dart index a15a585f..93aef94d 100644 --- a/lib/widgets/shared/text_fields/app-textfield-custom.dart +++ b/lib/widgets/shared/text_fields/app-textfield-custom.dart @@ -18,6 +18,7 @@ class AppTextFieldCustom extends StatefulWidget { final bool hasBorder; final String? dropDownText; final IconButton? suffixIcon; + final Widget? suffixWidget; final Color? dropDownColor; final bool enabled; final TextInputType? inputType; @@ -26,6 +27,7 @@ class AppTextFieldCustom extends StatefulWidget { final List? inputFormatters; final Function(String? value) onChanged; final Function() onFieldSubmitted; + final VoidCallback? onEditingComplete; final String? validationError; final bool isPrscription; @@ -42,6 +44,7 @@ class AppTextFieldCustom extends StatefulWidget { this.isTextFieldHasSuffix = false, this.dropDownText, this.suffixIcon, + this.suffixWidget, this.dropDownColor, this.enabled = true, this.inputType, @@ -55,6 +58,7 @@ class AppTextFieldCustom extends StatefulWidget { this.focus = false, this.isSearchTextField = false, required this.onFieldSubmitted, + this.onEditingComplete }); @override @@ -84,26 +88,32 @@ class _AppTextFieldCustomState extends State { @override void dispose() { - // _focusNode.dispose(); + // _focusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { ProjectViewModel projectViewModel = Provider.of(context); - TextInputType localKeyboardType = widget.inputType ?? (widget.maxLines == 1 ? TextInputType.text : TextInputType.multiline); + TextInputType localKeyboardType = widget.inputType ?? + (widget.maxLines == 1 ? TextInputType.text : TextInputType.multiline); return Column( children: [ Container( - height: widget.height != 0 && widget.maxLines == 1 ? widget.height + 8 : null, //MediaQuery.of(context).size.height * 0.098, + height: widget.height != 0 && widget.maxLines == 1 + ? widget.height + 8 + : null, //MediaQuery.of(context).size.height * 0.098, decoration: widget.hasBorder ? TextFieldsUtils.containerBorderDecoration( Color(0Xffffffff), - widget.validationError == null ? Color(0xFFEFEFEF) : Colors.red.shade700, + widget.validationError == null + ? Color(0xFFEFEFEF) + : Colors.red.shade700, ) : null, - padding: EdgeInsets.only(top: 4.0, bottom: 0.0, left: 8.0, right: 8.0), + padding: + EdgeInsets.only(top: 4.0, bottom: 0.0, left: 8.0, right: 8.0), child: InkWell( onTap: widget.onClick, child: Row( @@ -130,25 +140,44 @@ class _AppTextFieldCustomState extends State { ), widget.dropDownText == null ? Container( - height: widget.height != 0 && widget.maxLines == 1 ? widget.height - 22 : null, + height: + widget.height != 0 && widget.maxLines == 1 + ? widget.height - 22 + : null, child: RawKeyboardListener( focusNode: FocusNode(), autofocus: false, onKey: (rawKeyEvent) { - final isFormSkippedEnterEvent = rawKeyEvent is RawKeyDownEvent && rawKeyEvent.isKeyPressed(LogicalKeyboardKey.enter); + final isFormSkippedEnterEvent = + rawKeyEvent is RawKeyDownEvent && + rawKeyEvent.isKeyPressed( + LogicalKeyboardKey.enter); - final needToInsertNewLine = isFormSkippedEnterEvent && localKeyboardType == TextInputType.multiline; + final needToInsertNewLine = + isFormSkippedEnterEvent && + localKeyboardType == + TextInputType.multiline; if (needToInsertNewLine) { - TextEditingControllerHelper.insertText(widget.controller!, '\n'); + TextEditingControllerHelper.insertText( + widget.controller!, '\n'); } }, child: TextFormField( - textAlign: projectViewModel.isArabic ? TextAlign.right : TextAlign.left, + textInputAction: TextInputAction.search, + onEditingComplete: (){ + widget.onEditingComplete?.call(); + }, + textAlign: projectViewModel.isArabic + ? TextAlign.right + : TextAlign.left, focusNode: _focusNode, textAlignVertical: TextAlignVertical.top, - decoration: TextFieldsUtils.textFieldSelectorDecoration(widget.hintText!, "", true), + decoration: TextFieldsUtils + .textFieldSelectorDecoration( + widget.hintText!, "", true), style: TextStyle( - fontSize: SizeConfig.textMultiplier! * 1.7, + fontSize: + SizeConfig.textMultiplier! * 1.7, fontFamily: 'Poppins', color: Color(0xFF575757), fontWeight: FontWeight.w400, @@ -159,14 +188,19 @@ class _AppTextFieldCustomState extends State { enabled: widget.enabled, minLines: widget.minLines, maxLines: widget.maxLines, - inputFormatters: widget.inputFormatters != null ? widget.inputFormatters : [], + inputFormatters: + widget.inputFormatters != null + ? widget.inputFormatters + : [], onChanged: (value) { if (widget.onChanged != null) { widget.onChanged(value); } setState(() {}); }, - onFieldSubmitted: widget.onFieldSubmitted(), + + onFieldSubmitted: + widget.onFieldSubmitted(), obscureText: widget.isSecure), ), ) @@ -185,7 +219,8 @@ class _AppTextFieldCustomState extends State { ? Container( margin: EdgeInsets.only( bottom: widget.isSearchTextField - ? (widget.controller!.text.isEmpty || widget.controller == null) + ? (widget.controller!.text.isEmpty || + widget.controller == null) ? 10 : 25 : 0), @@ -193,16 +228,22 @@ class _AppTextFieldCustomState extends State { : InkWell( child: Icon( Icons.keyboard_arrow_down, - color: widget.dropDownColor != null ? widget.dropDownColor : Color(0xff2E303A), + color: widget.dropDownColor != null + ? widget.dropDownColor + : Color(0xff2E303A), size: 12.0, ), ) - : Container(), + : widget.suffixWidget != null + ? widget.suffixWidget ?? SizedBox.shrink() + : Container(), ], ), ), ), - if (widget.validationError != null && widget.validationError!.isNotEmpty) TextFieldsError(error: widget.validationError!), + if (widget.validationError != null && + widget.validationError!.isNotEmpty) + TextFieldsError(error: widget.validationError!), ], ); } @@ -218,7 +259,8 @@ class TextEditingControllerHelper { } final text = controller.text; - final newText = text.replaceRange(selection.start, selection.end, textToInsert); + final newText = + text.replaceRange(selection.start, selection.end, textToInsert); controller.value = controller.value.copyWith( text: newText, selection: TextSelection.collapsed( diff --git a/lib/widgets/shared/user-guid/CusomRow.dart b/lib/widgets/shared/user-guid/CusomRow.dart index aea3b1e8..3dcb57d8 100644 --- a/lib/widgets/shared/user-guid/CusomRow.dart +++ b/lib/widgets/shared/user-guid/CusomRow.dart @@ -42,16 +42,13 @@ class CustomRow extends StatelessWidget { SizedBox( width: 1, ), - Expanded( - flex: isExpanded ? 1 : 0, - child: AppText( - value, - fontSize: valueSize ?? SizeConfig.getTextMultiplierBasedOnWidth() * 2.9, - color: valueColor ?? Color(0xFF2B353E), - fontWeight: FontWeight.w700, - letterSpacing: -0.48, - isCopyable: isCopyable, - ), + AppText( + value, + fontSize: valueSize ?? SizeConfig.getTextMultiplierBasedOnWidth() * 2.9, + color: valueColor ?? Color(0xFF2B353E), + fontWeight: FontWeight.w700, + letterSpacing: -0.48, + isCopyable: isCopyable, ), ], ); diff --git a/lib/widgets/shared/user-guid/custom_validation_error.dart b/lib/widgets/shared/user-guid/custom_validation_error.dart index 6154255d..b4517861 100644 --- a/lib/widgets/shared/user-guid/custom_validation_error.dart +++ b/lib/widgets/shared/user-guid/custom_validation_error.dart @@ -23,7 +23,7 @@ class CustomValidationError extends StatelessWidget { margin: EdgeInsets.symmetric(horizontal: 3), child: AppText( error, - color: Theme.of(context).errorColor, + color: Colors.red, fontSize: 14, ), ), diff --git a/linux/.gitignore b/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt new file mode 100644 index 00000000..2bce06eb --- /dev/null +++ b/linux/CMakeLists.txt @@ -0,0 +1,145 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "doctor_app_flutter") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.hmg.doctor_app_flutter") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/CMakeLists.txt b/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..dbec55e5 --- /dev/null +++ b/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) maps_launcher_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "MapsLauncherPlugin"); + maps_launcher_plugin_register_with_registrar(maps_launcher_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); +} diff --git a/linux/flutter/generated_plugin_registrant.h b/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..6c56d5b0 --- /dev/null +++ b/linux/flutter/generated_plugins.cmake @@ -0,0 +1,25 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + maps_launcher + url_launcher_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/linux/main.cc b/linux/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/my_application.cc b/linux/my_application.cc new file mode 100644 index 00000000..626c7fd5 --- /dev/null +++ b/linux/my_application.cc @@ -0,0 +1,124 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "doctor_app_flutter"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "doctor_app_flutter"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/linux/my_application.h b/linux/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/macos/.gitignore b/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..d9cacc88 --- /dev/null +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,32 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import connectivity_macos +import firebase_analytics +import firebase_core +import firebase_messaging +import flutter_inappwebview_macos +import maps_launcher +import path_provider_foundation +import shared_preferences_foundation +import speech_to_text_macos +import sqflite_darwin +import url_launcher_macos + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) + FLTFirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAnalyticsPlugin")) + FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) + InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) + MapsLauncherPlugin.register(with: registry.registrar(forPlugin: "MapsLauncherPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SpeechToTextMacosPlugin.register(with: registry.registrar(forPlugin: "SpeechToTextMacosPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) +} diff --git a/macos/Podfile b/macos/Podfile new file mode 100644 index 00000000..c795730d --- /dev/null +++ b/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# 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', 'ephemeral', '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 Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..5595a9da --- /dev/null +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,705 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* doctor_app_flutter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "doctor_app_flutter.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* doctor_app_flutter.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* doctor_app_flutter.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.hmg.doctorAppFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/doctor_app_flutter.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/doctor_app_flutter"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.hmg.doctorAppFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/doctor_app_flutter.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/doctor_app_flutter"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.hmg.doctorAppFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/doctor_app_flutter.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/doctor_app_flutter"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + 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_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + 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_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + 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_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + 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_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner.xcworkspace/contents.xcworkspacedata b/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..d53ef643 --- /dev/null +++ b/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/macos/Runner/Base.lproj/MainMenu.xib b/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..4a0df9a9 --- /dev/null +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = doctor_app_flutter + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.hmg.doctorAppFlutter + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2024 com.hmg. All rights reserved. diff --git a/macos/Runner/Configs/Debug.xcconfig b/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Release.xcconfig b/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Warnings.xcconfig b/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/macos/Runner/DebugProfile.entitlements b/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/macos/Runner/MainFlutterWindow.swift b/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/macos/Runner/Release.entitlements b/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/macos/RunnerTests/RunnerTests.swift b/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..5418c9f5 --- /dev/null +++ b/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/pubspec.lock b/pubspec.lock index e69de29b..a13ac622 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -0,0 +1,1815 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + url: "https://pub.dev" + source: hosted + version: "64.0.0" + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: "4eec93681221723a686ad580c2e7d960e1017cf1a4e0a263c2573c2c6b0bf5cd" + url: "https://pub.dev" + source: hosted + version: "1.3.25" + adaptive_number: + dependency: transitive + description: + name: adaptive_number + sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + url: "https://pub.dev" + source: hosted + version: "6.2.0" + archive: + dependency: transitive + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" + args: + dependency: transitive + description: + name: args + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + url: "https://pub.dev" + source: hosted + version: "2.5.0" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + autocomplete_textfield: + dependency: "direct main" + description: + name: autocomplete_textfield + sha256: "8170e66d381c21623f1cfbb957ab9c6b5a45d9c50a6daac7fc57dbc3ba94abb4" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + badges: + dependency: "direct main" + description: + name: badges + sha256: a7b6bbd60dce418df0db3058b53f9d083c22cdb5132a052145dc267494df0b84 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + barcode_scan2: + dependency: "direct main" + description: + name: barcode_scan2 + sha256: a2ab566027cd57b2795ea42aa26835dbaa8fe70bcc1aff54942a14d3705dff97 + url: "https://pub.dev" + source: hosted + version: "4.3.3" + bazel_worker: + dependency: transitive + description: + name: bazel_worker + sha256: "4eef19cc486c289e4b06c69d0f6f3192e85cc93c25d4d15d02afb205e388d2f0" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + url: "https://pub.dev" + source: hosted + version: "4.0.1" + build_modules: + dependency: transitive + description: + name: build_modules + sha256: "9987d67a29081872e730468295fc565e9a2b377ca3673337c1d4e41d57c6cd7c" + url: "https://pub.dev" + source: hosted + version: "5.0.8" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" + url: "https://pub.dev" + source: hosted + version: "2.4.9" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" + url: "https://pub.dev" + source: hosted + version: "7.3.0" + build_web_compilers: + dependency: "direct dev" + description: + name: build_web_compilers + sha256: "9071a94aa67787cebdd9e76837c9d2af61fb5242db541244f6a0b6249afafb46" + url: "https://pub.dev" + source: hosted + version: "4.0.10" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + url: "https://pub.dev" + source: hosted + version: "8.9.2" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "205d6a9f1862de34b93184f22b9d2d94586b2f05c581d546695e3d8f6a805cd7" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + charts_common: + dependency: transitive + description: + name: charts_common + sha256: "7b8922f9b0d9b134122756a787dab1c3946ae4f3fc5022ff323ba0014998ea02" + url: "https://pub.dev" + source: hosted + version: "0.12.0" + charts_flutter: + dependency: "direct main" + description: + name: charts_flutter + sha256: "4172c3f4b85322fdffe1896ffbed79ae4689ae72cb6fe6690dcaaea620a9c558" + url: "https://pub.dev" + source: hosted + version: "0.12.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + cloudflare_turnstile: + dependency: "direct main" + description: + name: cloudflare_turnstile + sha256: "3f11c0e7336b266e4eb4e594e7603972902832e10ace004a2c710e93abb81bfe" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + url: "https://pub.dev" + source: hosted + version: "4.10.0" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + connectivity: + dependency: "direct main" + description: + name: connectivity + sha256: a8e91263cf3e25fb5cc95e19dfde4999e32a648ac3b9e8a558a28165731678f8 + url: "https://pub.dev" + source: hosted + version: "3.0.6" + connectivity_for_web: + dependency: transitive + description: + name: connectivity_for_web + sha256: "01a390c1d5adc2ed1fa1f52d120c07fe9fd01166a93f965a832fd6cfc0ea6482" + url: "https://pub.dev" + source: hosted + version: "0.4.0+1" + connectivity_macos: + dependency: transitive + description: + name: connectivity_macos + sha256: "51ae08d5162eca9669b9d8951ed83ce19c5355a81149f94e4dee2740beb93628" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + connectivity_platform_interface: + dependency: transitive + description: + name: connectivity_platform_interface + sha256: "2d82e942df9d49f29a24bb07fb5ce085d4a53e47818c62364d2b6deb9e0d7a8e" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f" + url: "https://pub.dev" + source: hosted + version: "0.17.3" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + dart_jsonwebtoken: + dependency: "direct main" + description: + name: dart_jsonwebtoken + sha256: "866787dc17afaef46a9ea7dd33eefe60c6d82084b4a36d70e8e788d091cd04ef" + url: "https://pub.dev" + source: hosted + version: "2.14.2" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + date_time_picker: + dependency: "direct main" + description: + name: date_time_picker + sha256: "6923c568bcb67a66ab7e083708d0adbcae8214b41bb84d49febc17e89e06fc4a" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + dropdown_search: + dependency: "direct main" + description: + name: dropdown_search + sha256: "55106e8290acaa97ed15bea1fdad82c3cf0c248dd410e651f5a8ac6870f783ab" + url: "https://pub.dev" + source: hosted + version: "5.0.6" + ed25519_edwards: + dependency: transitive + description: + name: ed25519_edwards + sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + equatable: + dependency: transitive + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" + eva_icons_flutter: + dependency: "direct main" + description: + name: eva_icons_flutter + sha256: "6d48a10b93590ab83eb092bee5adacdeb14f3d83f527a4b9e4092c363d56e2a8" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + events_emitter: + dependency: transitive + description: + name: events_emitter + sha256: a075477bdf9c8c0c31bb7c7b7bdd357b4486c34f30163119f96de4e7f54abeff + url: "https://pub.dev" + source: hosted + version: "0.5.2" + expandable: + dependency: "direct main" + description: + name: expandable + sha256: "9604d612d4d1146dafa96c6d8eec9c2ff0994658d6d09fed720ab788c7f5afc2" + url: "https://pub.dev" + source: hosted + version: "5.0.1" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: aac85f20436608e01a6ffd1fdd4e746a7f33c93a2c83752e626bdfaea139b877 + url: "https://pub.dev" + source: hosted + version: "8.1.3" + firebase_analytics: + dependency: "direct main" + description: + name: firebase_analytics + sha256: b13cbf1ee78744ca5e6b762e9218db3bd3967a0edfed75f58339907892a2ccb9 + url: "https://pub.dev" + source: hosted + version: "10.8.9" + firebase_analytics_platform_interface: + dependency: transitive + description: + name: firebase_analytics_platform_interface + sha256: "416b33d62033db5ecd2df719fcb657ad04e9995fa0fc392ffdab4ca0e76cb679" + url: "https://pub.dev" + source: hosted + version: "3.9.9" + firebase_analytics_web: + dependency: transitive + description: + name: firebase_analytics_web + sha256: "9dca9d8d468172444ef18cabb73fe99f7aae24733bfad67115bd36bffd2d65c1" + url: "https://pub.dev" + source: hosted + version: "0.5.5+21" + firebase_core: + dependency: transitive + description: + name: firebase_core + sha256: "53316975310c8af75a96e365f9fccb67d1c544ef0acdbf0d88bbe30eedd1c4f9" + url: "https://pub.dev" + source: hosted + version: "2.27.0" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: f7d7180c7f99babd4b4c517754d41a09a4943a0f7a69b65c894ca5c68ba66315 + url: "https://pub.dev" + source: hosted + version: "5.2.1" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: f4ee170441ca141c5f9ee5ad8737daba3ee9c8e7efb6902aee90b4fbd178ce25 + url: "https://pub.dev" + source: hosted + version: "2.18.0" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + sha256: "980259425fa5e2afc03e533f33723335731d21a56fd255611083bceebf4373a8" + url: "https://pub.dev" + source: hosted + version: "14.7.10" + firebase_messaging_platform_interface: + dependency: transitive + description: + name: firebase_messaging_platform_interface + sha256: f7a9d74ff7fc588a924f6b2eaeaa148b0db521b13a9db55f6ad45864fa98c06e + url: "https://pub.dev" + source: hosted + version: "4.5.27" + firebase_messaging_web: + dependency: transitive + description: + name: firebase_messaging_web + sha256: "90dc7ed885e90a24bb0e56d661d4d2b5f84429697fd2cbb9e5890a0ca370e6f4" + url: "https://pub.dev" + source: hosted + version: "3.5.18" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + fl_chart: + dependency: "direct main" + description: + name: fl_chart + sha256: "5a74434cc83bf64346efb562f1a06eefaf1bcb530dc3d96a104f631a1eff8d79" + url: "https://pub.dev" + source: hosted + version: "0.65.0" + flex_color_picker: + dependency: transitive + description: + name: flex_color_picker + sha256: "5c846437069fb7afdd7ade6bf37e628a71d2ab0787095ddcb1253bf9345d5f3a" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + flex_seed_scheme: + dependency: transitive + description: + name: flex_seed_scheme + sha256: "4cee2f1d07259f77e8b36f4ec5f35499d19e74e17c7dce5b819554914082bc01" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + flutter_colorpicker: + dependency: "direct main" + description: + name: flutter_colorpicker + sha256: "969de5f6f9e2a570ac660fb7b501551451ea2a1ab9e2097e89475f60e07816ea" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + flutter_datetime_picker_plus: + dependency: "direct main" + description: + name: flutter_datetime_picker_plus + sha256: "7d82da02c4e070bb28a9107de119ad195e2319b45c786fecc13482a9ffcc51da" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + flutter_device_type: + dependency: "direct main" + description: + name: flutter_device_type + sha256: "8f41f2271733f615957924dd1dcd10ef90848bb86b603ae20578f91591b900f3" + url: "https://pub.dev" + source: hosted + version: "0.4.0" + flutter_hooks: + dependency: transitive + description: + name: flutter_hooks + sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70 + url: "https://pub.dev" + source: hosted + version: "0.20.5" + flutter_html: + dependency: "direct main" + description: + name: flutter_html + sha256: "02ad69e813ecfc0728a455e4bf892b9379983e050722b1dce00192ee2e41d1ee" + url: "https://pub.dev" + source: hosted + version: "3.0.0-beta.2" + flutter_inappwebview: + dependency: transitive + description: + name: flutter_inappwebview + sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" + url: "https://pub.dev" + source: hosted + version: "6.1.5" + flutter_inappwebview_android: + dependency: transitive + description: + name: flutter_inappwebview_android + sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" + url: "https://pub.dev" + source: hosted + version: "1.1.3" + flutter_inappwebview_internal_annotations: + dependency: transitive + description: + name: flutter_inappwebview_internal_annotations + sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_inappwebview_ios: + dependency: transitive + description: + name: flutter_inappwebview_ios + sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_macos: + dependency: transitive + description: + name: flutter_inappwebview_macos + sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_platform_interface: + dependency: transitive + description: + name: flutter_inappwebview_platform_interface + sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 + url: "https://pub.dev" + source: hosted + version: "1.3.0+1" + flutter_inappwebview_web: + dependency: transitive + description: + name: flutter_inappwebview_web + sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_windows: + dependency: transitive + description: + name: flutter_inappwebview_windows + sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + flutter_keyboard_visibility: + dependency: transitive + description: + name: flutter_keyboard_visibility + sha256: "98664be7be0e3ffca00de50f7f6a287ab62c763fc8c762e0a21584584a3ff4f8" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_keyboard_visibility_linux: + dependency: transitive + description: + name: flutter_keyboard_visibility_linux + sha256: "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_keyboard_visibility_macos: + dependency: transitive + description: + name: flutter_keyboard_visibility_macos + sha256: c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_keyboard_visibility_platform_interface: + dependency: transitive + description: + name: flutter_keyboard_visibility_platform_interface + sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_web: + dependency: transitive + description: + name: flutter_keyboard_visibility_web + sha256: d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_windows: + dependency: transitive + description: + name: flutter_keyboard_visibility_windows + sha256: fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_localizations: + dependency: "direct overridden" + description: flutter + source: sdk + version: "0.0.0" + flutter_math_fork: + dependency: "direct main" + description: + name: flutter_math_fork + sha256: "94bee4642892a94939af0748c6a7de0ff8318feee588379dcdfea7dc5cba06c8" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" + url: "https://pub.dev" + source: hosted + version: "2.0.19" + flutter_staggered_grid_view: + dependency: "direct main" + description: + name: flutter_staggered_grid_view + sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" + url: "https://pub.dev" + source: hosted + version: "2.0.10+1" + flutter_swiper_view: + dependency: "direct main" + description: + name: flutter_swiper_view + sha256: "2a165b259e8a4c49d4da5626b967ed42a73dac2d075bd9e266ad8d23b9f01879" + url: "https://pub.dev" + source: hosted + version: "1.1.8" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_zoom_videosdk: + dependency: "direct main" + description: + name: flutter_zoom_videosdk + sha256: bb800c733c3a0a31909b2834922e75e089108980154ba1e60ef881c0e21b8802 + url: "https://pub.dev" + source: hosted + version: "1.12.10" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66" + url: "https://pub.dev" + source: hosted + version: "8.2.5" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + sha256: "275ff26905134bcb59417cf60ad979136f1f8257f2f449914b2c3e05bbb4cd6f" + url: "https://pub.dev" + source: hosted + version: "10.7.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7 + url: "https://pub.dev" + source: hosted + version: "7.6.7" + gif: + dependency: "direct main" + description: + name: gif + sha256: ade95694f1471da737922806818ffade2814d1d7f8d10af38ebcf36ace012bc0 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + hexcolor: + dependency: "direct main" + description: + name: hexcolor + sha256: c07f4bbb9095df87eeca87e7c69e8c3d60f70c66102d7b8d61c4af0453add3f6 + url: "https://pub.dev" + source: hosted + version: "3.0.1" + hijri: + dependency: transitive + description: + name: hijri + sha256: "203eb7341e32789af6429877e88411b1526ef44c5d157ce4d3b930dd32c37ef1" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + hijri_picker: + dependency: "direct main" + description: + name: hijri_picker + sha256: "15dd1716f3bd0b72122a71740b3ec9bc623463b11e0c907602d2b7598f851984" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + html: + dependency: "direct main" + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" + html_editor_enhanced: + dependency: "direct main" + description: + name: html_editor_enhanced + sha256: "5ae6cd965cca77f7186efccc47ca353799e831b31bd71438687a56131bbcd3a5" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + http: + dependency: "direct main" + description: + name: http + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + url: "https://pub.dev" + source: hosted + version: "1.2.2" + http_interceptor: + dependency: "direct main" + description: + name: http_interceptor + sha256: fc7eedc62433c17612bf65237a8aa2615553cc9130f1e4d75f7e5fa364d5232e + url: "https://pub.dev" + source: hosted + version: "2.0.0-beta.8" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + infinite_listview: + dependency: transitive + description: + name: infinite_listview + sha256: f6062c1720eb59be553dfa6b89813d3e8dd2f054538445aaa5edaddfa5195ce6 + url: "https://pub.dev" + source: hosted + version: "1.1.0" + intl: + dependency: "direct overridden" + description: + name: intl + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.dev" + source: hosted + version: "0.18.1" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + jhijri: + dependency: "direct main" + description: + name: jhijri + sha256: c2a28e803b1d07513a29953c6685b933235511a1f57966fd5bf66bfdae131f70 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + jhijri_picker: + dependency: "direct main" + description: + name: jhijri_picker + sha256: "55e3cdc03a20284fea179658c102b8eed802a5cc0e1fd949265285b1d352da8a" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + list_counter: + dependency: transitive + description: + name: list_counter + sha256: c447ae3dfcd1c55f0152867090e67e219d42fe6d4f2807db4bbe8b8d69912237 + url: "https://pub.dev" + source: hosted + version: "1.0.2" + local_auth: + dependency: "direct main" + description: + name: local_auth + sha256: "27679ed8e0d7daab2357db6bb7076359e083a56b295c0c59723845301da6aed9" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + local_auth_android: + dependency: transitive + description: + name: local_auth_android + sha256: e0e5b1ea247c5a0951c13a7ee13dc1beae69750e6a2e1910d1ed6a3cd4d56943 + url: "https://pub.dev" + source: hosted + version: "1.0.38" + local_auth_ios: + dependency: transitive + description: + name: local_auth_ios + sha256: eb283b530029b334698918f1e282d4483737cbca972ff21b9193be3d6de8e2b8 + url: "https://pub.dev" + source: hosted + version: "1.1.6" + local_auth_platform_interface: + dependency: transitive + description: + name: local_auth_platform_interface + sha256: "1b842ff177a7068442eae093b64abe3592f816afd2a533c0ebcdbe40f9d2075a" + url: "https://pub.dev" + source: hosted + version: "1.0.10" + local_auth_windows: + dependency: transitive + description: + name: local_auth_windows + sha256: bc4e66a29b0fdf751aafbec923b5bed7ad6ed3614875d8151afe2578520b2ab5 + url: "https://pub.dev" + source: hosted + version: "1.0.11" + localization: + dependency: "direct main" + description: + name: localization + sha256: "9fa21644b75ca3fe844f8f115d03cd6fdc675054dd9aab6c5de5861145ea57b5" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + maps_launcher: + dependency: "direct main" + description: + name: maps_launcher + sha256: "57ba3c31db96e30f58c23fcb22a1fac6accc5683535b2cf344c534bbb9f8f910" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" + source: hosted + version: "1.15.0" + mime: + dependency: transitive + description: + name: mime + sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" + url: "https://pub.dev" + source: hosted + version: "1.0.6" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + numberpicker: + dependency: "direct main" + description: + name: numberpicker + sha256: "4c129154944b0f6b133e693f8749c3f8bfb67c4d07ef9dcab48b595c22d1f156" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + url: "https://pub.dev" + source: hosted + version: "2.1.4" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d + url: "https://pub.dev" + source: hosted + version: "2.2.4" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + pedantic: + dependency: transitive + description: + name: pedantic + sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + percent_indicator: + dependency: "direct main" + description: + name: percent_indicator + sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c + url: "https://pub.dev" + source: hosted + version: "4.2.3" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb" + url: "https://pub.dev" + source: hosted + version: "11.3.1" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: "76e4ab092c1b240d31177bb64d2b0bea43f43d0e23541ec866151b9f7b2490fa" + url: "https://pub.dev" + source: hosted + version: "12.0.12" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0 + url: "https://pub.dev" + source: hosted + version: "9.4.5" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d" + url: "https://pub.dev" + source: hosted + version: "0.1.1" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea + url: "https://pub.dev" + source: hosted + version: "4.2.2" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + url: "https://pub.dev" + source: hosted + version: "3.1.5" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pointer_interceptor: + dependency: transitive + description: + name: pointer_interceptor + sha256: "57210410680379aea8b1b7ed6ae0c3ad349bfd56fe845b8ea934a53344b9d523" + url: "https://pub.dev" + source: hosted + version: "0.10.1+2" + pointer_interceptor_ios: + dependency: transitive + description: + name: pointer_interceptor_ios + sha256: a6906772b3205b42c44614fcea28f818b1e5fdad73a4ca742a7bd49818d9c917 + url: "https://pub.dev" + source: hosted + version: "0.10.1" + pointer_interceptor_platform_interface: + dependency: transitive + description: + name: pointer_interceptor_platform_interface + sha256: "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506" + url: "https://pub.dev" + source: hosted + version: "0.10.0+1" + pointer_interceptor_web: + dependency: transitive + description: + name: pointer_interceptor_web + sha256: "7a7087782110f8c1827170660b09f8aa893e0e9a61431dbbe2ac3fc482e8c044" + url: "https://pub.dev" + source: hosted + version: "0.10.2+1" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" + url: "https://pub.dev" + source: hosted + version: "3.9.1" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + protobuf: + dependency: transitive + description: + name: protobuf + sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + quiver: + dependency: "direct main" + description: + name: quiver + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" + source: hosted + version: "0.27.7" + scratch_space: + dependency: transitive + description: + name: scratch_space + sha256: "8510fbff458d733a58fc427057d1ac86303b376d609d6e1bc43f240aad9aa445" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 + url: "https://pub.dev" + source: hosted + version: "2.2.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + url: "https://pub.dev" + source: hosted + version: "2.3.5" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "2ba0510d3017f91655b7543e9ee46d48619de2a2af38e5c790423f7007c7ccc1" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "398084b47b7f92110683cac45c6dc4aae853db47e470e5ddcd52cab7f7196ab2" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + speech_to_text: + dependency: "direct main" + description: + name: speech_to_text + sha256: "57fef1d41bdebe298e84842c89bb4ac91f31cdbec7830c8cb1fc6b91d03abd42" + url: "https://pub.dev" + source: hosted + version: "6.6.0" + speech_to_text_macos: + dependency: transitive + description: + name: speech_to_text_macos + sha256: e685750f7542fcaa087a5396ee471e727ec648bf681f4da83c84d086322173f6 + url: "https://pub.dev" + source: hosted + version: "1.1.0" + speech_to_text_platform_interface: + dependency: transitive + description: + name: speech_to_text_platform_interface + sha256: a0df1a907091ea09880077dc25aae02af9f79811264e6e97ddb08639b7f771c2 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709" + url: "https://pub.dev" + source: hosted + version: "2.5.4+6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c" + url: "https://pub.dev" + source: hosted + version: "2.4.1+1" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + sticky_headers: + dependency: "direct main" + description: + name: sticky_headers + sha256: "9b3dd2cb0fd6a7038170af3261f855660cbb241cb56c501452cb8deed7023ede" + url: "https://pub.dev" + source: hosted + version: "0.3.0+2" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" + url: "https://pub.dev" + source: hosted + version: "6.3.0" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "17cd5e205ea615e2c6ea7a77323a11712dffa0720a8a90540db57a01347f9ad9" + url: "https://pub.dev" + source: hosted + version: "6.3.2" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" + url: "https://pub.dev" + source: hosted + version: "6.2.4" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + url: "https://pub.dev" + source: hosted + version: "3.1.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + uuid: + dependency: transitive + description: + name: uuid + sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77 + url: "https://pub.dev" + source: hosted + version: "4.5.0" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + visibility_detector: + dependency: transitive + description: + name: visibility_detector + sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420 + url: "https://pub.dev" + source: hosted + version: "0.4.0+2" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" + win32: + dependency: transitive + description: + name: win32 + sha256: e1d0cc62e65dc2561f5071fcbccecf58ff20c344f8f3dc7d4922df372a11df1f + url: "https://pub.dev" + source: hosted + version: "5.7.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.5.0 <3.6.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index d7fdc516..ec71db74 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,11 +11,11 @@ description: A new Flutter project. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 4.3.5+1 +version: 1.4.17+1 environment: - sdk: ">=3.0.0 <3.13.0" + sdk: ">=3.5.0 <4.0.0" #dependency_overrides: @@ -23,7 +23,6 @@ environment: #dependency_overrides: # intl: 0.17.0-nullsafety.2 - dependencies: flutter: sdk: flutter @@ -58,7 +57,7 @@ dependencies: barcode_scan2: ^4.3.0 # permissions permission_handler: ^11.1.0 - device_info: ^2.0.2 +# device_info: ^2.0.2 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. @@ -77,10 +76,11 @@ dependencies: # Firebase firebase_messaging: ^14.7.5 firebase_analytics : ^10.7.1 +# cloud_firestore: ^4.15.8 #GIF image # flutter_gifimage: ^1.0.1 - flutter_gif: ^0.0.4 +# flutter_gif: ^0.0.4 gif: ^2.3.0 #Autocomplete TextField autocomplete_textfield: ^2.0.1 @@ -95,7 +95,7 @@ dependencies: flutter_html: ^3.0.0-beta.2 sticky_headers: ^0.3.0+2 - file_picker: 5.2.0+1 + file_picker: ^8.1.3 #speech to text # speech_to_text: @@ -108,7 +108,7 @@ dependencies: # Html Editor Enhanced #html_editor_enhanced: any - html_editor_enhanced: ^2.5.1 + html_editor_enhanced: ^2.6.0 jhijri_picker: ^1.0.1 jhijri: ^1.0.0 @@ -130,10 +130,13 @@ dependencies: flutter_math_fork: ^0.7.2 - #zoom video plugin - flutter_zoom_videosdk: ^1.10.11 + #zoom video plugin + flutter_zoom_videosdk: 1.12.10 dart_jsonwebtoken: ^2.14.0 + cloudflare_turnstile: ^3.0.1 +# flutter_zoom_videosdk: ^1.10.11 +# dart_jsonwebtoken: ^2.14.0 dependency_overrides: diff --git a/web/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/web/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java new file mode 100644 index 00000000..539ab022 --- /dev/null +++ b/web/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -0,0 +1,19 @@ +package io.flutter.plugins; + +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import io.flutter.Log; + +import io.flutter.embedding.engine.FlutterEngine; + +/** + * Generated file. Do not edit. + * This file is generated by the Flutter tool based on the + * plugins that support the Android platform. + */ +@Keep +public final class GeneratedPluginRegistrant { + private static final String TAG = "GeneratedPluginRegistrant"; + public static void registerWith(@NonNull FlutterEngine flutterEngine) { + } +} diff --git a/web/android/gradle/wrapper/gradle-wrapper.jar b/web/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..13372aef Binary files /dev/null and b/web/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/web/android/gradlew b/web/android/gradlew new file mode 100755 index 00000000..9d82f789 --- /dev/null +++ b/web/android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/web/android/gradlew.bat b/web/android/gradlew.bat new file mode 100644 index 00000000..aec99730 --- /dev/null +++ b/web/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/web/android/local.properties b/web/android/local.properties new file mode 100644 index 00000000..48e2e8c6 --- /dev/null +++ b/web/android/local.properties @@ -0,0 +1,2 @@ +sdk.dir=/Users/sultankhan/Library/Android/sdk +flutter.sdk=/Users/sultankhan/Documents/flutter \ No newline at end of file diff --git a/web/favicon.png b/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/web/favicon.png differ diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/web/icons/Icon-192.png differ diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/web/icons/Icon-512.png differ diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/web/icons/Icon-maskable-192.png differ diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/web/icons/Icon-maskable-512.png differ diff --git a/web/index.html b/web/index.html new file mode 100644 index 00000000..05eb0e9f --- /dev/null +++ b/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + doctor_app_flutter + + + + + + + + + + diff --git a/web/ios/Runner/GeneratedPluginRegistrant.h b/web/ios/Runner/GeneratedPluginRegistrant.h new file mode 100644 index 00000000..7a890927 --- /dev/null +++ b/web/ios/Runner/GeneratedPluginRegistrant.h @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GeneratedPluginRegistrant_h +#define GeneratedPluginRegistrant_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GeneratedPluginRegistrant : NSObject ++ (void)registerWithRegistry:(NSObject*)registry; +@end + +NS_ASSUME_NONNULL_END +#endif /* GeneratedPluginRegistrant_h */ diff --git a/web/ios/Runner/GeneratedPluginRegistrant.m b/web/ios/Runner/GeneratedPluginRegistrant.m new file mode 100644 index 00000000..efe65ecc --- /dev/null +++ b/web/ios/Runner/GeneratedPluginRegistrant.m @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#import "GeneratedPluginRegistrant.h" + +@implementation GeneratedPluginRegistrant + ++ (void)registerWithRegistry:(NSObject*)registry { +} + +@end diff --git a/web/manifest.json b/web/manifest.json new file mode 100644 index 00000000..2b893959 --- /dev/null +++ b/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "doctor_app_flutter", + "short_name": "doctor_app_flutter", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/windows/.gitignore b/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt new file mode 100644 index 00000000..809a511f --- /dev/null +++ b/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(doctor_app_flutter LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "doctor_app_flutter") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..c0183aab --- /dev/null +++ b/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,29 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + FirebaseCorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); + FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); + LocalAuthPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("LocalAuthPlugin")); + MapsLauncherPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("MapsLauncherPlugin")); + PermissionHandlerWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); +} diff --git a/windows/flutter/generated_plugin_registrant.h b/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..14522e7e --- /dev/null +++ b/windows/flutter/generated_plugins.cmake @@ -0,0 +1,29 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + firebase_core + flutter_inappwebview_windows + local_auth_windows + maps_launcher + permission_handler_windows + url_launcher_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc new file mode 100644 index 00000000..7e94e81a --- /dev/null +++ b/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.hmg" "\0" + VALUE "FileDescription", "doctor_app_flutter" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "doctor_app_flutter" "\0" + VALUE "LegalCopyright", "Copyright (C) 2024 com.hmg. All rights reserved." "\0" + VALUE "OriginalFilename", "doctor_app_flutter.exe" "\0" + VALUE "ProductName", "doctor_app_flutter" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/windows/runner/flutter_window.h b/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp new file mode 100644 index 00000000..fd6b974f --- /dev/null +++ b/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"doctor_app_flutter", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/windows/runner/resource.h b/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/windows/runner/resources/app_icon.ico differ diff --git a/windows/runner/runner.exe.manifest b/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..a42ea768 --- /dev/null +++ b/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/windows/runner/utils.cpp b/windows/runner/utils.cpp new file mode 100644 index 00000000..b2b08734 --- /dev/null +++ b/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/windows/runner/utils.h b/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_