Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbc68001f4 | ||
|
|
caa57d9aa9 | ||
|
|
e0c240a212 | ||
|
|
bcb687e408 | ||
|
|
546eedf774 | ||
|
|
c7328bb80d | ||
|
|
dfe8e1bde5 | ||
|
|
066ae6c2b0 | ||
|
|
4abe664f3b | ||
|
|
f7018a5237 |
@@ -1,6 +1,6 @@
|
|||||||
# Aulas UNICABA 🎓📱
|
# Aulas UNICABA 🎓📱
|
||||||
|
|
||||||
[](package.json)
|
[](package.json)
|
||||||
[](https://angular.io/)
|
[](https://angular.io/)
|
||||||
[](https://ionicframework.com/)
|
[](https://ionicframework.com/)
|
||||||
[](https://capacitorjs.com/)
|
[](https://capacitorjs.com/)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "ar.edu.unicaba.cartelera"
|
applicationId "ar.edu.unicaba.cartelera"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 16
|
versionCode 17
|
||||||
versionName "1.2.3"
|
versionName "1.2.4"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||||
@@ -19,7 +19,7 @@ android {
|
|||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,3 +20,4 @@ org.gradle.jvmargs=-Xmx1536m
|
|||||||
# Android operating system, and which are packaged with your app's APK
|
# Android operating system, and which are packaged with your app's APK
|
||||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
java.home=/Users/carlosfacundotello/Library/Java/JavaVirtualMachines/jbr-21.0.11/Contents/Home
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
App/build
|
||||||
|
App/Pods
|
||||||
|
App/output
|
||||||
|
App/App/public
|
||||||
|
DerivedData
|
||||||
|
xcuserdata
|
||||||
|
|
||||||
|
# Cordova plugins for Capacitor
|
||||||
|
capacitor-cordova-ios-plugins
|
||||||
|
|
||||||
|
# Generated Config files
|
||||||
|
App/App/capacitor.config.json
|
||||||
|
App/App/config.xml
|
||||||
@@ -0,0 +1,376 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 60;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
|
||||||
|
4D22ABE92AF431CB00220026 /* CapApp-SPM in Frameworks */ = {isa = PBXBuildFile; productRef = 4D22ABE82AF431CB00220026 /* CapApp-SPM */; };
|
||||||
|
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
|
||||||
|
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
|
||||||
|
504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
|
||||||
|
504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; };
|
||||||
|
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
|
||||||
|
50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
|
||||||
|
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
|
||||||
|
504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
504EC30C1FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||||
|
504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
|
504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
|
||||||
|
958DCC722DB07C7200EA8C5F /* debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = debug.xcconfig; path = ../debug.xcconfig; sourceTree = SOURCE_ROOT; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
504EC3011FED79650016851F /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
4D22ABE92AF431CB00220026 /* CapApp-SPM in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
504EC2FB1FED79650016851F = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
958DCC722DB07C7200EA8C5F /* debug.xcconfig */,
|
||||||
|
504EC3061FED79650016851F /* App */,
|
||||||
|
504EC3051FED79650016851F /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
504EC3051FED79650016851F /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
504EC3041FED79650016851F /* App.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
504EC3061FED79650016851F /* App */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
50379B222058CBB4000EE86E /* capacitor.config.json */,
|
||||||
|
504EC3071FED79650016851F /* AppDelegate.swift */,
|
||||||
|
504EC30B1FED79650016851F /* Main.storyboard */,
|
||||||
|
504EC30E1FED79650016851F /* Assets.xcassets */,
|
||||||
|
504EC3101FED79650016851F /* LaunchScreen.storyboard */,
|
||||||
|
504EC3131FED79650016851F /* Info.plist */,
|
||||||
|
2FAD9762203C412B000D30F8 /* config.xml */,
|
||||||
|
50B271D01FEDC1A000F3C39B /* public */,
|
||||||
|
);
|
||||||
|
path = App;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
504EC3031FED79650016851F /* App */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */;
|
||||||
|
buildPhases = (
|
||||||
|
504EC3001FED79650016851F /* Sources */,
|
||||||
|
504EC3011FED79650016851F /* Frameworks */,
|
||||||
|
504EC3021FED79650016851F /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = App;
|
||||||
|
packageProductDependencies = (
|
||||||
|
4D22ABE82AF431CB00220026 /* CapApp-SPM */,
|
||||||
|
);
|
||||||
|
productName = App;
|
||||||
|
productReference = 504EC3041FED79650016851F /* App.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
504EC2FC1FED79650016851F /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastSwiftUpdateCheck = 0920;
|
||||||
|
LastUpgradeCheck = 0920;
|
||||||
|
TargetAttributes = {
|
||||||
|
504EC3031FED79650016851F = {
|
||||||
|
CreatedOnToolsVersion = 9.2;
|
||||||
|
LastSwiftMigration = 1100;
|
||||||
|
ProvisioningStyle = Automatic;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */;
|
||||||
|
compatibilityVersion = "Xcode 8.0";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 504EC2FB1FED79650016851F;
|
||||||
|
packageReferences = (
|
||||||
|
D4C12C0A2AAA248700AAC8A2 /* XCLocalSwiftPackageReference "CapApp-SPM" */,
|
||||||
|
);
|
||||||
|
productRefGroup = 504EC3051FED79650016851F /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
504EC3031FED79650016851F /* App */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
504EC3021FED79650016851F /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
|
||||||
|
50B271D11FEDC1A000F3C39B /* public in Resources */,
|
||||||
|
504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
|
||||||
|
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
|
||||||
|
504EC30D1FED79650016851F /* Main.storyboard in Resources */,
|
||||||
|
2FAD9763203C412B000D30F8 /* config.xml in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
504EC3001FED79650016851F /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
504EC30B1FED79650016851F /* Main.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
504EC30C1FED79650016851F /* Base */,
|
||||||
|
);
|
||||||
|
name = Main.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
504EC3101FED79650016851F /* LaunchScreen.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
504EC3111FED79650016851F /* Base */,
|
||||||
|
);
|
||||||
|
name = LaunchScreen.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
504EC3141FED79650016851F /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 958DCC722DB07C7200EA8C5F /* debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
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_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = 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_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
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_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
504EC3151FED79650016851F /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
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_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = 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_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
504EC3171FED79650016851F /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 958DCC722DB07C7200EA8C5F /* debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 17;
|
||||||
|
INFOPLIST_FILE = App/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.2.4;
|
||||||
|
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = ar.edu.unicaba.cartelera;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
504EC3181FED79650016851F /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 17;
|
||||||
|
INFOPLIST_FILE = App/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.2.4;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = ar.edu.unicaba.cartelera;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
504EC3141FED79650016851F /* Debug */,
|
||||||
|
504EC3151FED79650016851F /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
504EC3171FED79650016851F /* Debug */,
|
||||||
|
504EC3181FED79650016851F /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
|
/* Begin XCLocalSwiftPackageReference section */
|
||||||
|
D4C12C0A2AAA248700AAC8A2 /* XCLocalSwiftPackageReference "CapApp-SPM" */ = {
|
||||||
|
isa = XCLocalSwiftPackageReference;
|
||||||
|
relativePath = "CapApp-SPM";
|
||||||
|
};
|
||||||
|
/* End XCLocalSwiftPackageReference section */
|
||||||
|
|
||||||
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
4D22ABE82AF431CB00220026 /* CapApp-SPM */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = D4C12C0A2AAA248700AAC8A2 /* XCLocalSwiftPackageReference "CapApp-SPM" */;
|
||||||
|
productName = "CapApp-SPM";
|
||||||
|
};
|
||||||
|
/* End XCSwiftPackageProductDependency section */
|
||||||
|
};
|
||||||
|
rootObject = 504EC2FC1FED79650016851F /* Project object */;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"originHash" : "26db9e40224425527189efa269681907cff4f02aebc2d275c3ab2fb2c8ce83e1",
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "capacitor-swift-pm",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/ionic-team/capacitor-swift-pm.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "0e862e6ff13852a710c8a484180ca4d6a2cc9761",
|
||||||
|
"version" : "8.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "ion-ios-filesystem",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/ionic-team/ion-ios-filesystem.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "0d81e26e828ff9582807e2339112cedf2e0fab85",
|
||||||
|
"version" : "1.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "transistor-background-fetch",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/transistorsoft/transistor-background-fetch.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "34676021268c22c5cd356d9c96644aa0ee5fb68d",
|
||||||
|
"version" : "4.1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 3
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import UIKit
|
||||||
|
import Capacitor
|
||||||
|
|
||||||
|
@UIApplicationMain
|
||||||
|
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
|
||||||
|
var window: UIWindow?
|
||||||
|
|
||||||
|
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||||
|
// Override point for customization after application launch.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationWillResignActive(_ application: UIApplication) {
|
||||||
|
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||||
|
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||||
|
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||||
|
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||||
|
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||||
|
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationWillTerminate(_ application: UIApplication) {
|
||||||
|
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||||
|
}
|
||||||
|
|
||||||
|
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
|
||||||
|
// Called when the app was launched with a url. Feel free to add additional processing here,
|
||||||
|
// but if you want the App API to support tracking app url opens, make sure to keep this call
|
||||||
|
return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
||||||
|
// Called when the app was launched with an activity, including Universal Links.
|
||||||
|
// Feel free to add additional processing here, but if you want the App API to support
|
||||||
|
// tracking app url opens, make sure to keep this call
|
||||||
|
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "AppIcon-512@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "splash-2732x2732-2.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "splash-2732x2732-1.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "splash-2732x2732.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17132" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17105"/>
|
||||||
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="EHf-IW-A2E">
|
||||||
|
<objects>
|
||||||
|
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||||
|
<imageView key="view" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Splash" id="snD-IY-ifK">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
|
</imageView>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="53" y="375"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
<resources>
|
||||||
|
<image name="Splash" width="1366" height="1366"/>
|
||||||
|
<systemColor name="systemBackgroundColor">
|
||||||
|
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</systemColor>
|
||||||
|
</resources>
|
||||||
|
</document>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14111" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||||
|
<device id="retina4_7" orientation="portrait">
|
||||||
|
<adaptation id="fullscreen"/>
|
||||||
|
</device>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--Bridge View Controller-->
|
||||||
|
<scene sceneID="tne-QT-ifu">
|
||||||
|
<objects>
|
||||||
|
<viewController id="BYZ-38-t0r" customClass="CAPBridgeViewController" customModule="Capacitor" sceneMemberID="viewController"/>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CAPACITOR_DEBUG</key>
|
||||||
|
<string>$(CAPACITOR_DEBUG)</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>Aulas UNICABA</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(MARKETING_VERSION)</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>armv7</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
.DS_Store
|
||||||
|
/.build
|
||||||
|
/Packages
|
||||||
|
/*.xcodeproj
|
||||||
|
xcuserdata/
|
||||||
|
DerivedData/
|
||||||
|
.swiftpm/config/registries.json
|
||||||
|
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||||
|
.netrc
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// swift-tools-version: 5.9
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
// DO NOT MODIFY THIS FILE - managed by Capacitor CLI commands
|
||||||
|
let package = Package(
|
||||||
|
name: "CapApp-SPM",
|
||||||
|
platforms: [.iOS(.v15)],
|
||||||
|
products: [
|
||||||
|
.library(
|
||||||
|
name: "CapApp-SPM",
|
||||||
|
targets: ["CapApp-SPM"])
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "8.2.0"),
|
||||||
|
.package(name: "CapacitorCommunityFileOpener", path: "../../../node_modules/@capacitor-community/file-opener"),
|
||||||
|
.package(name: "CapacitorCommunityScreenBrightness", path: "../../../node_modules/@capacitor-community/screen-brightness"),
|
||||||
|
.package(name: "CapacitorApp", path: "../../../node_modules/@capacitor/app"),
|
||||||
|
.package(name: "CapacitorClipboard", path: "../../../node_modules/@capacitor/clipboard"),
|
||||||
|
.package(name: "CapacitorFilesystem", path: "../../../node_modules/@capacitor/filesystem"),
|
||||||
|
.package(name: "CapacitorHaptics", path: "../../../node_modules/@capacitor/haptics"),
|
||||||
|
.package(name: "CapacitorKeyboard", path: "../../../node_modules/@capacitor/keyboard"),
|
||||||
|
.package(name: "CapacitorLocalNotifications", path: "../../../node_modules/@capacitor/local-notifications"),
|
||||||
|
.package(name: "CapacitorNetwork", path: "../../../node_modules/@capacitor/network"),
|
||||||
|
.package(name: "CapacitorPreferences", path: "../../../node_modules/@capacitor/preferences"),
|
||||||
|
.package(name: "CapacitorShare", path: "../../../node_modules/@capacitor/share"),
|
||||||
|
.package(name: "CapacitorStatusBar", path: "../../../node_modules/@capacitor/status-bar"),
|
||||||
|
.package(name: "CapawesomeCapacitorFilePicker", path: "../../../node_modules/@capawesome/capacitor-file-picker"),
|
||||||
|
.package(name: "EbarooniCapacitorCalendar", path: "../../../node_modules/@ebarooni/capacitor-calendar"),
|
||||||
|
.package(name: "TransistorsoftCapacitorBackgroundFetch", path: "../../../node_modules/@transistorsoft/capacitor-background-fetch")
|
||||||
|
],
|
||||||
|
targets: [
|
||||||
|
.target(
|
||||||
|
name: "CapApp-SPM",
|
||||||
|
dependencies: [
|
||||||
|
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
||||||
|
.product(name: "Cordova", package: "capacitor-swift-pm"),
|
||||||
|
.product(name: "CapacitorCommunityFileOpener", package: "CapacitorCommunityFileOpener"),
|
||||||
|
.product(name: "CapacitorCommunityScreenBrightness", package: "CapacitorCommunityScreenBrightness"),
|
||||||
|
.product(name: "CapacitorApp", package: "CapacitorApp"),
|
||||||
|
.product(name: "CapacitorClipboard", package: "CapacitorClipboard"),
|
||||||
|
.product(name: "CapacitorFilesystem", package: "CapacitorFilesystem"),
|
||||||
|
.product(name: "CapacitorHaptics", package: "CapacitorHaptics"),
|
||||||
|
.product(name: "CapacitorKeyboard", package: "CapacitorKeyboard"),
|
||||||
|
.product(name: "CapacitorLocalNotifications", package: "CapacitorLocalNotifications"),
|
||||||
|
.product(name: "CapacitorNetwork", package: "CapacitorNetwork"),
|
||||||
|
.product(name: "CapacitorPreferences", package: "CapacitorPreferences"),
|
||||||
|
.product(name: "CapacitorShare", package: "CapacitorShare"),
|
||||||
|
.product(name: "CapacitorStatusBar", package: "CapacitorStatusBar"),
|
||||||
|
.product(name: "CapawesomeCapacitorFilePicker", package: "CapawesomeCapacitorFilePicker"),
|
||||||
|
.product(name: "EbarooniCapacitorCalendar", package: "EbarooniCapacitorCalendar"),
|
||||||
|
.product(name: "TransistorsoftCapacitorBackgroundFetch", package: "TransistorsoftCapacitorBackgroundFetch")
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# CapApp-SPM
|
||||||
|
|
||||||
|
This package is used to host SPM dependencies for your Capacitor project
|
||||||
|
|
||||||
|
Do not modify the contents of it or there may be unintended consequences.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
public let isCapacitorApp = true
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
CAPACITOR_DEBUG = true
|
||||||
Generated
+12
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "aulas-unicaba",
|
"name": "aulas-unicaba",
|
||||||
"version": "1.2.2",
|
"version": "1.2.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "aulas-unicaba",
|
"name": "aulas-unicaba",
|
||||||
"version": "1.2.2",
|
"version": "1.2.4",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "~20.3.18",
|
"@angular/animations": "~20.3.18",
|
||||||
"@angular/common": "~20.3.18",
|
"@angular/common": "~20.3.18",
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
"@capacitor/core": "8.2.0",
|
"@capacitor/core": "8.2.0",
|
||||||
"@capacitor/filesystem": "^8.1.2",
|
"@capacitor/filesystem": "^8.1.2",
|
||||||
"@capacitor/haptics": "8.0.1",
|
"@capacitor/haptics": "8.0.1",
|
||||||
|
"@capacitor/ios": "^8.2.0",
|
||||||
"@capacitor/keyboard": "8.0.1",
|
"@capacitor/keyboard": "8.0.1",
|
||||||
"@capacitor/local-notifications": "^8.0.2",
|
"@capacitor/local-notifications": "^8.0.2",
|
||||||
"@capacitor/network": "^8.0.0",
|
"@capacitor/network": "^8.0.0",
|
||||||
@@ -2865,6 +2866,15 @@
|
|||||||
"@capacitor/core": ">=8.0.0"
|
"@capacitor/core": ">=8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@capacitor/ios": {
|
||||||
|
"version": "8.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-8.2.0.tgz",
|
||||||
|
"integrity": "sha512-X2/VtM4qP/R1SM0VQ5W/VotEc6PS/KTooD33EijsfAHWBdee+xmBapW8SeNLnu16wJ+tsfWlvtipaJEyfKbRKQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@capacitor/core": "^8.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@capacitor/keyboard": {
|
"node_modules/@capacitor/keyboard": {
|
||||||
"version": "8.0.1",
|
"version": "8.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-8.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-8.0.1.tgz",
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "aulas-unicaba",
|
"name": "aulas-unicaba",
|
||||||
"version": "1.2.3",
|
"version": "1.2.4",
|
||||||
"author": "Ionic Framework",
|
"author": "Ionic Framework",
|
||||||
"homepage": "https://ionicframework.com/",
|
"homepage": "https://ionicframework.com/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
"@capacitor/core": "8.2.0",
|
"@capacitor/core": "8.2.0",
|
||||||
"@capacitor/filesystem": "^8.1.2",
|
"@capacitor/filesystem": "^8.1.2",
|
||||||
"@capacitor/haptics": "8.0.1",
|
"@capacitor/haptics": "8.0.1",
|
||||||
|
"@capacitor/ios": "^8.2.0",
|
||||||
"@capacitor/keyboard": "8.0.1",
|
"@capacitor/keyboard": "8.0.1",
|
||||||
"@capacitor/local-notifications": "^8.0.2",
|
"@capacitor/local-notifications": "^8.0.2",
|
||||||
"@capacitor/network": "^8.0.0",
|
"@capacitor/network": "^8.0.0",
|
||||||
|
|||||||
@@ -27,4 +27,4 @@ La aplicación ha sido diseñada bajo una arquitectura de "cliente liviano" con
|
|||||||
Esta innovación tecnológica es de carácter informativo. La precisión estricta de asignación de las aulas depende originariamente de la pre-carga impuesta por el cuerpo no-docente en el documento de Spreadsheets. En escenarios contradictorios, la palabra oficial del ala administrativa universitaria primará sobre la respuesta sincronizada en Aulas UNICABA.
|
Esta innovación tecnológica es de carácter informativo. La precisión estricta de asignación de las aulas depende originariamente de la pre-carga impuesta por el cuerpo no-docente en el documento de Spreadsheets. En escenarios contradictorios, la palabra oficial del ala administrativa universitaria primará sobre la respuesta sincronizada en Aulas UNICABA.
|
||||||
|
|
||||||
---
|
---
|
||||||
*Última actualización: 28 de Agosto, 2026 - v1.2.3*
|
*Última actualización: 29 de Agosto, 2026 - v1.2.4*
|
||||||
|
|||||||
@@ -30,46 +30,108 @@
|
|||||||
<p class="subtitle">Aprendé a usar tu Ecosistema Digital</p>
|
<p class="subtitle">Aprendé a usar tu Ecosistema Digital</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="info-body">
|
<div class="guide-cards-container">
|
||||||
<section>
|
|
||||||
<h3>1. Mi Cartelera (Horarios y Aulas)</h3>
|
|
||||||
<p>Visualizá todas las materias organizadas por día. Usá la barra de búsqueda para filtrar rápido por nombre,
|
|
||||||
aula o código.</p>
|
|
||||||
<ul>
|
|
||||||
<li><strong>Favoritos:</strong> Toca la estrella ⭐ para activar notificaciones automáticas y recordatorios 30
|
|
||||||
min antes de clase.</li>
|
|
||||||
<li><strong>Sincronización:</strong> Desliza hacia abajo para traer los últimos datos oficiales.</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
<!-- Paso 1: Cartelera -->
|
||||||
<h3>2. Mi Carrera (Seguimiento)</h3>
|
<div class="guide-card">
|
||||||
<p>Accedé desde el botón inferior para ver tu plan de estudios.</p>
|
<div class="guide-card-header">
|
||||||
<ul>
|
<div class="guide-icon-badge step-1">
|
||||||
<li><strong>Estados:</strong> Marcá materias como <em>Aprobadas</em> (Fucsia) o <em>En Curso</em> (Celeste).
|
<ion-icon name="calendar-outline"></ion-icon>
|
||||||
</li>
|
</div>
|
||||||
<li><strong>Optativas:</strong> Elegí tus materias directamente desde el selector para completar tu progreso.
|
<div class="guide-title-wrap">
|
||||||
</li>
|
<span class="guide-tag">Módulo 1</span>
|
||||||
</ul>
|
<h3>Mi Cartelera (Horarios y Aulas)</h3>
|
||||||
</section>
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="guide-text">
|
||||||
|
Consultá tus materias organizadas por día. Usá el buscador rápido por nombre, aula o código oficial.
|
||||||
|
</p>
|
||||||
|
<div class="guide-highlights">
|
||||||
|
<div class="highlight-item">
|
||||||
|
<ion-icon name="star" color="warning"></ion-icon>
|
||||||
|
<span><strong>Favoritos:</strong> Tocá la estrella ⭐ para recibir notificaciones y recordatorios 30 min antes de clase.</span>
|
||||||
|
</div>
|
||||||
|
<div class="highlight-item">
|
||||||
|
<ion-icon name="sync-outline" color="primary"></ion-icon>
|
||||||
|
<span><strong>Sincronización:</strong> Deslizá hacia abajo para actualizar con la cartelera oficial.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<section>
|
<!-- Paso 2: Carrera -->
|
||||||
<h3>3. Agenda y Exámenes</h3>
|
<div class="guide-card">
|
||||||
<p>En el menú de cada materia (`...`) podés agendar <strong>Parciales, Finales o TPs</strong>. Verás insignias
|
<div class="guide-card-header">
|
||||||
de colores avisándote la proximidad.</p>
|
<div class="guide-icon-badge step-2">
|
||||||
</section>
|
<ion-icon name="school-outline"></ion-icon>
|
||||||
|
</div>
|
||||||
|
<div class="guide-title-wrap">
|
||||||
|
<span class="guide-tag">Módulo 2</span>
|
||||||
|
<h3>Mi Carrera (Seguimiento)</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="guide-text">
|
||||||
|
Accedé desde el botón inferior para ver tu plan de estudios y seguir tu progreso académico.
|
||||||
|
</p>
|
||||||
|
<div class="guide-highlights">
|
||||||
|
<div class="highlight-item">
|
||||||
|
<ion-icon name="checkmark-circle-outline" color="secondary"></ion-icon>
|
||||||
|
<span><strong>Estados:</strong> Marcá materias como <em>Aprobadas</em> (Fucsia) o <em>En Curso</em> (Celeste).</span>
|
||||||
|
</div>
|
||||||
|
<div class="highlight-item">
|
||||||
|
<ion-icon name="list-outline" color="tertiary"></ion-icon>
|
||||||
|
<span><strong>Optativas:</strong> Seleccioná tus materias electivas directamente desde la grilla.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<section>
|
<!-- Paso 3: Agenda -->
|
||||||
<h3>4. Credencial Digital QR</h3>
|
<div class="guide-card">
|
||||||
<p>Tocá el logo arriba a la izquierda para abrir tu credencial. La app subirá el brillo automáticamente para
|
<div class="guide-card-header">
|
||||||
facilitar el escaneo.</p>
|
<div class="guide-icon-badge step-3">
|
||||||
</section>
|
<ion-icon name="alarm-outline"></ion-icon>
|
||||||
|
</div>
|
||||||
|
<div class="guide-title-wrap">
|
||||||
|
<span class="guide-tag">Módulo 3</span>
|
||||||
|
<h3>Agenda y Exámenes</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="guide-text">
|
||||||
|
En el menú de cada materia (<code>...</code>) podés agendar <strong>Parciales, Finales y Trabajos Prácticos</strong> con alertas visuales de proximidad.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Paso 4: Credencial -->
|
||||||
|
<div class="guide-card">
|
||||||
|
<div class="guide-card-header">
|
||||||
|
<div class="guide-icon-badge step-4">
|
||||||
|
<ion-icon name="qr-code-outline"></ion-icon>
|
||||||
|
</div>
|
||||||
|
<div class="guide-title-wrap">
|
||||||
|
<span class="guide-tag">Módulo 4</span>
|
||||||
|
<h3>Credencial Digital QR</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="guide-text">
|
||||||
|
Tocá el logo de la Universidad en la barra superior para abrir tu credencial. La app optimiza el brillo automáticamente para el molinete y funciona <strong>100% offline</strong>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Paso 5: Respaldo -->
|
||||||
|
<div class="guide-card">
|
||||||
|
<div class="guide-card-header">
|
||||||
|
<div class="guide-icon-badge step-5">
|
||||||
|
<ion-icon name="shield-checkmark-outline"></ion-icon>
|
||||||
|
</div>
|
||||||
|
<div class="guide-title-wrap">
|
||||||
|
<span class="guide-tag">Módulo 5</span>
|
||||||
|
<h3>Respaldo y Seguridad</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="guide-text">
|
||||||
|
En <strong>Perfil > Guardar Respaldo</strong> exportá tu archivo CSV seguro. Podés restaurarlo en cualquier momento sin perder tus datos.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<section>
|
|
||||||
<h3>5. Mantené tus datos seguros</h3>
|
|
||||||
<p>Usa <strong>Perfil > Guardar Respaldo</strong> para exportar un archivo CSV. Si cambias de teléfono, podés
|
|
||||||
restaurarlo desde el mismo lugar.</p>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -81,20 +143,40 @@
|
|||||||
<p class="subtitle">Tus datos son tuyos y de nadie más</p>
|
<p class="subtitle">Tus datos son tuyos y de nadie más</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="info-body">
|
<div class="privacy-cards-container">
|
||||||
<h3>Sin Intermediarios</h3>
|
|
||||||
<p>Aulas UNICABA no tiene servidores propios. Cada vez que sincronizás la cartelera o tu credencial, la conexión
|
|
||||||
viaja directo de tu teléfono al servidor de la Universidad.</p>
|
|
||||||
|
|
||||||
<h3>Tratamiento de Credenciales</h3>
|
<div class="privacy-card">
|
||||||
<p>Tus claves de Moodle o SIU Guaraní se guardan de forma encriptada en el almacenamiento seguro de tu
|
<div class="privacy-card-header">
|
||||||
dispositivo. Nunca salen de tu teléfono hacia terceros.</p>
|
<div class="privacy-icon-badge">
|
||||||
|
<ion-icon name="server-outline"></ion-icon>
|
||||||
|
</div>
|
||||||
|
<h3>Sin Servidores Intermediarios</h3>
|
||||||
|
</div>
|
||||||
|
<p>Aulas UNICABA no almacena tus datos en servidores intermedios. Cada sincronización de cartelera o credencial viaja directamente entre tu dispositivo y el servidor oficial de la Universidad.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h3>Analíticas y Rastreos</h3>
|
<div class="privacy-card">
|
||||||
<p>No usamos Google Analytics ni SDKs de seguimiento. No hay publicidad. Cero telemetría invasiva.</p>
|
<div class="privacy-card-header">
|
||||||
|
<div class="privacy-icon-badge">
|
||||||
|
<ion-icon name="key-outline"></ion-icon>
|
||||||
|
</div>
|
||||||
|
<h3>Almacenamiento Local Seguro</h3>
|
||||||
|
</div>
|
||||||
|
<p>Tus claves de Moodle o SIU Guaraní se guardan de forma encriptada en el almacenamiento seguro de tu teléfono y nunca se transmiten a terceros.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="privacy-card">
|
||||||
|
<div class="privacy-card-header">
|
||||||
|
<div class="privacy-icon-badge">
|
||||||
|
<ion-icon name="eye-off-outline"></ion-icon>
|
||||||
|
</div>
|
||||||
|
<h3>Cero Rastreadores y Sin Publicidad</h3>
|
||||||
|
</div>
|
||||||
|
<p>No utilizamos Google Analytics, ni cookies publicitarias ni SDKs de telemetría invasiva. Tu actividad académica es estrictamente privada.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="footer-info ion-text-center">
|
<div class="footer-info ion-text-center">
|
||||||
<p><small>Aulas UNICABA v1.2.3 • Independiente y Offline-First</small></p>
|
<p><small>Aulas UNICABA v1.2.4 • Independiente y Offline-First</small></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -118,14 +200,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="title-wrap">
|
<div class="title-wrap">
|
||||||
<h3>ON FIT</h3>
|
<h3>ON FIT</h3>
|
||||||
<p class="category">Gimnasio & Bienestar</p>
|
<p class="category">Gimnasio & Bienestar</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ion-badge color="success" class="discount-badge">25% OFF</ion-badge>
|
<ion-badge color="success" class="discount-badge">25% OFF</ion-badge>
|
||||||
</div>
|
</div>
|
||||||
<p class="benefit-desc">
|
<div class="benefit-headline">
|
||||||
25% de descuento sobre el valor de la membresía mensual con acceso libre a sus 20 sedes en todo el AMBA.
|
<span class="discount-lead">25% de descuento sobre el valor de la membresía mensual</span>
|
||||||
</p>
|
<span class="discount-sub">Acceso libre a sus 20 sedes en todo el AMBA</span>
|
||||||
|
</div>
|
||||||
<div class="inclusion-box">
|
<div class="inclusion-box">
|
||||||
<h4>¿Qué incluye la membresía?</h4>
|
<h4>¿Qué incluye la membresía?</h4>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -137,15 +220,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="meta-grid">
|
<div class="meta-grid">
|
||||||
<div class="meta-row">
|
<div class="meta-row">
|
||||||
<ion-icon name="information-circle-outline"></ion-icon>
|
<ion-icon name="information-circle-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Presentá tu Credencial Digital de la app para acreditar pertenencia a la Universidad.</span>
|
<span class="meta-text">Presentá tu Credencial Digital de la app para acreditar pertenencia.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ion-button expand="block" color="success" class="action-btn"
|
<ion-button expand="block" color="success" class="action-btn"
|
||||||
href="https://wa.me/5491158500830?text=Hola!%20Soy%20de%20la%20Universidad%20de%20la%20Ciudad%20y%20deseo%20acceder%20al%20beneficio%20ON%20FIT"
|
href="https://wa.me/5491158500830?text=Hola!%20Soy%20de%20la%20Universidad%20de%20la%20Ciudad%20y%20deseo%20acceder%20al%20beneficio%20ON%20FIT"
|
||||||
target="_blank">
|
target="_blank">
|
||||||
<ion-icon name="logo-whatsapp" slot="start"></ion-icon>
|
<ion-icon name="logo-whatsapp" slot="start"></ion-icon>
|
||||||
Consultar por WhatsApp (+54 9 11 5850-0830)
|
Consultar por WhatsApp
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -163,15 +246,22 @@
|
|||||||
</div>
|
</div>
|
||||||
<ion-badge color="warning" class="discount-badge">10% OFF</ion-badge>
|
<ion-badge color="warning" class="discount-badge">10% OFF</ion-badge>
|
||||||
</div>
|
</div>
|
||||||
<p class="benefit-desc">10% de descuento en productos (excluye promociones vigentes).</p>
|
<div class="benefit-headline">
|
||||||
|
<span class="discount-lead">10% de descuento en productos</span>
|
||||||
|
<span class="discount-cond">(excluye promociones vigentes)</span>
|
||||||
|
</div>
|
||||||
<div class="meta-grid">
|
<div class="meta-grid">
|
||||||
<div class="meta-row">
|
<div class="meta-row clickable-address" (click)="openMap('Tte. Gral. Juan Domingo Perón 893, CABA')">
|
||||||
<ion-icon name="location-outline"></ion-icon>
|
<ion-icon name="location-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Tte. Gral. Perón 893, CABA <em>(a metros de la sede)</em></span>
|
<div class="address-wrapper">
|
||||||
|
<span class="address-text">Tte. Gral. Perón 893, CABA</span>
|
||||||
|
<span class="address-extra"><em>(a metros de la sede)</em></span>
|
||||||
|
<span class="map-action-tag">Ver mapa <ion-icon name="open-outline"></ion-icon></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta-row">
|
<div class="meta-row">
|
||||||
<ion-icon name="time-outline"></ion-icon>
|
<ion-icon name="time-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Lun a Vie de 8 a 20 h • Sábados de 8 a 16 h</span>
|
<span class="meta-text">Lun a Vie de 8 a 20 h • Sábados de 8 a 16 h</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -184,21 +274,27 @@
|
|||||||
<ion-icon name="restaurant-outline"></ion-icon>
|
<ion-icon name="restaurant-outline"></ion-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="title-wrap">
|
<div class="title-wrap">
|
||||||
<h3>Café & Chocolate</h3>
|
<h3>Café & Chocolate</h3>
|
||||||
<p class="category">Cafetería & Delicatessen</p>
|
<p class="category">Cafetería & Delicatessen</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ion-badge color="warning" class="discount-badge">10% OFF</ion-badge>
|
<ion-badge color="warning" class="discount-badge">10% OFF</ion-badge>
|
||||||
</div>
|
</div>
|
||||||
<p class="benefit-desc">10% de descuento en productos (excluye promociones vigentes).</p>
|
<div class="benefit-headline">
|
||||||
|
<span class="discount-lead">10% de descuento en productos</span>
|
||||||
|
<span class="discount-cond">(excluye promociones vigentes)</span>
|
||||||
|
</div>
|
||||||
<div class="meta-grid">
|
<div class="meta-grid">
|
||||||
<div class="meta-row">
|
<div class="meta-row clickable-address" (click)="openMap('Bartolomé Mitre 807, CABA')">
|
||||||
<ion-icon name="location-outline"></ion-icon>
|
<ion-icon name="location-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Bartolomé Mitre 807, CABA</span>
|
<div class="address-wrapper">
|
||||||
|
<span class="address-text">Bartolomé Mitre 807, CABA</span>
|
||||||
|
<span class="map-action-tag">Ver mapa <ion-icon name="open-outline"></ion-icon></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta-row">
|
<div class="meta-row">
|
||||||
<ion-icon name="time-outline"></ion-icon>
|
<ion-icon name="time-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Lun a Vie de 8 a 19 h • Sábados de 8 a 14 h</span>
|
<span class="meta-text">Lun a Vie de 8 a 19 h • Sábados de 8 a 14 h</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -217,15 +313,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<ion-badge color="danger" class="discount-badge">10% OFF</ion-badge>
|
<ion-badge color="danger" class="discount-badge">10% OFF</ion-badge>
|
||||||
</div>
|
</div>
|
||||||
<p class="benefit-desc">10% de descuento en productos (excluye promociones vigentes).</p>
|
<div class="benefit-headline">
|
||||||
|
<span class="discount-lead">10% de descuento en productos</span>
|
||||||
|
<span class="discount-cond">(excluye promociones vigentes)</span>
|
||||||
|
</div>
|
||||||
<div class="meta-grid">
|
<div class="meta-grid">
|
||||||
<div class="meta-row">
|
<div class="meta-row clickable-address" (click)="openMap('Tucumán 1596, CABA')">
|
||||||
<ion-icon name="location-outline"></ion-icon>
|
<ion-icon name="location-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Tucumán 1596, CABA</span>
|
<div class="address-wrapper">
|
||||||
|
<span class="address-text">Tucumán 1596, CABA</span>
|
||||||
|
<span class="map-action-tag">Ver mapa <ion-icon name="open-outline"></ion-icon></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta-row">
|
<div class="meta-row">
|
||||||
<ion-icon name="time-outline"></ion-icon>
|
<ion-icon name="time-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Mar a Vie de 8 a 19 h • Sáb y Dom de 9:30 a 14:30 h</span>
|
<span class="meta-text">Mar a Vie de 8 a 19 h • Sáb y Dom de 9:30 a 14:30 h</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -239,20 +341,26 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="title-wrap">
|
<div class="title-wrap">
|
||||||
<h3>Atlas Comercial</h3>
|
<h3>Atlas Comercial</h3>
|
||||||
<p class="category">Librería & Papelería</p>
|
<p class="category">Librería & Papelería</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ion-badge color="primary" class="discount-badge">10% OFF</ion-badge>
|
<ion-badge color="primary" class="discount-badge">10% OFF</ion-badge>
|
||||||
</div>
|
</div>
|
||||||
<p class="benefit-desc">10% de descuento en productos (excluye promociones vigentes).</p>
|
<div class="benefit-headline">
|
||||||
|
<span class="discount-lead">10% de descuento en productos</span>
|
||||||
|
<span class="discount-cond">(excluye promociones vigentes)</span>
|
||||||
|
</div>
|
||||||
<div class="meta-grid">
|
<div class="meta-grid">
|
||||||
<div class="meta-row">
|
<div class="meta-row clickable-address" (click)="openMap('Bartolomé Mitre 839, CABA')">
|
||||||
<ion-icon name="location-outline"></ion-icon>
|
<ion-icon name="location-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Bartolomé Mitre 839, CABA</span>
|
<div class="address-wrapper">
|
||||||
|
<span class="address-text">Bartolomé Mitre 839, CABA</span>
|
||||||
|
<span class="map-action-tag">Ver mapa <ion-icon name="open-outline"></ion-icon></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta-row">
|
<div class="meta-row">
|
||||||
<ion-icon name="time-outline"></ion-icon>
|
<ion-icon name="time-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Lun a Vie de 9 a 18 h</span>
|
<span class="meta-text">Lun a Vie de 9 a 18 h</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -266,22 +374,25 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="title-wrap">
|
<div class="title-wrap">
|
||||||
<h3>Fluire Studio</h3>
|
<h3>Fluire Studio</h3>
|
||||||
<p class="category">Pilates & Salud</p>
|
<p class="category">Pilates & Salud</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ion-badge color="tertiary" class="discount-badge">Hasta 20% OFF</ion-badge>
|
<ion-badge color="tertiary" class="discount-badge">Hasta 20% OFF</ion-badge>
|
||||||
</div>
|
</div>
|
||||||
<p class="benefit-desc">
|
<div class="benefit-headline">
|
||||||
10% de descuento abonando 1 mes de servicio y 20% de descuento abonando 4 meses de servicio.
|
<span class="discount-lead">10% OFF en 1 mes • 20% OFF abonando 4 meses</span>
|
||||||
</p>
|
</div>
|
||||||
<div class="meta-grid">
|
<div class="meta-grid">
|
||||||
<div class="meta-row">
|
<div class="meta-row clickable-address" (click)="openMap('Esmeralda 135, CABA')">
|
||||||
<ion-icon name="location-outline"></ion-icon>
|
<ion-icon name="location-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Esmeralda 135, piso 4 B, CABA</span>
|
<div class="address-wrapper">
|
||||||
|
<span class="address-text">Esmeralda 135, piso 4 B, CABA</span>
|
||||||
|
<span class="map-action-tag">Ver mapa <ion-icon name="open-outline"></ion-icon></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta-row">
|
<div class="meta-row">
|
||||||
<ion-icon name="mail-outline"></ion-icon>
|
<ion-icon name="mail-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Contacto: fluire.studio.ba@gmail.com</span>
|
<span class="meta-text">fluire.studio.ba@gmail.com</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ion-button expand="block" fill="outline" color="tertiary" class="action-btn"
|
<ion-button expand="block" fill="outline" color="tertiary" class="action-btn"
|
||||||
@@ -303,17 +414,23 @@
|
|||||||
<p class="category">Transporte de Larga Distancia</p>
|
<p class="category">Transporte de Larga Distancia</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ion-badge color="secondary" class="discount-badge">Descuento Nacional</ion-badge>
|
<ion-badge color="secondary" class="discount-badge">Desc. Nacional</ion-badge>
|
||||||
|
</div>
|
||||||
|
<div class="benefit-headline">
|
||||||
|
<span class="discount-lead">Descuentos en pasajes de micro a todo el país</span>
|
||||||
|
<span class="discount-sub">A través del portal oficial de Central de Pasajes</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="benefit-desc">
|
|
||||||
Obtené descuentos en pasajes de micro a todo el país a través del portal de Central de Pasajes.
|
|
||||||
</p>
|
|
||||||
<div class="meta-grid">
|
<div class="meta-grid">
|
||||||
<div class="meta-row">
|
<div class="meta-row">
|
||||||
<ion-icon name="checkmark-circle-outline"></ion-icon>
|
<ion-icon name="checkmark-circle-outline" class="meta-icon"></ion-icon>
|
||||||
<span>Entrá a <b>Perfil</b>, generá tu Certificado de Alumno Regular y subilo a <a href="https://soyestudiante.com.ar/" target="_blank">soyestudiante.com.ar</a>.</span>
|
<span class="meta-text">Entrá a <b>Perfil</b>, generá tu Certificado de Alumno Regular y subilo al portal.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ion-button expand="block" fill="outline" color="secondary" class="action-btn"
|
||||||
|
href="https://soyestudiante.com.ar/" target="_blank">
|
||||||
|
<ion-icon name="globe-outline" slot="start"></ion-icon>
|
||||||
|
Ir a SoyEstudiante.com.ar
|
||||||
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,101 +1,254 @@
|
|||||||
|
:host {
|
||||||
|
--modal-bg: var(--ion-color-light, #f4f5f8);
|
||||||
|
--card-bg: #ffffff;
|
||||||
|
--card-border: rgba(0, 0, 0, 0.05);
|
||||||
|
--card-shadow: 0 3px 12px rgba(0, 0, 0, 0.04);
|
||||||
|
--text-title: #1c1c1e;
|
||||||
|
--text-body: #4a4a52;
|
||||||
|
--text-sub: #55555e;
|
||||||
|
--text-muted: #777780;
|
||||||
|
--border-line: #f0f0f4;
|
||||||
|
--address-bg: rgba(var(--ion-color-primary-rgb), 0.04);
|
||||||
|
--address-border: rgba(var(--ion-color-primary-rgb), 0.1);
|
||||||
|
--address-hover: rgba(var(--ion-color-primary-rgb), 0.08);
|
||||||
|
--address-text: #1a1a1a;
|
||||||
|
--map-tag-bg: #ffffff;
|
||||||
|
--map-tag-color: var(--ion-color-primary);
|
||||||
|
--map-tag-border: rgba(var(--ion-color-primary-rgb), 0.2);
|
||||||
|
--h2-color: var(--ion-color-primary);
|
||||||
|
--segment-bg: rgba(0, 0, 0, 0.15);
|
||||||
|
--segment-indicator: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:host {
|
||||||
|
--modal-bg: var(--ion-background-color, #121212);
|
||||||
|
--card-bg: var(--ion-color-step-100, #1c1c1e);
|
||||||
|
--card-border: var(--ion-color-step-200, #2c2c30);
|
||||||
|
--card-shadow: 0 4px 18px rgba(0, 0, 0, 0.3);
|
||||||
|
--text-title: #ffffff;
|
||||||
|
--text-body: #d1d2d8;
|
||||||
|
--text-sub: #b5b6bc;
|
||||||
|
--text-muted: #a0a0a8;
|
||||||
|
--border-line: rgba(255, 255, 255, 0.08);
|
||||||
|
--address-bg: rgba(100, 181, 246, 0.08);
|
||||||
|
--address-border: rgba(100, 181, 246, 0.2);
|
||||||
|
--address-hover: rgba(100, 181, 246, 0.15);
|
||||||
|
--address-text: #64b5f6;
|
||||||
|
--map-tag-bg: rgba(100, 181, 246, 0.18);
|
||||||
|
--map-tag-color: #90caf9;
|
||||||
|
--map-tag-border: rgba(100, 181, 246, 0.35);
|
||||||
|
--h2-color: #ff8ab6;
|
||||||
|
--segment-bg: rgba(0, 0, 0, 0.35);
|
||||||
|
--segment-indicator: #ff8ab6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.privacy-content {
|
.privacy-content {
|
||||||
--background: var(--ion-color-light);
|
--background: var(--modal-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-segment {
|
ion-segment {
|
||||||
--background: var(--ion-color-primary-shade);
|
--background: var(--segment-bg);
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
|
||||||
ion-segment-button {
|
ion-segment-button {
|
||||||
--color: rgba(255,255,255,0.7);
|
--color: rgba(255, 255, 255, 0.75);
|
||||||
--color-checked: white;
|
--color-checked: #ffffff;
|
||||||
--indicator-color: white;
|
--indicator-color: var(--segment-indicator);
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo-container {
|
.logo-container {
|
||||||
padding: 10px 0 20px;
|
padding: 10px 0 18px;
|
||||||
|
|
||||||
.info-logo {
|
.info-logo {
|
||||||
height: 80px;
|
height: 76px;
|
||||||
background: white;
|
background: #ffffff;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
margin-bottom: 15px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-icon {
|
ion-icon {
|
||||||
font-size: 64px;
|
font-size: 56px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--ion-color-primary);
|
color: var(--h2-color);
|
||||||
|
font-size: 1.45rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
margin: 5px 0 0;
|
margin: 4px 0 0;
|
||||||
color: var(--ion-color-medium);
|
color: var(--text-muted);
|
||||||
font-size: 0.9rem;
|
font-size: 0.88rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-body {
|
/* =========================================================
|
||||||
background: white;
|
GUÍA DEL ESTUDIANTE (MANUAL)
|
||||||
border-radius: 20px;
|
========================================================= */
|
||||||
padding: 20px;
|
.guide-cards-container,
|
||||||
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
|
.privacy-cards-container,
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
section {
|
|
||||||
margin-bottom: 25px;
|
|
||||||
&:last-child { margin-bottom: 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 1rem;
|
|
||||||
color: var(--ion-color-dark);
|
|
||||||
margin: 0 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p, li {
|
|
||||||
font-size: 0.9rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: var(--ion-color-medium-shade);
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding-left: 20px;
|
|
||||||
margin: 10px 0;
|
|
||||||
li { margin-bottom: 8px; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --- ESTILOS DE BENEFICIOS --- */
|
|
||||||
.benefits-container {
|
.benefits-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 14px;
|
||||||
margin-bottom: 25px;
|
margin-bottom: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.guide-card,
|
||||||
|
.privacy-card,
|
||||||
|
.benefit-card {
|
||||||
|
background: var(--card-bg);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
box-shadow: var(--card-shadow);
|
||||||
|
border: 1px solid var(--card-border);
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-card {
|
||||||
|
.guide-card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.guide-icon-badge {
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 20px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&.step-1 { background: rgba(194, 24, 91, 0.12); color: #c2185b; }
|
||||||
|
&.step-2 { background: rgba(81, 45, 168, 0.12); color: #7e57c2; }
|
||||||
|
&.step-3 { background: rgba(2, 136, 209, 0.12); color: #0288d1; }
|
||||||
|
&.step-4 { background: rgba(46, 125, 50, 0.12); color: #2e7d32; }
|
||||||
|
&.step-5 { background: rgba(230, 81, 0, 0.12); color: #ef6c00; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-title-wrap {
|
||||||
|
.guide-tag {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--h2-color);
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.98rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-text {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
line-height: 1.45;
|
||||||
|
color: var(--text-body);
|
||||||
|
&:last-child { margin-bottom: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-highlights {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px solid var(--border-line);
|
||||||
|
|
||||||
|
.highlight-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 0.83rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: var(--text-sub);
|
||||||
|
|
||||||
|
ion-icon {
|
||||||
|
font-size: 15px;
|
||||||
|
margin-top: 2px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: var(--text-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
em {
|
||||||
|
color: var(--h2-color);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================================================
|
||||||
|
PRIVACIDAD ZERO-TRUST
|
||||||
|
========================================================= */
|
||||||
|
.privacy-card {
|
||||||
|
.privacy-card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.privacy-icon-badge {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(45, 211, 111, 0.15);
|
||||||
|
color: #2dd36f;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 18px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.98rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
line-height: 1.45;
|
||||||
|
color: var(--text-body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================================================
|
||||||
|
COMUNIDAD DE BENEFICIOS
|
||||||
|
========================================================= */
|
||||||
.benefit-card {
|
.benefit-card {
|
||||||
background: white;
|
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
padding: 18px;
|
padding: 18px;
|
||||||
box-shadow: 0 4px 15px rgba(0,0,0,0.06);
|
|
||||||
border: 1px solid rgba(0,0,0,0.04);
|
|
||||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
||||||
|
|
||||||
&.featured {
|
&.featured {
|
||||||
border: 1.5px solid var(--ion-color-primary);
|
border: 1.5px solid var(--h2-color);
|
||||||
background: linear-gradient(180deg, #ffffff 0%, rgba(var(--ion-color-primary-rgb), 0.02) 100%);
|
box-shadow: 0 6px 20px rgba(var(--ion-color-primary-rgb), 0.16);
|
||||||
box-shadow: 0 6px 20px rgba(var(--ion-color-primary-rgb), 0.12);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-top {
|
.card-top {
|
||||||
@@ -116,17 +269,15 @@ ion-segment {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background: rgba(var(--ion-color-primary-rgb), 0.1);
|
|
||||||
color: var(--ion-color-primary);
|
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
&.cafe { background: #fff3e0; color: #e65100; }
|
&.cafe { background: rgba(255, 152, 0, 0.15); color: #f57c00; }
|
||||||
&.gym { background: #e8f5e9; color: #2e7d32; }
|
&.gym { background: rgba(76, 175, 80, 0.15); color: #388e3c; }
|
||||||
&.pilates { background: #ede7f6; color: #512da8; }
|
&.pilates { background: rgba(156, 39, 176, 0.15); color: #8e24aa; }
|
||||||
&.pasta { background: #fbe9e7; color: #d84315; }
|
&.pasta { background: rgba(255, 87, 34, 0.15); color: #e64a19; }
|
||||||
&.libreria { background: #e1f5fe; color: #0288d1; }
|
&.libreria { background: rgba(3, 169, 244, 0.15); color: #0288d1; }
|
||||||
&.travel { background: #e3f2fd; color: #1565c0; }
|
&.travel { background: rgba(33, 150, 243, 0.15); color: #1976d2; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-wrap {
|
.title-wrap {
|
||||||
@@ -134,12 +285,12 @@ ion-segment {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1.05rem;
|
font-size: 1.05rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: var(--ion-color-dark);
|
color: var(--text-title);
|
||||||
}
|
}
|
||||||
.category {
|
.category {
|
||||||
margin: 2px 0 0;
|
margin: 2px 0 0;
|
||||||
font-size: 0.8rem;
|
font-size: 0.78rem;
|
||||||
color: var(--ion-color-medium);
|
color: var(--text-muted);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
@@ -156,11 +307,31 @@ ion-segment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.benefit-desc {
|
.benefit-headline {
|
||||||
font-size: 0.92rem;
|
margin-bottom: 12px;
|
||||||
color: var(--ion-color-dark-shade);
|
display: flex;
|
||||||
margin: 0 0 12px;
|
flex-direction: column;
|
||||||
line-height: 1.45;
|
gap: 2px;
|
||||||
|
|
||||||
|
.discount-lead {
|
||||||
|
font-size: 0.94rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-title);
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discount-cond {
|
||||||
|
font-size: 0.82rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discount-sub {
|
||||||
|
font-size: 0.84rem;
|
||||||
|
color: var(--text-body);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.meta-grid {
|
.meta-grid {
|
||||||
@@ -168,38 +339,101 @@ ion-segment {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
border-top: 1px dashed #e0e0e0;
|
border-top: 1px dashed var(--border-line);
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
|
||||||
.meta-row {
|
.meta-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
font-size: 0.84rem;
|
font-size: 0.84rem;
|
||||||
color: var(--ion-color-medium-shade);
|
color: var(--text-sub);
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
|
|
||||||
ion-icon {
|
.meta-icon {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
margin-top: 2px;
|
color: var(--h2-color);
|
||||||
color: var(--ion-color-primary);
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.meta-text {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clickable-address {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 6px 10px;
|
||||||
|
margin: -2px -6px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--address-bg);
|
||||||
|
border: 1px solid var(--address-border);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
.address-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px 6px;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.address-text {
|
||||||
|
color: var(--address-text);
|
||||||
|
font-weight: 700;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-extra {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-action-tag {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--map-tag-color);
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
|
background: var(--map-tag-bg);
|
||||||
|
padding: 2px 7px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid var(--map-tag-border);
|
||||||
|
flex-shrink: 0;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
|
||||||
|
margin-left: auto;
|
||||||
|
|
||||||
|
ion-icon {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--address-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.985);
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.inclusion-box {
|
.inclusion-box {
|
||||||
background: #f8fafc;
|
background: rgba(0, 0, 0, 0.03);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
border-left: 3px solid var(--ion-color-success);
|
border-left: 3px solid var(--ion-color-success, #2dd36f);
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
margin: 0 0 6px;
|
margin: 0 0 6px;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--ion-color-dark);
|
color: var(--text-title);
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
@@ -208,7 +442,7 @@ ion-segment {
|
|||||||
li {
|
li {
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
color: #475569;
|
color: var(--text-body);
|
||||||
&:last-child { margin-bottom: 0; }
|
&:last-child { margin-bottom: 0; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,8 +458,11 @@ ion-segment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.footer-info {
|
.footer-info {
|
||||||
margin-top: 30px;
|
margin-top: 25px;
|
||||||
opacity: 0.6;
|
p, small {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-in {
|
.fade-in {
|
||||||
|
|||||||
@@ -18,4 +18,29 @@ export class InfoModalComponent {
|
|||||||
close() {
|
close() {
|
||||||
this.modalCtrl.dismiss();
|
this.modalCtrl.dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openMap(address: string, event?: Event) {
|
||||||
|
if (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
const encodedAddress = encodeURIComponent(address);
|
||||||
|
|
||||||
|
// En iOS / Android se usan los esquemas nativos del sistema
|
||||||
|
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
|
||||||
|
const isAndroid = /android/i.test(navigator.userAgent);
|
||||||
|
|
||||||
|
let url = '';
|
||||||
|
if (isAndroid) {
|
||||||
|
// En Android, geo:0,0?q= abre el selector de mapas (Maps, Waze)
|
||||||
|
url = `geo:0,0?q=${encodedAddress}`;
|
||||||
|
} else if (isIOS) {
|
||||||
|
// En iOS, maps:// abre Apple Maps
|
||||||
|
url = `maps://?q=${encodedAddress}`;
|
||||||
|
} else {
|
||||||
|
// Fallback para Web / Escritorio
|
||||||
|
url = `https://www.google.com/maps/search/?api=1&query=${encodedAddress}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.open(url, '_system');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,32 @@
|
|||||||
|
|
||||||
.view-segment {
|
.view-segment {
|
||||||
background: var(--ion-background-color);
|
background: var(--ion-background-color);
|
||||||
padding: 10px;
|
padding: 10px 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
ion-segment {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
|
&.ios {
|
||||||
|
width: 85% !important;
|
||||||
|
max-width: 85% !important;
|
||||||
|
margin-left: auto !important;
|
||||||
|
margin-right: auto !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:host-context(.ios) .view-segment ion-segment {
|
||||||
|
width: 85% !important;
|
||||||
|
max-width: 85% !important;
|
||||||
|
margin-left: auto !important;
|
||||||
|
margin-right: auto !important;
|
||||||
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-header-flex {
|
.card-header-flex {
|
||||||
|
|||||||
@@ -171,38 +171,7 @@
|
|||||||
</ion-card-content>
|
</ion-card-content>
|
||||||
</ion-card>
|
</ion-card>
|
||||||
|
|
||||||
<!-- Beneficios del Estudiante -->
|
|
||||||
<div class="section-header ion-padding-horizontal">
|
|
||||||
<h3>Beneficios del Estudiante</h3>
|
|
||||||
<p>Aprovechá convenios exclusivos por ser parte de UNICABA.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ion-row class="benefits-row">
|
|
||||||
<ion-col size="6">
|
|
||||||
<ion-card class="benefit-card" (click)="showBenefitDetail('soy')">
|
|
||||||
<div class="benefit-icon-container soy">
|
|
||||||
<ion-icon name="school-outline"></ion-icon>
|
|
||||||
</div>
|
|
||||||
<ion-card-content>
|
|
||||||
<h4>SOY Estudiante</h4>
|
|
||||||
<p>Descuentos en pasajes de micro.</p>
|
|
||||||
<ion-badge color="success">Activo</ion-badge>
|
|
||||||
</ion-card-content>
|
|
||||||
</ion-card>
|
|
||||||
</ion-col>
|
|
||||||
<ion-col size="6">
|
|
||||||
<ion-card class="benefit-card" (click)="showBenefitDetail('google')">
|
|
||||||
<div class="benefit-icon-container google">
|
|
||||||
<ion-icon name="logo-google" color="primary"></ion-icon>
|
|
||||||
</div>
|
|
||||||
<ion-card-content>
|
|
||||||
<h4>Google Students</h4>
|
|
||||||
<p>Gemini PRO & Drive 1TB.</p>
|
|
||||||
<ion-badge color="tertiary">Bonificado</ion-badge>
|
|
||||||
</ion-card-content>
|
|
||||||
</ion-card>
|
|
||||||
</ion-col>
|
|
||||||
</ion-row>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="security-info ion-padding">
|
<div class="security-info ion-padding">
|
||||||
|
|||||||
@@ -195,81 +195,6 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-header {
|
|
||||||
margin-top: 24px;
|
|
||||||
h3 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
font-weight: 700;
|
|
||||||
color: var(--ion-color-dark);
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
margin: 4px 0 0;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
color: var(--ion-color-medium);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.benefits-row {
|
|
||||||
padding: 0 8px;
|
|
||||||
margin-top: -8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.benefit-card {
|
|
||||||
margin: 8px;
|
|
||||||
border-radius: 16px;
|
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: calc(100% - 16px);
|
|
||||||
transition: transform 0.2s;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
transform: scale(0.96);
|
|
||||||
}
|
|
||||||
|
|
||||||
.benefit-icon-container {
|
|
||||||
height: 80px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
&.soy {
|
|
||||||
background: linear-gradient(135deg, #f0f7ff 0%, #e0e7ff 100%);
|
|
||||||
ion-icon { font-size: 40px; color: #1a73e8; }
|
|
||||||
}
|
|
||||||
|
|
||||||
&.google {
|
|
||||||
background: linear-gradient(135deg, #fff5f5 0%, #ffe0e0 100%);
|
|
||||||
ion-icon { font-size: 40px; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-card-content {
|
|
||||||
padding: 12px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
font-weight: 700;
|
|
||||||
color: var(--ion-color-dark);
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
margin: 6px 0;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: var(--ion-color-medium);
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
ion-badge {
|
|
||||||
font-size: 0.65rem;
|
|
||||||
padding: 4px 8px;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.security-info {
|
.security-info {
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -290,20 +215,3 @@
|
|||||||
max-width: 280px;
|
max-width: 280px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:host ::ng-deep .benefit-alert {
|
|
||||||
.alert-message {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.benefit-modal-content {
|
|
||||||
b { color: var(--ion-color-primary); }
|
|
||||||
ol {
|
|
||||||
padding-left: 20px;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -202,15 +202,7 @@ export class PerfilPage implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async showBenefitDetail(type: 'soy' | 'google') {
|
|
||||||
const modal = await this.modalCtrl.create({
|
|
||||||
component: InfoModalComponent,
|
|
||||||
componentProps: {
|
|
||||||
selectedSegment: 'benefits'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await modal.present();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- NUEVAS FUNCIONES CONSOLIDADAS ---
|
// --- NUEVAS FUNCIONES CONSOLIDADAS ---
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CapacitorHttp, HttpResponse } from '@capacitor/core';
|
import { CapacitorHttp, CapacitorCookies, HttpResponse } from '@capacitor/core';
|
||||||
import { Filesystem, Directory } from '@capacitor/filesystem';
|
import { Filesystem, Directory } from '@capacitor/filesystem';
|
||||||
import { FileOpener } from '@capacitor-community/file-opener';
|
import { FileOpener } from '@capacitor-community/file-opener';
|
||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
@@ -11,16 +11,16 @@ export class SiuService {
|
|||||||
|
|
||||||
async getAcademicHistory(dni: string, pass: string, carreraId: string = '30'): Promise<any[]> {
|
async getAcademicHistory(dni: string, pass: string, carreraId: string = '30'): Promise<any[]> {
|
||||||
try {
|
try {
|
||||||
await this.authenticateSiu(dni, pass);
|
const authCookies = await this.authenticateSiu(dni, pass);
|
||||||
await this.selectCareer(carreraId);
|
const sessionCookies = await this.selectCareer(carreraId, authCookies);
|
||||||
|
|
||||||
// 3. OBTENER PLAN DE ESTUDIO
|
// 3. OBTENER PLAN DE ESTUDIO
|
||||||
const resPlan: HttpResponse = await CapacitorHttp.get({
|
const { html: rawHtml } = await this.getHtml(`${this.BASE_URL}/plan_estudio`, sessionCookies);
|
||||||
url: `${this.BASE_URL}/plan_estudio`,
|
|
||||||
});
|
if (!rawHtml) {
|
||||||
|
throw new Error('No se recibió contenido del plan de estudios.');
|
||||||
|
}
|
||||||
|
|
||||||
// 4. PARSEO DEL JSON EMBEBIDO
|
|
||||||
const rawHtml = resPlan.data;
|
|
||||||
const regex = /on_arrival\((\{.*?"id":"info_plan".*?\})\);/s;
|
const regex = /on_arrival\((\{.*?"id":"info_plan".*?\})\);/s;
|
||||||
const match = rawHtml.match(regex);
|
const match = rawHtml.match(regex);
|
||||||
|
|
||||||
@@ -30,6 +30,10 @@ export class SiuService {
|
|||||||
return this.parseHtmlSubjects(contentHtml);
|
return this.parseHtmlSubjects(contentHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rawHtml.includes('acceso?auth=form') || rawHtml.includes('id="login"')) {
|
||||||
|
throw new Error('La sesión de SIU Guaraní no se pudo autenticar o expiró.');
|
||||||
|
}
|
||||||
|
|
||||||
throw new Error('No se encontró el bloque de materias');
|
throw new Error('No se encontró el bloque de materias');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error SIU Academic History:', error);
|
console.error('Error SIU Academic History:', error);
|
||||||
@@ -39,15 +43,13 @@ export class SiuService {
|
|||||||
|
|
||||||
async getInscripcionesActivas(dni: string, pass: string, carreraId: string = '30'): Promise<any[]> {
|
async getInscripcionesActivas(dni: string, pass: string, carreraId: string = '30'): Promise<any[]> {
|
||||||
try {
|
try {
|
||||||
await this.authenticateSiu(dni, pass);
|
const authCookies = await this.authenticateSiu(dni, pass);
|
||||||
await this.selectCareer(carreraId);
|
const sessionCookies = await this.selectCareer(carreraId, authCookies);
|
||||||
|
|
||||||
// OBTENER PÁGINA DE CURSADA
|
// OBTENER PÁGINA DE CURSADA
|
||||||
const resCursada: HttpResponse = await CapacitorHttp.get({
|
const { html: rawHtml } = await this.getHtml(`${this.BASE_URL}/cursada`, sessionCookies);
|
||||||
url: `${this.BASE_URL}/cursada`,
|
|
||||||
});
|
|
||||||
|
|
||||||
const rawHtml = resCursada.data;
|
if (!rawHtml) return [];
|
||||||
|
|
||||||
// 1. Extraer directamente de "notificaciones" donde SIU provee el array JSON "asignaciones"
|
// 1. Extraer directamente de "notificaciones" donde SIU provee el array JSON "asignaciones"
|
||||||
const regexNotif = /on_arrival\((\{.*?"id":"notificaciones".*?\})\);/s;
|
const regexNotif = /on_arrival\((\{.*?"id":"notificaciones".*?\})\);/s;
|
||||||
@@ -86,25 +88,110 @@ export class SiuService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async authenticateSiu(dni: string, pass: string): Promise<void> {
|
private async authenticateSiu(dni: string, pass: string): Promise<string> {
|
||||||
console.log('Autenticando en SIU...');
|
console.log('Autenticando en SIU...');
|
||||||
const loginData = `usuario=${dni}&password=${pass}&login=Ingresar`;
|
const loginData = `usuario=${encodeURIComponent(dni)}&password=${encodeURIComponent(pass)}&login=Ingresar`;
|
||||||
await CapacitorHttp.post({
|
const headers = this.getCommonHeaders();
|
||||||
|
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||||
|
|
||||||
|
const resLogin: HttpResponse = await CapacitorHttp.post({
|
||||||
url: `${this.BASE_URL}/acceso?auth=form`,
|
url: `${this.BASE_URL}/acceso?auth=form`,
|
||||||
data: loginData,
|
data: loginData,
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
headers
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let cookies = this.extractCookies(resLogin.headers);
|
||||||
|
const stored = await this.getStoredCookies();
|
||||||
|
cookies = this.mergeCookieStrings(cookies, stored);
|
||||||
|
|
||||||
|
const dataStr = this.decodeResponseData(resLogin.data);
|
||||||
|
|
||||||
|
if (dataStr && (dataStr.includes('El usuario o la contraseña no son correctos') || dataStr.includes('error-login') || dataStr.includes('login_error'))) {
|
||||||
|
throw new Error('DNI o Contraseña incorrectos en SIU Guaraní.');
|
||||||
}
|
}
|
||||||
|
|
||||||
private async selectCareer(carreraId: string): Promise<void> {
|
return cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async selectCareer(carreraId: string, currentCookies: string): Promise<string> {
|
||||||
console.log('Seleccionando carrera:', carreraId);
|
console.log('Seleccionando carrera:', carreraId);
|
||||||
await CapacitorHttp.get({
|
const resCambio = await this.getHtml(`${this.BASE_URL}/acceso/cambiar_carrera?id=${carreraId}&op=inicio_alumno`, currentCookies);
|
||||||
url: `${this.BASE_URL}/acceso/cambiar_carrera?id=${carreraId}&op=inicio_alumno`,
|
const resInicio = await this.getHtml(`${this.BASE_URL}/inicio_alumno`, resCambio.cookies);
|
||||||
|
return resInicio.cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getHtml(url: string, cookies: string): Promise<{ html: string; cookies: string }> {
|
||||||
|
let updatedCookies = cookies;
|
||||||
|
const res: HttpResponse = await CapacitorHttp.get({
|
||||||
|
url,
|
||||||
|
headers: this.getCommonHeaders(updatedCookies)
|
||||||
});
|
});
|
||||||
// Hit inicio_alumno to ensure context is established
|
|
||||||
await CapacitorHttp.get({
|
updatedCookies = this.mergeCookies(updatedCookies, res.headers);
|
||||||
url: `${this.BASE_URL}/inicio_alumno`,
|
const stored = await this.getStoredCookies();
|
||||||
|
updatedCookies = this.mergeCookieStrings(updatedCookies, stored);
|
||||||
|
|
||||||
|
let html = this.decodeResponseData(res.data);
|
||||||
|
|
||||||
|
// Fallback: si html es nulo/vacío por codificación no-UTF8 (ej. ISO-8859-1 en SIU), solicitar arraybuffer y decodificar
|
||||||
|
if (!html) {
|
||||||
|
console.log(`Reintentando ${url} con arraybuffer para decodificación ISO-8859-1...`);
|
||||||
|
const resBuffer: HttpResponse = await CapacitorHttp.get({
|
||||||
|
url,
|
||||||
|
responseType: 'arraybuffer',
|
||||||
|
headers: this.getCommonHeaders(updatedCookies)
|
||||||
});
|
});
|
||||||
|
updatedCookies = this.mergeCookies(updatedCookies, resBuffer.headers);
|
||||||
|
html = this.decodeBase64Response(resBuffer.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { html, cookies: updatedCookies };
|
||||||
|
}
|
||||||
|
|
||||||
|
private decodeResponseData(data: any): string {
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
if (data && typeof data === 'object') {
|
||||||
|
return JSON.stringify(data);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
private decodeBase64Response(base64: string): string {
|
||||||
|
if (!base64 || typeof base64 !== 'string') return '';
|
||||||
|
try {
|
||||||
|
const binaryString = window.atob(base64);
|
||||||
|
const bytes = new Uint8Array(binaryString.length);
|
||||||
|
for (let i = 0; i < binaryString.length; i++) {
|
||||||
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const utf8Decoder = new TextDecoder('utf-8', { fatal: true });
|
||||||
|
return utf8Decoder.decode(bytes);
|
||||||
|
} catch {
|
||||||
|
const latinDecoder = new TextDecoder('iso-8859-1');
|
||||||
|
return latinDecoder.decode(bytes);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error decoding base64 response:', e);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getStoredCookies(): Promise<string> {
|
||||||
|
try {
|
||||||
|
const cookieMap = await CapacitorCookies.getCookies({ url: this.BASE_URL });
|
||||||
|
if (cookieMap && typeof cookieMap === 'object') {
|
||||||
|
return Object.entries(cookieMap)
|
||||||
|
.filter(([k, v]) => k && v)
|
||||||
|
.map(([k, v]) => `${k}=${v}`)
|
||||||
|
.join('; ');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// CapacitorCookies can fail gracefully without breaking flow
|
||||||
|
}
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractTobaContent(html: string, pageletId: string = 'pagelet'): string {
|
private extractTobaContent(html: string, pageletId: string = 'pagelet'): string {
|
||||||
@@ -132,34 +219,30 @@ export class SiuService {
|
|||||||
async downloadCertificate(dni: string, pass: string): Promise<{ base64: string, filename: string }> {
|
async downloadCertificate(dni: string, pass: string): Promise<{ base64: string, filename: string }> {
|
||||||
console.log('Iniciando descarga de certificado para:', dni);
|
console.log('Iniciando descarga de certificado para:', dni);
|
||||||
try {
|
try {
|
||||||
await this.authenticateSiu(dni, pass);
|
const authCookies = await this.authenticateSiu(dni, pass);
|
||||||
await this.selectCareer('30');
|
const sessionCookies = await this.selectCareer('30', authCookies);
|
||||||
console.log('Login y selección de carrera (ID 30) listos');
|
console.log('Login y selección de carrera (ID 30) listos');
|
||||||
|
|
||||||
// 1. VALIDAR SI EXISTE UNO VIGENTE (< 30 DÍAS)
|
// 1. VALIDAR SI EXISTE UNO VIGENTE (< 30 DÍAS)
|
||||||
const resSolicitudes: HttpResponse = await CapacitorHttp.get({
|
const { html: rawHtmlSolicitudes, cookies: solicitCookies } = await this.getHtml(`${this.BASE_URL}/solicitudes`, sessionCookies);
|
||||||
url: `${this.BASE_URL}/solicitudes`,
|
|
||||||
});
|
|
||||||
console.log('Página de solicitudes obtenida');
|
console.log('Página de solicitudes obtenida');
|
||||||
|
|
||||||
const contentHtmlSolicitudes = this.extractTobaContent(resSolicitudes.data, 'pagelet');
|
const contentHtmlSolicitudes = this.extractTobaContent(rawHtmlSolicitudes, 'pagelet');
|
||||||
if (contentHtmlSolicitudes) {
|
if (contentHtmlSolicitudes) {
|
||||||
const existingCert = this.findValidCertificate(contentHtmlSolicitudes);
|
const existingCert = this.findValidCertificate(contentHtmlSolicitudes);
|
||||||
if (existingCert) {
|
if (existingCert) {
|
||||||
console.log('Certificado vigente encontrado:', existingCert.filename);
|
console.log('Certificado vigente encontrado:', existingCert.filename);
|
||||||
return await this.downloadFile(existingCert.url, existingCert.filename);
|
return await this.downloadFile(existingCert.url, existingCert.filename, solicitCookies);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. GENERAR NUEVA SOLICITUD (HEADLESS)
|
// 2. GENERAR NUEVA SOLICITUD (HEADLESS)
|
||||||
console.log('No hay certificado vigente o no se pudo leer la tabla. Intentando generar uno nuevo...');
|
console.log('No hay certificado vigente o no se pudo leer la tabla. Intentando generar uno nuevo...');
|
||||||
const resGestion: HttpResponse = await CapacitorHttp.get({
|
const { html: rawHtmlGestion, cookies: gestionCookies } = await this.getHtml(`${this.BASE_URL}/solicitudes/solicitud_gestion`, solicitCookies);
|
||||||
url: `${this.BASE_URL}/solicitudes/solicitud_gestion`,
|
|
||||||
});
|
|
||||||
|
|
||||||
const contentHtmlGestion = this.extractTobaContent(resGestion.data, 'pagelet');
|
const contentHtmlGestion = this.extractTobaContent(rawHtmlGestion, 'pagelet');
|
||||||
if (!contentHtmlGestion) {
|
if (!contentHtmlGestion) {
|
||||||
console.error('HTML completo de gestión no contiene on_arrival de pagelet. Muestra:', resGestion.data.substring(0, 1000));
|
console.error('HTML completo de gestión no contiene on_arrival de pagelet. Muestra:', rawHtmlGestion.substring(0, 1000));
|
||||||
throw new Error('No se pudo localizar el generador (content missing)');
|
throw new Error('No se pudo localizar el generador (content missing)');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +269,7 @@ export class SiuService {
|
|||||||
: `${iframeSrc}?toba_ei_notificar=imprimir`;
|
: `${iframeSrc}?toba_ei_notificar=imprimir`;
|
||||||
|
|
||||||
console.log('Solicitando generación de PDF:', printUrl);
|
console.log('Solicitando generación de PDF:', printUrl);
|
||||||
return await this.downloadFile(printUrl, `Certificado_Alumno_Regular_${new Date().getTime()}.pdf`);
|
return await this.downloadFile(printUrl, `Certificado_Alumno_Regular_${new Date().getTime()}.pdf`, gestionCookies);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error detallado en SIU Certificate:', error);
|
console.error('Error detallado en SIU Certificate:', error);
|
||||||
@@ -237,13 +320,14 @@ export class SiuService {
|
|||||||
return days < 30;
|
return days < 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async downloadFile(url: string, filename: string): Promise<{ base64: string, filename: string }> {
|
private async downloadFile(url: string, filename: string, cookies?: string): Promise<{ base64: string, filename: string }> {
|
||||||
// Si la URL es relativa, completarla
|
// Si la URL es relativa, completarla
|
||||||
const fullUrl = url.startsWith('http') ? url : `${this.BASE_URL}/${url.startsWith('/') ? url.substring(1) : url}`;
|
const fullUrl = url.startsWith('http') ? url : `${this.BASE_URL}/${url.startsWith('/') ? url.substring(1) : url}`;
|
||||||
|
|
||||||
const response: HttpResponse = await CapacitorHttp.get({
|
const response: HttpResponse = await CapacitorHttp.get({
|
||||||
url: fullUrl,
|
url: fullUrl,
|
||||||
responseType: 'blob'
|
responseType: 'blob',
|
||||||
|
headers: this.getCommonHeaders(cookies)
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -252,6 +336,66 @@ export class SiuService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getCommonHeaders(cookies?: string): Record<string, string> {
|
||||||
|
const headers: Record<string, string> = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
|
||||||
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||||
|
'Accept-Language': 'es-AR,es;q=0.9'
|
||||||
|
};
|
||||||
|
if (cookies) {
|
||||||
|
headers['Cookie'] = cookies;
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private extractCookies(headers: Record<string, string> | undefined): string {
|
||||||
|
return this.mergeCookies('', headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private mergeCookies(existingCookies: string, newHeaders: Record<string, string> | undefined): string {
|
||||||
|
if (!newHeaders) return existingCookies;
|
||||||
|
const rawSetCookie: string = newHeaders['set-cookie'] || newHeaders['Set-Cookie'] || '';
|
||||||
|
if (!rawSetCookie) return existingCookies;
|
||||||
|
|
||||||
|
const cookieMap = new Map<string, string>();
|
||||||
|
if (existingCookies) {
|
||||||
|
existingCookies.split(';').forEach(c => {
|
||||||
|
const [k, ...v] = c.trim().split('=');
|
||||||
|
if (k) cookieMap.set(k.trim(), v.join('='));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const newCookies = rawSetCookie.split(/,(?=[^ ])/);
|
||||||
|
newCookies.forEach(c => {
|
||||||
|
const cookiePart = c.trim().split(';')[0];
|
||||||
|
const [k, ...v] = cookiePart.split('=');
|
||||||
|
if (k && v.length > 0) {
|
||||||
|
cookieMap.set(k.trim(), v.join('='));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(cookieMap.entries())
|
||||||
|
.map(([k, v]) => `${k}=${v}`)
|
||||||
|
.join('; ');
|
||||||
|
}
|
||||||
|
|
||||||
|
private mergeCookieStrings(cookies1: string, cookies2: string): string {
|
||||||
|
if (!cookies1) return cookies2 || '';
|
||||||
|
if (!cookies2) return cookies1 || '';
|
||||||
|
const cookieMap = new Map<string, string>();
|
||||||
|
cookies1.split(';').forEach(c => {
|
||||||
|
const [k, ...v] = c.trim().split('=');
|
||||||
|
if (k) cookieMap.set(k.trim(), v.join('='));
|
||||||
|
});
|
||||||
|
cookies2.split(';').forEach(c => {
|
||||||
|
const [k, ...v] = c.trim().split('=');
|
||||||
|
if (k) cookieMap.set(k.trim(), v.join('='));
|
||||||
|
});
|
||||||
|
return Array.from(cookieMap.entries())
|
||||||
|
.map(([k, v]) => `${k}=${v}`)
|
||||||
|
.join('; ');
|
||||||
|
}
|
||||||
|
|
||||||
async saveAndOpenFile(base64Data: string, filename: string): Promise<void> {
|
async saveAndOpenFile(base64Data: string, filename: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const savedFile = await Filesystem.writeFile({
|
const savedFile = await Filesystem.writeFile({
|
||||||
|
|||||||
@@ -35,3 +35,12 @@
|
|||||||
/* @import "@ionic/angular/css/palettes/dark.always.css"; */
|
/* @import "@ionic/angular/css/palettes/dark.always.css"; */
|
||||||
/* @import "@ionic/angular/css/palettes/dark.class.css"; */
|
/* @import "@ionic/angular/css/palettes/dark.class.css"; */
|
||||||
@import "@ionic/angular/css/palettes/dark.system.css";
|
@import "@ionic/angular/css/palettes/dark.system.css";
|
||||||
|
|
||||||
|
/* iOS 85% width for Home segments */
|
||||||
|
.ios .view-segment ion-segment,
|
||||||
|
.view-segment ion-segment.ios {
|
||||||
|
width: 85% !important;
|
||||||
|
max-width: 85% !important;
|
||||||
|
margin-left: auto !important;
|
||||||
|
margin-right: auto !important;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user