diff --git a/refilc/.gitignore b/refilc/.gitignore
index f991fd7..4257c18 100644
--- a/refilc/.gitignore
+++ b/refilc/.gitignore
@@ -46,4 +46,32 @@ app.*.map.json
.symlinks/
Pods
Podfile.lock
-UserInterfaceState.xcuserstate
\ No newline at end of file
+UserInterfaceState.xcuserstate
+**/ios/**/*.mode1v3
+**/ios/**/*.mode2v3
+**/ios/**/*.moved-aside
+**/ios/**/*.pbxuser
+**/ios/**/*.perspectivev3
+**/ios/**/*sync/
+**/ios/**/.sconsign.dblite
+**/ios/**/.tags*
+**/ios/**/.vagrant/
+**/ios/**/DerivedData/
+**/ios/**/Icon?
+**/ios/**/Pods/
+**/ios/**/.symlinks/
+**/ios/**/profile
+**/ios/**/xcuserdata
+**/ios/.generated/
+**/ios/Flutter/.last_build_id
+**/ios/Flutter/App.framework
+**/ios/Flutter/Flutter.framework
+**/ios/Flutter/Flutter.podspec
+**/ios/Flutter/Generated.xcconfig
+**/ios/Flutter/ephemeral
+**/ios/Flutter/app.flx
+**/ios/Flutter/app.zip
+**/ios/Flutter/flutter_assets/
+**/ios/Flutter/flutter_export_environment.sh
+**/ios/ServiceDefinitions.json
+**/ios/Runner/GeneratedPluginRegistrant.*
diff --git a/refilc/build-ipa.sh b/refilc/build-ipa.sh
old mode 100644
new mode 100755
diff --git a/refilc/ios/PrivacyInfo.xcprivacy b/refilc/ios/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000..a1c5b3b
--- /dev/null
+++ b/refilc/ios/PrivacyInfo.xcprivacy
@@ -0,0 +1,20 @@
+
+
+
+
+
+ NSPrivacyAccessedAPITypes
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryUserDefaults
+
+ NSPrivacyAccessedAPITypeReasons
+
+ CA92.1
+
+
+
+
+
\ No newline at end of file
diff --git a/refilc/ios/Runner.xcodeproj/project.pbxproj b/refilc/ios/Runner.xcodeproj/project.pbxproj
index 806d9e6..2cc04b9 100644
--- a/refilc/ios/Runner.xcodeproj/project.pbxproj
+++ b/refilc/ios/Runner.xcodeproj/project.pbxproj
@@ -17,7 +17,13 @@
3127F7A828EAEE8500C2EFB3 /* lesson_model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3127F7A728EAEE8500C2EFB3 /* lesson_model.swift */; };
373A6ECB5FC71FE9D8AF2EDB /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F0ADD56276103500A3016C8 /* Pods_Runner.framework */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
- 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 4F35BF332BE2FFA30098EF72 /* public_vars.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F35BF322BE2FFA30098EF72 /* public_vars.swift */; };
+ 4F35BF352BE2FFD80098EF72 /* LiveActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F35BF342BE2FFD80098EF72 /* LiveActivityManager.swift */; };
+ 4F35BF362BE2FFD80098EF72 /* LiveActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F35BF342BE2FFD80098EF72 /* LiveActivityManager.swift */; };
+ 4F35BF382BE300A70098EF72 /* lesson_model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3127F7A728EAEE8500C2EFB3 /* lesson_model.swift */; };
+ 4F35BF392BE300B10098EF72 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 4F35BF3A2BE301180098EF72 /* public_vars.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F35BF322BE2FFA30098EF72 /* public_vars.swift */; };
+ 4F35BF3E2BE304550098EF72 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4F35BF3D2BE304550098EF72 /* PrivacyInfo.xcprivacy */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
@@ -73,6 +79,10 @@
3127F7A728EAEE8500C2EFB3 /* lesson_model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = lesson_model.swift; sourceTree = ""; };
317DE77A294F6FFB002E323E /* livecard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = livecard.entitlements; sourceTree = ""; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 4F35BF322BE2FFA30098EF72 /* public_vars.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = public_vars.swift; sourceTree = ""; };
+ 4F35BF342BE2FFD80098EF72 /* LiveActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveActivityManager.swift; sourceTree = ""; };
+ 4F35BF3B2BE303A40098EF72 /* app_group_directory.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = app_group_directory.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4F35BF3D2BE304550098EF72 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; };
707F8089D970F81C480F73C4 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
@@ -118,6 +128,7 @@
3127F79728EAEDE300C2EFB3 /* Assets.xcassets */,
3127F79928EAEDE300C2EFB3 /* Info.plist */,
3127F7A528EAEE5900C2EFB3 /* livecard.swift */,
+ 4F35BF342BE2FFD80098EF72 /* LiveActivityManager.swift */,
);
path = livecard;
sourceTree = "";
@@ -125,6 +136,7 @@
6640A963014A9D4F31026053 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 4F35BF3B2BE303A40098EF72 /* app_group_directory.framework */,
1F0ADD56276103500A3016C8 /* Pods_Runner.framework */,
3127F73F28EAEC8A00C2EFB3 /* IntentsUI.framework */,
3127F75528EAECC800C2EFB3 /* WidgetKit.framework */,
@@ -157,6 +169,7 @@
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
+ 4F35BF3D2BE304550098EF72 /* PrivacyInfo.xcprivacy */,
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
3127F78F28EAEDE200C2EFB3 /* livecard */,
@@ -187,6 +200,7 @@
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
+ 4F35BF322BE2FFA30098EF72 /* public_vars.swift */,
);
path = Runner;
sourceTree = "";
@@ -242,7 +256,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastSwiftUpdateCheck = 1410;
+ LastSwiftUpdateCheck = 1530;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
@@ -290,6 +304,7 @@
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+ 4F35BF3E2BE304550098EF72 /* PrivacyInfo.xcprivacy in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -320,6 +335,8 @@
buildActionMask = 12;
files = (
);
+ inputFileListPaths = (
+ );
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
@@ -372,7 +389,7 @@
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
- buildActionMask = 2147483647;
+ buildActionMask = 12;
files = (
);
inputPaths = (
@@ -391,9 +408,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 4F35BF362BE2FFD80098EF72 /* LiveActivityManager.swift in Sources */,
3127F7A828EAEE8500C2EFB3 /* lesson_model.swift in Sources */,
3127F7A428EAEE3D00C2EFB3 /* livecard.intentdefinition in Sources */,
3127F7A628EAEE5900C2EFB3 /* livecard.swift in Sources */,
+ 4F35BF3A2BE301180098EF72 /* public_vars.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -401,8 +420,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
+ 4F35BF392BE300B10098EF72 /* AppDelegate.swift in Sources */,
+ 4F35BF382BE300A70098EF72 /* lesson_model.swift in Sources */,
+ 4F35BF352BE2FFD80098EF72 /* LiveActivityManager.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ 4F35BF332BE2FFA30098EF72 /* public_vars.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -495,7 +517,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
- CURRENT_PROJECT_VERSION = 250;
+ CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -527,7 +549,7 @@
CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 250;
+ CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES;
@@ -535,7 +557,7 @@
INFOPLIST_KEY_CFBundleDisplayName = livecard;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSSupportsLiveActivities = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -569,7 +591,7 @@
CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 250;
+ CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES;
@@ -577,7 +599,7 @@
INFOPLIST_KEY_CFBundleDisplayName = livecard;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSSupportsLiveActivities = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -609,7 +631,7 @@
CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 250;
+ CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES;
@@ -617,7 +639,7 @@
INFOPLIST_KEY_CFBundleDisplayName = livecard;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSSupportsLiveActivities = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -753,7 +775,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
- CURRENT_PROJECT_VERSION = 250;
+ CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -781,7 +803,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
- CURRENT_PROJECT_VERSION = 250;
+ CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
diff --git a/refilc/ios/Runner.xcodeproj/xcuserdata/tmarccci.xcuserdatad/xcschemes/xcschememanagement.plist b/refilc/ios/Runner.xcodeproj/xcuserdata/tmarccci.xcuserdatad/xcschemes/xcschememanagement.plist
index 1c0c029..1970da8 100644
--- a/refilc/ios/Runner.xcodeproj/xcuserdata/tmarccci.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/refilc/ios/Runner.xcodeproj/xcuserdata/tmarccci.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -12,7 +12,7 @@
livecard.xcscheme_^#shared#^_
orderHint
- 78
+ 83
diff --git a/refilc/ios/Runner.xcworkspace/xcuserdata/tmarccci.xcuserdatad/UserInterfaceState.xcuserstate b/refilc/ios/Runner.xcworkspace/xcuserdata/tmarccci.xcuserdatad/UserInterfaceState.xcuserstate
deleted file mode 100644
index 45ab200..0000000
Binary files a/refilc/ios/Runner.xcworkspace/xcuserdata/tmarccci.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ
diff --git a/refilc/ios/Runner/AppDelegate.swift b/refilc/ios/Runner/AppDelegate.swift
index 2c4c46e..a3d1b29 100644
--- a/refilc/ios/Runner/AppDelegate.swift
+++ b/refilc/ios/Runner/AppDelegate.swift
@@ -1,25 +1,113 @@
import UIKit
+import background_fetch
+import ActivityKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
+ private var methodChannel: FlutterMethodChannel?
+
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
-
- // here, Without this code the task will not work.
- //SwiftFlutterForegroundTaskPlugin.setPluginRegistrantCallback(registerPlugins)
- if #available(iOS 10.0, *) {
- UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
+ guard let controller = window?.rootViewController as? FlutterViewController else {
+ fatalError("rootViewController is not type FlutterViewController")
}
-
+ methodChannel = FlutterMethodChannel(name: "hu.refilc/liveactivity",
+ binaryMessenger: controller as! FlutterBinaryMessenger)
+ methodChannel?.setMethodCallHandler({
+ [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
+ guard call.method == "createLiveActivity" || call.method == "endLiveActivity" || call.method == "updateLiveActivity" else {
+ result(FlutterMethodNotImplemented)
+ return
+ }
+ self?.handleMethodCall(call, result: result)
+ })
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
-}
-// here
-func registerPlugins(registry: FlutterPluginRegistry) {
- GeneratedPluginRegistrant.register(with: registry)
+ override func applicationWillTerminate(_ application: UIApplication) {
+ if #available(iOS 16.2, *) {
+ LiveActivityManager.stop()
+ }
+ }
+
+ private func handleMethodCall(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ if call.method == "createLiveActivity" {
+ if let args = call.arguments as? [String: Any] {
+ lessonDataDictionary = args
+ globalLessonData = LessonData(from: lessonDataDictionary)
+ print("swift: megkapott flutter adatok:",lessonDataDictionary)
+ print("Live Activity bekapcsolva az eszközön: ",checkLiveActivityFeatureAvailable())
+ if(checkLiveActivityFeatureAvailable()) {
+ createLiveActivity(with: lessonDataDictionary)
+ result(checkLiveActivityFeatureAvailable())
+ } else {
+ result(nil)
+ }
+
+ } else {
+ result(FlutterError(code: "INVALID_ARGUMENTS", message: "Invalid iOS arguments received", details: nil))
+ }
+ } else if call.method == "updateLiveActivity" {
+ if let args = call.arguments as? [String: Any] {
+ lessonDataDictionary = args
+ globalLessonData = LessonData(from: lessonDataDictionary)
+ updateLiveActivity(with: lessonDataDictionary)
+ result(nil)
+ } else {
+ result(FlutterError(code: "INVALID_ARGUMENTS", message: "Invalid iOS arguments received", details: nil))
+ }
+ } else if call.method == "endLiveActivity" {
+ endLiveActivity()
+ result(nil)
+ }
+ }
+
+ private func createLiveActivity(with activityData: [String: Any]) -> String? {
+ var lessonData = LessonData(from: activityData)
+ print("Live Activity létrehozása...")
+ if #available(iOS 16.2, *) {
+ LiveActivityManager.create()
+ }
+ return nil
+ }
+
+ private func updateLiveActivity(with activityData: [String: Any]) {
+ let lessonData = LessonData(from: activityData)
+ print("swift: megkapott flutter adatok:",lessonDataDictionary)
+ print("Live Activity frissítés...")
+ if #available(iOS 16.2, *) {
+ LiveActivityManager.update()
+ }
+ }
+
+
+ private func endLiveActivity() {
+ print("Live Activity befejezése...")
+ if #available(iOS 16.2, *) {
+ LiveActivityManager.stop()
+ }
+ }
+
+ private func checkIfLiveActivityExists() -> Bool {
+ if let activityID = activityID {
+ if #available(iOS 16.2, *) {
+ return LiveActivityManager.isRunning(activityID)
+ }
+ }
+ return false
+ }
+
+ private func checkLiveActivityFeatureAvailable() -> Bool {
+ if #available(iOS 16.2, *) {
+ guard ActivityAuthorizationInfo().areActivitiesEnabled else {
+ return false
+ }
+ return true
+ }
+ return false
+ }
}
diff --git a/refilc/ios/Runner/Info.plist b/refilc/ios/Runner/Info.plist
index e9ca19a..e32ae93 100644
--- a/refilc/ios/Runner/Info.plist
+++ b/refilc/ios/Runner/Info.plist
@@ -1,137 +1,138 @@
+
+ BGTaskSchedulerPermittedIdentifiers
+
+ com.transistorsoft.refilcnotification
+ com.transistorsoft.refilcliveactivity
+
+ CADisableMinimumFrameDurationOnPhone
+
+ CFBundleAlternateIcons
- BGTaskSchedulerPermittedIdentifiers
-
- com.transistorsoft.fetch
-
- CADisableMinimumFrameDurationOnPhone
-
- CFBundleAlternateIcons
+ refilc_concept
- refilc_concept
-
- CFBundleIconFiles
-
- refilc_concept
-
- UIPrerenderedIcon
-
-
- refilc_default
-
- CFBundleIconFiles
-
- refilc_default
-
- UIPrerenderedIcon
-
-
- refilc_overcomplicated
-
- CFBundleIconFiles
-
- refilc_overcomplicated
-
- UIPrerenderedIcon
-
-
- refilc_pride
-
- CFBundleIconFiles
-
- refilc_pride
-
- UIPrerenderedIcon
-
-
+ CFBundleIconFiles
+
+ refilc_concept
+
+ UIPrerenderedIcon
+
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIcons
+ refilc_default
- CFBundlePrimaryIcon
-
- CFBundleIconFiles
-
-
-
- CFBundleIconName
-
- UIPrerenderedIcon
-
-
+ CFBundleIconFiles
+
+ refilc_default
+
+ UIPrerenderedIcon
+
+
+ refilc_overcomplicated
+
+ CFBundleIconFiles
+
+ refilc_overcomplicated
+
+ UIPrerenderedIcon
+
+
+ refilc_pride
+
+ CFBundleIconFiles
+
+ refilc_pride
+
+ UIPrerenderedIcon
+
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- reFilc
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- $(FLUTTER_BUILD_NAME)
- CFBundleSignature
- ????
- CFBundleURLTypes
-
-
- CFBundleTypeRole
- Editor
- CFBundleURLSchemes
-
- refilcapp
-
-
-
- CFBundleVersion
- $(FLUTTER_BUILD_NUMBER)
- ITSAppUsesNonExemptEncryption
-
- LSApplicationQueriesSchemes
-
- https
- http
-
- LSRequiresIPhoneOS
-
- NSCameraUsageDescription
- The app requires the camera access to set a custom profile picture.
- NSPhotoLibraryUsageDescription
- The app requires the photo library to set a custom profile picture.
- NSSupportsLiveActivities
-
- UIApplicationSupportsIndirectInputEvents
-
- UIBackgroundModes
-
- fetch
- processing
-
- UILaunchStoryboardName
- LaunchScreen
- UIMainStoryboardFile
- Main
- UIStatusBarHidden
-
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
- UISupportedInterfaceOrientations~ipad
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
- UIViewControllerBasedStatusBarAppearance
-
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIcons
+
+ CFBundlePrimaryIcon
+
+ CFBundleIconFiles
+
+
+
+ CFBundleIconName
+
+ UIPrerenderedIcon
+
+
+
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ reFilc
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleSignature
+ ????
+ CFBundleURLTypes
+
+
+ CFBundleTypeRole
+ Editor
+ CFBundleURLSchemes
+
+ refilcapp
+
+
+
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ ITSAppUsesNonExemptEncryption
+
+ LSApplicationQueriesSchemes
+
+ https
+ http
+
+ LSRequiresIPhoneOS
+
+ NSCameraUsageDescription
+ The app requires the camera access to set a custom profile picture.
+ NSPhotoLibraryUsageDescription
+ The app requires the photo library to set a custom profile picture.
+ NSSupportsLiveActivities
+
+ UIApplicationSupportsIndirectInputEvents
+
+ UIBackgroundModes
+
+ fetch
+ processing
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIStatusBarHidden
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+
diff --git a/refilc/ios/Runner/Runner.entitlements b/refilc/ios/Runner/Runner.entitlements
index 8e1d462..127fede 100644
--- a/refilc/ios/Runner/Runner.entitlements
+++ b/refilc/ios/Runner/Runner.entitlements
@@ -5,8 +5,6 @@
aps-environment
development
com.apple.security.application-groups
-
- group.refilc2.livecard
-
+
diff --git a/refilc/ios/Runner/public_vars.swift b/refilc/ios/Runner/public_vars.swift
new file mode 100644
index 0000000..f084d22
--- /dev/null
+++ b/refilc/ios/Runner/public_vars.swift
@@ -0,0 +1,12 @@
+//
+// public_vars.swift
+// Runner
+//
+// Created by Geryy on 02/05/2024.
+//
+
+import Foundation
+
+var lessonDataDictionary: [String: Any] = [:]
+var globalLessonData = LessonData(from: lessonDataDictionary)
+var activityID: String? = ""
diff --git a/refilc/ios/livecard/LiveActivityManager.swift b/refilc/ios/livecard/LiveActivityManager.swift
new file mode 100644
index 0000000..25f9eab
--- /dev/null
+++ b/refilc/ios/livecard/LiveActivityManager.swift
@@ -0,0 +1,92 @@
+import ActivityKit
+import WidgetKit
+import Foundation
+
+public struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable {
+ public typealias LiveDeliveryData = ContentState
+ public struct ContentState: Codable, Hashable {
+ var color: String
+ var icon: String
+ var index: String
+ var title: String
+ var subtitle: String
+ var description: String
+ var startDate: Date
+ var endDate: Date
+ var date: ClosedRange
+ var nextSubject: String
+ var nextRoom: String
+ }
+
+ public var id = UUID()
+}
+
+@available(iOS 16.2, *)
+final class LiveActivityManager {
+ static let shared = LiveActivityManager()
+ var currentActivity: Activity?
+
+ class func create() {
+
+ Task {
+ do {
+ let contentState = LiveActivitiesAppAttributes.ContentState(color: globalLessonData.color, icon: globalLessonData.icon, index: globalLessonData.index, title: globalLessonData.title, subtitle: globalLessonData.subtitle, description: globalLessonData.description, startDate: globalLessonData.startDate, endDate: globalLessonData.endDate, date: globalLessonData.date, nextSubject: globalLessonData.nextSubject, nextRoom: globalLessonData.nextRoom)
+
+ let activityContent = ActivityContent(state: contentState, staleDate: globalLessonData.endDate, relevanceScore: 0)
+
+ let activity = try Activity.request(
+ attributes: LiveActivitiesAppAttributes(),
+ content: activityContent,
+ pushType: nil
+ )
+
+ activityID = activity.id
+ print("Live Activity létrehozva. Azonosító: \(activity.id)")
+ } catch {
+ print("Hiba történt a Live Activity létrehozásakor: \(error)")
+ }
+ }
+ }
+
+ class func update() {
+ Task {
+ for activity in Activity.activities {
+ do {
+ let contentState = LiveActivitiesAppAttributes.ContentState(color: globalLessonData.color, icon: globalLessonData.icon, index: globalLessonData.index, title: globalLessonData.title, subtitle: globalLessonData.subtitle, description: globalLessonData.description, startDate: globalLessonData.startDate, endDate: globalLessonData.endDate, date: globalLessonData.date, nextSubject: globalLessonData.nextSubject, nextRoom: globalLessonData.nextRoom)
+
+ let activityContent = ActivityContent(state: contentState, staleDate: globalLessonData.endDate, relevanceScore: 0)
+
+ await activity.update(activityContent)
+ activityID = activity.id
+ print("Live Activity frissítve. Azonosító: \(activity.id)")
+ } catch {
+ print("Hiba történt a Live Activity frissítésekor: \(error)")
+ }
+ }
+ }
+ }
+
+
+ class func stop() {
+ if (activityID != "") {
+ Task {
+ for activity in Activity.activities{
+ let contentState = LiveActivitiesAppAttributes.ContentState(color: globalLessonData.color, icon: globalLessonData.icon, index: globalLessonData.index, title: globalLessonData.title, subtitle: globalLessonData.subtitle, description: globalLessonData.description, startDate: globalLessonData.startDate, endDate: globalLessonData.endDate, date: globalLessonData.date, nextSubject: globalLessonData.nextSubject, nextRoom: globalLessonData.nextRoom)
+
+ await activity.end(ActivityContent(state: contentState, staleDate: Date.distantFuture),dismissalPolicy: .immediate)
+ }
+ activityID = nil
+ print("Live Activity sikeresen leállítva")
+ }
+ }
+ }
+
+ class func isRunning(_ activityID: String) -> Bool {
+ for activity in Activity.activities {
+ if activity.id == activityID {
+ return true
+ }
+ }
+ return false
+ }
+}
diff --git a/refilc/ios/livecard/lesson_model.swift b/refilc/ios/livecard/lesson_model.swift
index f098b63..f0d9904 100644
--- a/refilc/ios/livecard/lesson_model.swift
+++ b/refilc/ios/livecard/lesson_model.swift
@@ -1,31 +1,40 @@
import Foundation
+import ActivityKit
-class LessonData {
- var color: String
- var icon: String
- var index: String
- var title: String
- var subtitle: String
- var description: String
- var startDate: Date
- var endDate: Date
- var date: ClosedRange
- var nextSubject: String
- var nextRoom: String
-
- init?() {
- let sharedDefault = UserDefaults(suiteName: "group.refilc2.livecard")!
-
- self.color = sharedDefault.string(forKey: "color")!
- self.icon = sharedDefault.string(forKey: "icon")!
- self.index = sharedDefault.string(forKey: "index")!
- self.title = sharedDefault.string(forKey: "title")!
- self.subtitle = sharedDefault.string(forKey: "subtitle")!
- self.description = sharedDefault.string(forKey: "description")!
- self.startDate = Date(timeIntervalSince1970: Double(sharedDefault.string(forKey: "startDate")!)! / 1000)
- self.endDate = Date(timeIntervalSince1970: Double(sharedDefault.string(forKey: "endDate")!)! / 1000)
- date = self.startDate...self.endDate
- self.nextSubject = sharedDefault.string(forKey: "nextSubject")!
- self.nextRoom = sharedDefault.string(forKey: "nextRoom")!
- }
+public struct LessonData {
+ var color: String
+ var icon: String
+ var index: String
+ var title: String
+ var subtitle: String
+ var description: String
+ var startDate: Date
+ var endDate: Date
+ var date: ClosedRange
+ var nextSubject: String
+ var nextRoom: String
+
+ init(from dictionary: [String: Any]) {
+ self.color = dictionary["color"] as? String ?? ""
+ self.icon = dictionary["icon"] as? String ?? ""
+ self.index = dictionary["index"] as? String ?? ""
+ self.title = dictionary["title"] as? String ?? ""
+ self.subtitle = dictionary["subtitle"] as? String ?? ""
+ self.description = dictionary["description"] as? String ?? ""
+ self.nextSubject = dictionary["nextSubject"] as? String ?? ""
+ self.nextRoom = dictionary["nextRoom"] as? String ?? ""
+
+ if let startDateStr = dictionary["startDate"] as? String, let startDateInt = Int(startDateStr) {
+ self.startDate = Date(timeIntervalSince1970: TimeInterval(startDateInt) / 1000)
+ } else {
+ self.startDate = Date()
+ }
+
+ if let endDateStr = dictionary["endDate"] as? String, let endDateInt = Int(endDateStr) {
+ self.endDate = Date(timeIntervalSince1970: TimeInterval(endDateInt) / 1000)
+ } else {
+ self.endDate = Date()
+ }
+ date = self.startDate...self.endDate
+ }
}
diff --git a/refilc/ios/livecard/livecard.entitlements b/refilc/ios/livecard/livecard.entitlements
index 8e1d462..127fede 100644
--- a/refilc/ios/livecard/livecard.entitlements
+++ b/refilc/ios/livecard/livecard.entitlements
@@ -5,8 +5,6 @@
aps-environment
development
com.apple.security.application-groups
-
- group.refilc2.livecard
-
+
diff --git a/refilc/ios/livecard/livecard.swift b/refilc/ios/livecard/livecard.swift
index 3781b3e..f5f27e7 100644
--- a/refilc/ios/livecard/livecard.swift
+++ b/refilc/ios/livecard/livecard.swift
@@ -5,8 +5,8 @@ import SwiftUI
@main
struct Widgets: WidgetBundle {
var body: some Widget {
- if #available(iOS 16.1, *) {
- LiveCardWidget()
+ if #available(iOS 16.2, *) {
+ LiveCardWidget()
}
}
}
@@ -37,169 +37,161 @@ extension Color {
}
}
-
-// We need to redefined live activities pipe
-struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable {
- public struct ContentState: Codable, Hashable { }
-
- var id = UUID()
-}
-
struct LockScreenLiveActivityView: View {
- let context: ActivityViewContext
+ let context: ActivityViewContext
- let lesson = LessonData()
-
- var body: some View {
- HStack(alignment: .center) {
- Image(systemName: lesson!.icon)
- .resizable()
- .aspectRatio(contentMode: .fit)
- .frame(width: CGFloat(30), height: CGFloat(30))
- .padding(.leading, CGFloat(24))
-
- VStack(alignment: .leading) {
+ var body: some View {
HStack(alignment: .center) {
- Text(lesson!.index + lesson!.title)
- .font(.title3)
- .bold()
-
- Text(lesson!.subtitle)
- .font(.subheadline)
- .padding(.trailing, 12)
- }
-
- if (lesson!.description != "") {
- Text(lesson!.description)
- .font(.subheadline)
- }
-
- HStack {
- Image(systemName: "arrow.right")
- .resizable()
- .aspectRatio(contentMode: .fit)
- .frame(width: CGFloat(8), height: CGFloat(8))
- Text(lesson!.nextSubject)
- .font(.caption)
- Text(lesson!.nextRoom)
- .font(.caption2)
- }
- }.padding(15)
-
- Spacer()
-
- Text(timerInterval: lesson!.date, countsDown: true)
- .multilineTextAlignment(.center)
- .frame(width: 85)
- .font(.title2)
- .monospacedDigit()
- .padding(.trailing, CGFloat(24))
- }
- .activityBackgroundTint(
- lesson!.color != "#676767"
- ? Color(hex: lesson!.color)
- // Ha nem megy hat nem megy
- : Color.clear
- )
- }
-}
-
-@available(iOSApplicationExtension 16.1, *)
-struct LiveCardWidget: Widget {
- var body: some WidgetConfiguration {
- /// Live Activity Notification
- ActivityConfiguration(for: LiveActivitiesAppAttributes.self) { context in
- LockScreenLiveActivityView(context: context)
- /// Dynamic Island
- } dynamicIsland: { context in
- let lesson = LessonData()
-
- /// Expanded
- return DynamicIsland {
- DynamicIslandExpandedRegion(.leading) {
- VStack {
- Spacer()
- ProgressView(
- timerInterval: lesson!.date,
- countsDown: true,
- label: {
- Image(systemName: lesson!.icon)
- .resizable()
- .aspectRatio(contentMode: .fit)
- .frame(width: CGFloat(32), height: CGFloat(32))
- },
- currentValueLabel: {
- Image(systemName: lesson!.icon)
- .resizable()
- .aspectRatio(contentMode: .fit)
- .frame(width: CGFloat(32), height: CGFloat(32))
- }
- ).progressViewStyle(.circular)
- }
- }
- DynamicIslandExpandedRegion(.center) {
- VStack(alignment: .leading) {
- Text(lesson!.index + lesson!.title)
- .lineLimit(1)
- .font(.title3)
- .bold()
-
- Text(lesson!.description)
- .lineLimit(2)
- .font(.caption)
- }.padding(EdgeInsets(top: 0.0, leading: 5.0, bottom: 0.0, trailing: 0.0))
- }
- DynamicIslandExpandedRegion(.trailing) {
- VStack {
- Spacer()
- Text(lesson!.subtitle)
- .lineLimit(1)
- .font(.subheadline)
- Spacer()
- }
- }
-
- /// Compact
- } compactLeading: {
- Label {
- Text(lesson!.title)
- } icon: {
- Image(systemName: lesson!.icon)
- }
- .font(.caption2)
- }
- compactTrailing: {
- Text(timerInterval: lesson!.date, countsDown: true)
- .multilineTextAlignment(.center)
- .frame(width: 40)
- .font(.caption2)
-
- /// Collapsed
- } minimal: {
- VStack(alignment: .center, content: {
- ProgressView(
- timerInterval: lesson!.date,
- countsDown: true,
- label: {
- Image(systemName: lesson!.icon)
+ // Ikon
+ Image(systemName: context.state.icon)
.resizable()
.aspectRatio(contentMode: .fit)
- .frame(width: CGFloat(12), height: CGFloat(12))
- },
- currentValueLabel: {
- Image(systemName: lesson!.icon)
- .resizable()
- .aspectRatio(contentMode: .fit)
- .frame(width: CGFloat(12), height: CGFloat(12))
+ .frame(width: CGFloat(30), height: CGFloat(30))
+ .padding(.leading, CGFloat(24))
+
+ VStack(alignment: .center) {
+ // Jelenlegi óra
+ VStack {
+ Text(context.state.index + " " + context.state.title)
+ .font(.body)
+ .bold()
+ .multilineTextAlignment(.center)
+
+ Text("Terem: \(context.state.subtitle)")
+ .italic()
+ .font(.caption)
+ }
+
+ // Leírás
+ if (context.state.description != "") {
+ Text(context.state.description)
+ .font(.subheadline)
+ }
+
+ // Következő óra
+ HStack {
+ Image(systemName: "arrow.right")
+ .resizable()
+ .aspectRatio(contentMode: .fit)
+ .frame(width: CGFloat(8), height: CGFloat(8))
+ Text(context.state.nextSubject)
+ .font(.caption)
+ Text(context.state.nextRoom)
+ .font(.caption2)
+ }
+ .multilineTextAlignment(.center)
}
- ).progressViewStyle(.circular)
- })
- }
- .keylineTint(
- lesson!.color != "#676767"
- ? Color(hex: lesson!.color)
- : Color.clear
- )
+ .padding(15)
+
+ Spacer()
+
+ // Visszaszámláló
+ Text(timerInterval: context.state.date, countsDown: true)
+ .multilineTextAlignment(.center)
+ .frame(width: 85)
+ .font(.title2)
+ .monospacedDigit()
+ .padding(.trailing, CGFloat(24))
+ }
+ .activityBackgroundTint(
+ context.state.color != "#676767"
+ ? Color(hex: context.state.color)
+ : Color.clear
+ )
+ }
+}
+
+@available(iOSApplicationExtension 16.2, *)
+struct LiveCardWidget: Widget {
+ var body: some WidgetConfiguration {
+ /// Live Activity Notification
+ ActivityConfiguration(for: LiveActivitiesAppAttributes.self) { context in
+ LockScreenLiveActivityView(context: context)
+ /// Dynamic Island
+ } dynamicIsland: { context in
+
+ /// Expanded
+ return DynamicIsland {
+ DynamicIslandExpandedRegion(.leading) {
+ VStack {
+ Spacer()
+ ProgressView(
+ timerInterval: context.state.date,
+ countsDown: true,
+ label: {
+ Image(systemName: context.state.icon)
+ .resizable()
+ .aspectRatio(contentMode: .fit)
+ .frame(width: CGFloat(32), height: CGFloat(32))
+ },
+ currentValueLabel: {
+ Image(systemName: context.state.icon)
+ .resizable()
+ .aspectRatio(contentMode: .fit)
+ .frame(width: CGFloat(32), height: CGFloat(32))
+ }
+ ).progressViewStyle(.circular)
+ }
+ }
+ DynamicIslandExpandedRegion(.center) {
+ VStack(alignment: .center) {
+ Text(context.state.index + context.state.title)
+ .lineLimit(1)
+ .font(.body)
+ .bold()
+
+ Text(context.state.subtitle)
+ .lineLimit(1)
+ .font(.subheadline)
+ Spacer()
+
+ Text(context.state.description)
+ .lineLimit(2)
+ .font(.caption)
+ }.padding(EdgeInsets(top: 0.0, leading: 5.0, bottom: 0.0, trailing: 0.0))
+ }
+
+ /// Compact
+ } compactLeading: {
+ Label {
+ Text(context.state.title)
+ } icon: {
+ Image(systemName: context.state.icon)
+ }
+ .font(.caption2)
+ }
+ compactTrailing: {
+ Text(timerInterval: context.state.date, countsDown: true)
+ .multilineTextAlignment(.center)
+ .frame(width: 40)
+ .font(.caption2)
+
+ /// Collapsed
+ } minimal: {
+ VStack(alignment: .center, content: {
+ ProgressView(
+ timerInterval: context.state.date,
+ countsDown: true,
+ label: {
+ Image(systemName: context.state.icon)
+ .resizable()
+ .aspectRatio(contentMode: .fit)
+ .frame(width: CGFloat(12), height: CGFloat(12))
+ },
+ currentValueLabel: {
+ Image(systemName: context.state.icon)
+ .resizable()
+ .aspectRatio(contentMode: .fit)
+ .frame(width: CGFloat(12), height: CGFloat(12))
+ }
+ ).progressViewStyle(.circular)
+ })
+ }
+ .keylineTint(
+ context.state.color != "#676767"
+ ? Color(hex: context.state.color)
+ : Color.clear
+ )
+ }
}
- }
}
diff --git a/refilc/lib/api/providers/live_card_provider.dart b/refilc/lib/api/providers/live_card_provider.dart
index 05197fb..7ace094 100644
--- a/refilc/lib/api/providers/live_card_provider.dart
+++ b/refilc/lib/api/providers/live_card_provider.dart
@@ -3,6 +3,7 @@
import 'dart:async';
import 'dart:io';
+import 'package:refilc/api/providers/liveactivity/platform_channel.dart';
import 'package:refilc/helpers/subject.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc_kreta_api/models/lesson.dart';
@@ -10,7 +11,6 @@ import 'package:refilc_kreta_api/models/week.dart';
import 'package:refilc/utils/format.dart';
import 'package:refilc_kreta_api/providers/timetable_provider.dart';
import 'package:flutter/foundation.dart';
-import 'package:live_activities/live_activities.dart';
import 'package:refilc_mobile_ui/pages/home/live_card/live_card.i18n.dart';
enum LiveCardState {
@@ -29,6 +29,15 @@ class LiveCardProvider extends ChangeNotifier {
Lesson? prevLesson;
List? nextLessons;
+ // new variables
+ static bool hasActivityStarted = false;
+ static bool hasDayEnd = false;
+ static DateTime? storeFirstRunDate;
+ static bool hasActivitySettingsChanged = false;
+ static Map LAData = {};
+ static DateTime? now;
+ //
+
LiveCardState currentState = LiveCardState.empty;
late Timer _timer;
late final TimetableProvider _timetable;
@@ -36,9 +45,6 @@ class LiveCardProvider extends ChangeNotifier {
late Duration _delay;
- final _liveActivitiesPlugin = LiveActivities();
- String? _latestActivityId;
- Map _lastActivity = {};
bool _hasCheckedTimetable = false;
@@ -47,23 +53,6 @@ class LiveCardProvider extends ChangeNotifier {
required SettingsProvider settings,
}) : _timetable = timetable,
_settings = settings {
- if (Platform.isIOS) {
- _liveActivitiesPlugin.areActivitiesEnabled().then((value) {
- // Console log
- if (kDebugMode) {
- print("iOS LiveActivity enabled: $value");
- }
-
- if (value) {
- _liveActivitiesPlugin.init(appGroupId: "group.refilc2.livecard");
-
- _liveActivitiesPlugin.getAllActivitiesIds().then((value) {
- _latestActivityId = value.isNotEmpty ? value.first : null;
- });
- }
- });
- }
-
_timer = Timer.periodic(const Duration(seconds: 1), (timer) => update());
_delay = settings.bellDelayEnabled
? Duration(seconds: settings.bellDelay)
@@ -71,21 +60,6 @@ class LiveCardProvider extends ChangeNotifier {
update();
}
- @override
- void dispose() {
- _timer.cancel();
- if (Platform.isIOS) {
- _liveActivitiesPlugin.areActivitiesEnabled().then((value) {
- if (value) {
- if (_latestActivityId != null) {
- _liveActivitiesPlugin.endActivity(_latestActivityId!);
- }
- }
- });
- }
- super.dispose();
- }
-
// Debugging
static DateTime _now() {
// return DateTime(2023, 9, 27, 9, 30);
@@ -110,31 +84,88 @@ class LiveCardProvider extends ChangeNotifier {
Map toMap() {
switch (currentState) {
+ case LiveCardState.morning:
+ return {
+ "color":
+ '#${_settings.liveActivityColor.toString().substring(10, 16)}',
+ "icon": nextLesson != null
+ ? SubjectIcon.resolveName(subject: nextLesson?.subject)
+ : "book",
+ "title": "Első órádig:",
+ "subtitle": "",
+ "description": "",
+ "startDate": storeFirstRunDate != null ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - (_delay.inMilliseconds)).toString(): "",
+ "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
+ _delay.inMilliseconds)
+ .toString(),
+ "nextSubject": nextLesson != null
+ ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital()
+ : "",
+ "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
+ };
+
+ case LiveCardState.afternoon:
+ return {
+ "color":
+ '#${_settings.liveActivityColor.toString().substring(10, 16)}',
+ "icon": nextLesson != null
+ ? SubjectIcon.resolveName(subject: nextLesson?.subject)
+ : "book",
+ "title": "Első órádig:",
+ "subtitle": "",
+ "description": "",
+ "startDate": storeFirstRunDate != null ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - (_delay.inMilliseconds)).toString(): "",
+ "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
+ _delay.inMilliseconds)
+ .toString(),
+ "nextSubject": nextLesson != null
+ ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital()
+ : "",
+ "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
+ };
+
+ case LiveCardState.night:
+ return {
+ "color":
+ '#${_settings.liveActivityColor.toString().substring(10, 16)}',
+ "icon": nextLesson != null
+ ? SubjectIcon.resolveName(subject: nextLesson?.subject)
+ : "book",
+ "title": "Első órádig:",
+ "subtitle": "",
+ "description": "",
+ "startDate": storeFirstRunDate != null ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - (_delay.inMilliseconds)).toString(): "",
+ "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
+ _delay.inMilliseconds)
+ .toString(),
+ "nextSubject": nextLesson != null
+ ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital()
+ : "",
+ "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
+ };
+
case LiveCardState.duringLesson:
return {
"color":
- '#${_settings.liveActivityColor.toString().substring(10, 16)}',
+ '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": currentLesson != null
? SubjectIcon.resolveName(subject: currentLesson?.subject)
: "book",
"index":
- currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
+ currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
"title": currentLesson != null
- ? currentLesson?.subject.renamedTo ??
- ShortSubject.resolve(subject: currentLesson?.subject)
- .capital()
+ ? currentLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: currentLesson?.subject).capital()
: "",
"subtitle": currentLesson?.room.replaceAll("_", " ") ?? "",
"description": currentLesson?.description ?? "",
"startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) -
- _delay.inMilliseconds)
+ _delay.inMilliseconds)
.toString(),
"endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) -
- _delay.inMilliseconds)
+ _delay.inMilliseconds)
.toString(),
"nextSubject": nextLesson != null
- ? nextLesson?.subject.renamedTo ??
- ShortSubject.resolve(subject: nextLesson?.subject).capital()
+ ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
};
@@ -150,23 +181,21 @@ class LiveCardProvider extends ChangeNotifier {
return {
"color":
- '#${_settings.liveActivityColor.toString().substring(10, 16)}',
+ '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": iconFloorMap[diff] ?? "cup.and.saucer",
"title": "Szünet",
"description": "go $diff".i18n.fill([
diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room
]),
"startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) -
- _delay.inMilliseconds)
+ _delay.inMilliseconds)
.toString(),
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
- _delay.inMilliseconds)
+ _delay.inMilliseconds)
.toString(),
"nextSubject": (nextLesson != null
- ? nextLesson?.subject.renamedTo ??
- ShortSubject.resolve(subject: nextLesson?.subject)
- .capital()
- : "")
+ ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital()
+ : "")
.capital(),
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
"index": "",
@@ -178,37 +207,6 @@ class LiveCardProvider extends ChangeNotifier {
}
void update() async {
- if (Platform.isIOS) {
- _liveActivitiesPlugin.areActivitiesEnabled().then((value) {
- if (value) {
- final cmap = toMap();
- if (!mapEquals(cmap, _lastActivity)) {
- _lastActivity = cmap;
- try {
- if (_lastActivity.isNotEmpty) {
- if (_latestActivityId == null) {
- _liveActivitiesPlugin
- .createActivity(_lastActivity)
- .then((value) => _latestActivityId = value);
- } else {
- _liveActivitiesPlugin.updateActivity(
- _latestActivityId!, _lastActivity);
- }
- } else {
- if (_latestActivityId != null) {
- _liveActivitiesPlugin.endActivity(_latestActivityId!);
- }
- }
- } catch (e) {
- if (kDebugMode) {
- print('ERROR: Unable to create or update iOS LiveActivity!');
- }
- }
- }
- }
- });
- }
-
List today = _today(_timetable);
if (today.isEmpty && !_hasCheckedTimetable) {
@@ -221,15 +219,22 @@ class LiveCardProvider extends ChangeNotifier {
? Duration(seconds: _settings.bellDelay)
: Duration.zero;
- final now = _now().add(_delay);
+
+ DateTime now = _now().add(_delay);
+
+ if ((currentState == LiveCardState.morning ||
+ currentState == LiveCardState.afternoon ||
+ currentState == LiveCardState.night) && storeFirstRunDate == null) {
+ storeFirstRunDate = now;
+ }
// Filter cancelled lessons #20
// Filter label lessons #128
today = today
.where((lesson) =>
- lesson.status?.name != "Elmaradt" &&
- lesson.subject.id != '' &&
- !lesson.isEmpty)
+ lesson.status?.name != "Elmaradt" &&
+ lesson.subject.id != '' &&
+ !lesson.isEmpty)
.toList();
if (today.isNotEmpty) {
@@ -237,7 +242,7 @@ class LiveCardProvider extends ChangeNotifier {
today.sort((a, b) => a.start.compareTo(b.start));
final _lesson = today.firstWhere(
- (l) => l.start.isBefore(now) && l.end.isAfter(now),
+ (l) => l.start.isBefore(now) && l.end.isAfter(now),
orElse: () => Lesson.fromJson({}));
if (_lesson.start.year != 0) {
@@ -283,11 +288,65 @@ class LiveCardProvider extends ChangeNotifier {
currentState = LiveCardState.empty;
}
+ //LIVE ACTIVITIES
+
+ //CREATE
+ if (!hasActivityStarted && nextLesson != null && nextLesson!
+ .start
+ .difference(now)
+ .inMinutes <= 60 && (currentState == LiveCardState.morning ||
+ currentState == LiveCardState.afternoon ||
+ currentState == LiveCardState.night)) {
+ debugPrint(
+ "Az első óra előtt állunk, kevesebb mint egy órával. Létrehozás...");
+ PlatformChannel.createLiveActivity(toMap());
+ hasActivityStarted = true;
+ }
+ else if (!hasActivityStarted && ((currentState == LiveCardState.duringLesson &&
+ currentLesson != null) ||
+ currentState == LiveCardState.duringBreak)) {
+ debugPrint(
+ "Óra van, vagy szünet, de nincs LiveActivity. létrehozás...");
+ PlatformChannel.createLiveActivity(toMap());
+ hasActivityStarted = true;
+ }
+
+ //UPDATE
+ else if (hasActivityStarted) {
+ if (hasActivitySettingsChanged) {
+ debugPrint("Valamelyik beállítás megváltozott. Frissítés...");
+ PlatformChannel.updateLiveActivity(toMap());
+ hasActivitySettingsChanged = false;
+ }
+ else if (nextLesson != null || currentLesson != null) {
+ bool afterPrevLessonEnd = prevLesson != null &&
+ now.subtract(const Duration(seconds: 1)).isBefore(
+ prevLesson!.end) && now.isAfter(prevLesson!.end);
+
+ bool afterCurrentLessonStart = currentLesson != null &&
+ now.subtract(const Duration(seconds: 1)).isBefore(
+ currentLesson!.start) && now.isAfter(currentLesson!.start);
+ if (afterPrevLessonEnd || afterCurrentLessonStart) {
+ debugPrint(
+ "Óra kezdete/vége után 1 másodperccel vagyunk. Frissítés...");
+ PlatformChannel.updateLiveActivity(toMap());
+ }
+ }
+ }
+
+ //END
+ if (hasActivityStarted && !hasDayEnd && nextLesson == null &&
+ now.isAfter(prevLesson!.end)) {
+ debugPrint("Az utolsó óra véget ért. Befejezés...");
+ PlatformChannel.endLiveActivity();
+ hasDayEnd = true;
+ hasActivityStarted = false;
+ }
+ LAData = toMap();
notifyListeners();
}
bool get show => currentState != LiveCardState.empty;
-
Duration get delay => _delay;
bool _sameDate(DateTime a, DateTime b) =>
@@ -296,4 +355,4 @@ class LiveCardProvider extends ChangeNotifier {
List _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? [])
.where((l) => _sameDate(l.date, _now()))
.toList();
-}
+}
\ No newline at end of file
diff --git a/refilc/lib/api/providers/liveactivity/platform_channel.dart b/refilc/lib/api/providers/liveactivity/platform_channel.dart
new file mode 100644
index 0000000..8b782da
--- /dev/null
+++ b/refilc/lib/api/providers/liveactivity/platform_channel.dart
@@ -0,0 +1,43 @@
+import 'dart:async';
+import 'dart:io';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/services.dart';
+
+class PlatformChannel {
+ static const MethodChannel _channel = MethodChannel('hu.refilc/liveactivity');
+
+ static Future createLiveActivity(
+ Map activityData) async {
+ if (Platform.isIOS) {
+ try {
+ debugPrint("creating...");
+ await _channel.invokeMethod('createLiveActivity', activityData);
+ } on PlatformException catch (e) {
+ debugPrint("Hiba történt a Live Activity létrehozásakor: ${e.message}");
+ }
+ }
+ }
+
+ static Future updateLiveActivity(
+ Map activityData) async {
+ if (Platform.isIOS) {
+ try {
+ debugPrint("updating...");
+ await _channel.invokeMethod('updateLiveActivity', activityData);
+ } on PlatformException catch (e) {
+ debugPrint("Hiba történt a Live Activity frissítésekor: ${e.message}");
+ }
+ }
+ }
+
+ static Future endLiveActivity() async {
+ if (Platform.isIOS) {
+ try {
+ debugPrint("finishing...");
+ await _channel.invokeMethod('endLiveActivity');
+ } on PlatformException catch (e) {
+ debugPrint("Hiba történt a Live Activity befejezésekor: ${e.message}");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/refilc/lib/api/providers/sync.dart b/refilc/lib/api/providers/sync.dart
index 52a69ae..d6be0b1 100644
--- a/refilc/lib/api/providers/sync.dart
+++ b/refilc/lib/api/providers/sync.dart
@@ -22,6 +22,9 @@ import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import 'package:home_widget/home_widget.dart';
+import 'live_card_provider.dart';
+import 'liveactivity/platform_channel.dart';
+
// Mutex
bool lock = false;
@@ -86,10 +89,17 @@ Future syncAll(BuildContext context) {
return false;
}
+
+
return Future.wait(tasks).then((value) {
// Unlock
lock = false;
+ if(Platform.isIOS && LiveCardProvider.hasActivityStarted == true){
+ PlatformChannel.endLiveActivity();
+ LiveCardProvider.hasActivityStarted = false;
+ }
+
// Update Widget
if (Platform.isAndroid) updateWidget();
});
diff --git a/refilc/lib/helpers/live_activity_helper.dart b/refilc/lib/helpers/live_activity_helper.dart
new file mode 100644
index 0000000..69a26bc
--- /dev/null
+++ b/refilc/lib/helpers/live_activity_helper.dart
@@ -0,0 +1,15 @@
+import 'package:refilc/api/providers/live_card_provider.dart';
+import '../api/providers/liveactivity/platform_channel.dart';
+
+
+class LiveActivityHelper {
+ @pragma('vm:entry-point')
+ void backgroundJob() async {
+ // initialize provider
+ if (!LiveCardProvider.hasDayEnd) {
+ await PlatformChannel.updateLiveActivity(LiveCardProvider.LAData);
+ } else {
+ await PlatformChannel.endLiveActivity();
+ }
+ }
+}
\ No newline at end of file
diff --git a/refilc/lib/main.dart b/refilc/lib/main.dart
index 818a38b..7b58d0f 100644
--- a/refilc/lib/main.dart
+++ b/refilc/lib/main.dart
@@ -16,6 +16,8 @@ import 'package:refilc_mobile_ui/screens/error_screen.dart';
import 'package:refilc_mobile_ui/screens/error_report_screen.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
+import 'helpers/live_activity_helper.dart';
+
// days without touching grass: 5,843 (16 yrs)
void main() async {
@@ -84,6 +86,7 @@ class Startup {
// Notifications setup
if (!kIsWeb) {
initPlatformState();
+ initAdditionalBackgroundFetch();
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
}
@@ -196,7 +199,12 @@ Future initPlatformState() async {
if (kDebugMode) {
print("[BackgroundFetch] Event received $taskId");
}
- NotificationsHelper().backgroundJob();
+ if (taskId == "com.transistorsoft.refilcliveactivity") {
+ if (!Platform.isIOS) return;
+ LiveActivityHelper().backgroundJob();
+ } else {
+ NotificationsHelper().backgroundJob();
+ }
BackgroundFetch.finish(taskId);
}, (String taskId) async {
// <-- Task timeout handler.
@@ -231,6 +239,50 @@ void backgroundHeadlessTask(HeadlessTask task) {
if (kDebugMode) {
print('[BackgroundFetch] Headless event received.');
}
- NotificationsHelper().backgroundJob();
- BackgroundFetch.finish(task.taskId);
+ if (taskId == "com.transistorsoft.refilcliveactivity") {
+ if (!Platform.isIOS) return;
+ LiveActivityHelper().backgroundJob();
+ } else {
+ NotificationsHelper().backgroundJob();
+ } BackgroundFetch.finish(task.taskId);
+}
+
+Future initAdditionalBackgroundFetch() async {
+ int status = await BackgroundFetch.configure(
+ BackgroundFetchConfig(
+ minimumFetchInterval: 1, // 1 minute
+ stopOnTerminate: false,
+ enableHeadless: true,
+ requiresBatteryNotLow: false,
+ requiresCharging: false,
+ requiresStorageNotLow: false,
+ requiresDeviceIdle: false,
+ requiredNetworkType: NetworkType.ANY,
+ startOnBoot: true), (String taskId) async {
+ // <-- Event handler
+
+ if (kDebugMode) {
+ print("[BackgroundFetch] Event received $taskId");
+ }
+ LiveActivityHelper liveActivityHelper = LiveActivityHelper();
+ liveActivityHelper.backgroundJob();
+
+ BackgroundFetch.finish(taskId);
+ }, (String taskId) async {
+ // <-- Task timeout handler.
+ if (kDebugMode) {
+ print("[BackgroundFetch] TASK TIMEOUT taskId: $taskId");
+ }
+ BackgroundFetch.finish(taskId);
+ });
+ if (kDebugMode) {
+ print('[BackgroundFetch] configure success: $status');
+ }
+ BackgroundFetch.scheduleTask(TaskConfig(
+ taskId: "com.transistorsoft.refilcliveactivity",
+ delay: 300000, // 5 minute
+ periodic: true,
+ forceAlarmManager: true,
+ stopOnTerminate: false,
+ enableHeadless: true));
}
diff --git a/refilc/lib/models/settings.dart b/refilc/lib/models/settings.dart
index ebe191e..9cea67f 100644
--- a/refilc/lib/models/settings.dart
+++ b/refilc/lib/models/settings.dart
@@ -1,5 +1,6 @@
import 'dart:convert';
import 'dart:developer';
+import 'dart:io';
import 'package:flutter/services.dart';
import 'package:refilc/api/providers/database_provider.dart';
@@ -10,6 +11,8 @@ import 'package:refilc/theme/colors/dark_mobile.dart';
import 'package:flutter/material.dart';
import 'package:uuid/uuid.dart';
+import '../api/providers/live_card_provider.dart';
+
enum Pages { home, grades, timetable, notes, absences }
enum UpdateChannel { stable, beta, dev }
@@ -691,6 +694,9 @@ class SettingsProvider extends ChangeNotifier {
if (bellDelay != null && bellDelay != _bellDelay) _bellDelay = bellDelay;
if (bellDelayEnabled != null && bellDelayEnabled != _bellDelayEnabled) {
_bellDelayEnabled = bellDelayEnabled;
+ if(Platform.isIOS){
+ LiveCardProvider.hasActivitySettingsChanged = true;
+ }
}
if (gradeOpeningFun != null && gradeOpeningFun != _gradeOpeningFun) {
_gradeOpeningFun = gradeOpeningFun;
diff --git a/refilc/lib/theme/theme.dart b/refilc/lib/theme/theme.dart
index 755589e..1acae12 100644
--- a/refilc/lib/theme/theme.dart
+++ b/refilc/lib/theme/theme.dart
@@ -187,7 +187,7 @@ class AppTheme {
accentColor == AccentColor.ogfilc) ||
!settings.newColors
? accent
- : ColorsUtils().lighten(accent, amount: 0.3);
+ : ColorsUtils().lighten(accent, amount: 0.22);
// Color newScaffoldBg = ColorsUtils().lighten(accent, amount: 0.4);
Color newTertiary = (accentColor == AccentColor.adaptive ||
accentColor == AccentColor.custom ||
diff --git a/refilc/lib/ui/widgets/lesson/lesson_tile.dart b/refilc/lib/ui/widgets/lesson/lesson_tile.dart
index 43a494b..f2041da 100644
--- a/refilc/lib/ui/widgets/lesson/lesson_tile.dart
+++ b/refilc/lib/ui/widgets/lesson/lesson_tile.dart
@@ -27,7 +27,7 @@ class LessonTile extends StatelessWidget {
this.currentLessonIndicator = true,
this.padding,
this.contentPadding,
- this.showSubTiles = false,
+ this.showSubTiles = true,
});
final Lesson lesson;
@@ -151,7 +151,8 @@ class LessonTile extends StatelessWidget {
child: PanelTitle(title: Text(lesson.name)),
),
child: Padding(
- padding: EdgeInsets.only(bottom: subtiles.isEmpty ? 0.0 : 12.0),
+ padding: EdgeInsets.only(
+ bottom: (subtiles.isNotEmpty && showSubTiles) ? 12.0 : 0.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
@@ -245,7 +246,7 @@ class LessonTile extends StatelessWidget {
? accent.withOpacity(.15)
: Theme.of(context)
.colorScheme
- .secondary
+ .tertiary
.withOpacity(.15),
borderRadius: BorderRadius.circular(10.0),
),
@@ -397,7 +398,7 @@ class LessonTile extends StatelessWidget {
? accent.withOpacity(.15)
: Theme.of(context)
.colorScheme
- .secondary
+ .tertiary
.withOpacity(.15),
borderRadius: BorderRadius.circular(10.0),
),
diff --git a/refilc/pubspec.yaml b/refilc/pubspec.yaml
index 39cc8c6..dfc7c68 100644
--- a/refilc/pubspec.yaml
+++ b/refilc/pubspec.yaml
@@ -3,7 +3,7 @@ description: "Egy nem hivatalos e-KRÉTA kliens, diákoktól diákoknak."
homepage: https://refilc.hu
publish_to: "none"
-version: 5.0.0+253
+version: 5.0.0+255
environment:
sdk: ">=2.17.0 <=3.3.2"
diff --git a/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart b/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart
index a30dd2b..1cca668 100644
--- a/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart
+++ b/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart
@@ -1,9 +1,15 @@
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
+import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart';
import 'package:refilc/api/providers/database_provider.dart';
import 'package:refilc/api/providers/user_provider.dart';
+import 'package:refilc/helpers/subject.dart';
+import 'package:refilc/theme/colors/colors.dart';
+import 'package:refilc/theme/colors/utils.dart';
import 'package:refilc_kreta_api/models/lesson.dart';
+import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart';
import 'package:refilc_mobile_ui/common/panel/panel_button.dart';
+import 'package:refilc_mobile_ui/common/round_border_icon.dart';
import 'package:refilc_mobile_ui/common/viewable.dart';
import 'package:refilc_mobile_ui/common/widgets/card_handle.dart';
import 'package:refilc/ui/widgets/lesson/lesson_tile.dart';
@@ -49,158 +55,164 @@ class LessonViewableState extends State {
if (lsn.subject.id == '' || tile.lesson.isEmpty) return tile;
- return Viewable(
- tile: tile,
- view: CardHandle(child: LessonView(lsn)),
- actions: [
- PanelButton(
- background: true,
- title: Text(
- "edit_lesson".i18n,
- textAlign: TextAlign.center,
- maxLines: 2,
- overflow: TextOverflow.ellipsis,
- ),
- onPressed: () {
- Navigator.of(context, rootNavigator: true).pop();
-
- if (!Provider.of(context, listen: false)
- .hasScope(PremiumScopes.timetableNotes)) {
- PlusLockedFeaturePopup.show(
- context: context, feature: PremiumFeature.timetableNotes);
-
- return;
- }
-
- showDialog(
- context: context,
- builder: (context) => StatefulBuilder(builder: (context, setS) {
- return AlertDialog(
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.all(Radius.circular(14.0))),
- title: Text("edit_lesson".i18n),
- content: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- // description
- TextField(
- controller: _descTxt,
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderSide: const BorderSide(
- color: Colors.grey, width: 1.5),
- borderRadius: BorderRadius.circular(12.0),
- ),
- focusedBorder: OutlineInputBorder(
- borderSide: const BorderSide(
- color: Colors.grey, width: 1.5),
- borderRadius: BorderRadius.circular(12.0),
- ),
- contentPadding:
- const EdgeInsets.symmetric(horizontal: 12.0),
- hintText: 'l_desc'.i18n,
- suffixIcon: IconButton(
- icon: const Icon(
- FeatherIcons.x,
- color: Colors.grey,
- size: 18.0,
- ),
- onPressed: () {
- setState(() {
- _descTxt.text = '';
- });
- },
- ),
- ),
- ),
- // const SizedBox(
- // height: 14.0,
- // ),
- // // class
- // TextField(
- // controller: _descTxt,
- // onEditingComplete: () async {
- // // SharedTheme? theme = await shareProvider.getThemeById(
- // // context,
- // // id: _paintId.text.replaceAll(' ', ''),
- // // );
-
- // // if (theme != null) {
- // // // set theme variable
- // // newThemeByID = theme;
-
- // // _paintId.clear();
- // // } else {
- // // ScaffoldMessenger.of(context).showSnackBar(
- // // CustomSnackBar(
- // // content: Text("theme_not_found".i18n,
- // // style: const TextStyle(color: Colors.white)),
- // // backgroundColor: AppColors.of(context).red,
- // // context: context,
- // // ),
- // // );
- // // }
- // },
- // decoration: InputDecoration(
- // border: OutlineInputBorder(
- // borderSide: const BorderSide(
- // color: Colors.grey, width: 1.5),
- // borderRadius: BorderRadius.circular(12.0),
- // ),
- // focusedBorder: OutlineInputBorder(
- // borderSide: const BorderSide(
- // color: Colors.grey, width: 1.5),
- // borderRadius: BorderRadius.circular(12.0),
- // ),
- // contentPadding:
- // const EdgeInsets.symmetric(horizontal: 12.0),
- // hintText: 'l_desc'.i18n,
- // suffixIcon: IconButton(
- // icon: const Icon(
- // FeatherIcons.x,
- // color: Colors.grey,
- // size: 18.0,
- // ),
- // onPressed: () {
- // setState(() {
- // _descTxt.text = '';
- // });
- // },
- // ),
- // ),
- // ),
- ],
- ),
- actions: [
- TextButton(
- child: Text(
- "cancel".i18n,
- style: const TextStyle(fontWeight: FontWeight.w500),
- ),
- onPressed: () {
- Navigator.of(context).maybePop();
- },
- ),
- TextButton(
- child: Text(
- "done".i18n,
- style: const TextStyle(fontWeight: FontWeight.w500),
- ),
- onPressed: () async {
- saveLesson();
-
- Navigator.of(context).pop();
- setState(() {});
- },
- ),
- ],
- );
- }),
- );
- },
- ),
- ],
+ return LessonTile(
+ lsn,
+ swapDesc: widget.swapDesc,
+ onTap: () => TimetableLessonPopup.show(context: context, lesson: lsn),
);
+
+ // return Viewable(
+ // tile: tile,
+ // view: CardHandle(child: LessonView(lsn)),
+ // actions: [
+ // PanelButton(
+ // background: true,
+ // title: Text(
+ // "edit_lesson".i18n,
+ // textAlign: TextAlign.center,
+ // maxLines: 2,
+ // overflow: TextOverflow.ellipsis,
+ // ),
+ // onPressed: () {
+ // Navigator.of(context, rootNavigator: true).pop();
+
+ // if (!Provider.of(context, listen: false)
+ // .hasScope(PremiumScopes.timetableNotes)) {
+ // PlusLockedFeaturePopup.show(
+ // context: context, feature: PremiumFeature.timetableNotes);
+
+ // return;
+ // }
+
+ // showDialog(
+ // context: context,
+ // builder: (context) => StatefulBuilder(builder: (context, setS) {
+ // return AlertDialog(
+ // shape: const RoundedRectangleBorder(
+ // borderRadius: BorderRadius.all(Radius.circular(14.0))),
+ // title: Text("edit_lesson".i18n),
+ // content: Column(
+ // mainAxisSize: MainAxisSize.min,
+ // children: [
+ // // description
+ // TextField(
+ // controller: _descTxt,
+ // decoration: InputDecoration(
+ // border: OutlineInputBorder(
+ // borderSide: const BorderSide(
+ // color: Colors.grey, width: 1.5),
+ // borderRadius: BorderRadius.circular(12.0),
+ // ),
+ // focusedBorder: OutlineInputBorder(
+ // borderSide: const BorderSide(
+ // color: Colors.grey, width: 1.5),
+ // borderRadius: BorderRadius.circular(12.0),
+ // ),
+ // contentPadding:
+ // const EdgeInsets.symmetric(horizontal: 12.0),
+ // hintText: 'l_desc'.i18n,
+ // suffixIcon: IconButton(
+ // icon: const Icon(
+ // FeatherIcons.x,
+ // color: Colors.grey,
+ // size: 18.0,
+ // ),
+ // onPressed: () {
+ // setState(() {
+ // _descTxt.text = '';
+ // });
+ // },
+ // ),
+ // ),
+ // ),
+ // // const SizedBox(
+ // // height: 14.0,
+ // // ),
+ // // // class
+ // // TextField(
+ // // controller: _descTxt,
+ // // onEditingComplete: () async {
+ // // // SharedTheme? theme = await shareProvider.getThemeById(
+ // // // context,
+ // // // id: _paintId.text.replaceAll(' ', ''),
+ // // // );
+
+ // // // if (theme != null) {
+ // // // // set theme variable
+ // // // newThemeByID = theme;
+
+ // // // _paintId.clear();
+ // // // } else {
+ // // // ScaffoldMessenger.of(context).showSnackBar(
+ // // // CustomSnackBar(
+ // // // content: Text("theme_not_found".i18n,
+ // // // style: const TextStyle(color: Colors.white)),
+ // // // backgroundColor: AppColors.of(context).red,
+ // // // context: context,
+ // // // ),
+ // // // );
+ // // // }
+ // // },
+ // // decoration: InputDecoration(
+ // // border: OutlineInputBorder(
+ // // borderSide: const BorderSide(
+ // // color: Colors.grey, width: 1.5),
+ // // borderRadius: BorderRadius.circular(12.0),
+ // // ),
+ // // focusedBorder: OutlineInputBorder(
+ // // borderSide: const BorderSide(
+ // // color: Colors.grey, width: 1.5),
+ // // borderRadius: BorderRadius.circular(12.0),
+ // // ),
+ // // contentPadding:
+ // // const EdgeInsets.symmetric(horizontal: 12.0),
+ // // hintText: 'l_desc'.i18n,
+ // // suffixIcon: IconButton(
+ // // icon: const Icon(
+ // // FeatherIcons.x,
+ // // color: Colors.grey,
+ // // size: 18.0,
+ // // ),
+ // // onPressed: () {
+ // // setState(() {
+ // // _descTxt.text = '';
+ // // });
+ // // },
+ // // ),
+ // // ),
+ // // ),
+ // ],
+ // ),
+ // actions: [
+ // TextButton(
+ // child: Text(
+ // "cancel".i18n,
+ // style: const TextStyle(fontWeight: FontWeight.w500),
+ // ),
+ // onPressed: () {
+ // Navigator.of(context).maybePop();
+ // },
+ // ),
+ // TextButton(
+ // child: Text(
+ // "done".i18n,
+ // style: const TextStyle(fontWeight: FontWeight.w500),
+ // ),
+ // onPressed: () async {
+ // saveLesson();
+
+ // Navigator.of(context).pop();
+ // setState(() {});
+ // },
+ // ),
+ // ],
+ // );
+ // }),
+ // );
+ // },
+ // ),
+ // ],
+ // );
}
void saveLesson() async {
@@ -218,3 +230,197 @@ class LessonViewableState extends State {
.storeCustomLessonDescriptions(lessonDesc, userId: user.id!);
}
}
+
+class TimetableLessonPopup extends StatelessWidget {
+ const TimetableLessonPopup({super.key, required this.lesson});
+
+ final Lesson lesson;
+
+ static void show({
+ required BuildContext context,
+ required Lesson lesson,
+ }) =>
+ showRoundedModalBottomSheet(
+ context,
+ child: TimetableLessonPopup(
+ lesson: lesson,
+ ),
+ showHandle: false,
+ );
+
+ // IconData _getIcon() => _featureLevels[feature] == PremiumFeatureLevel.cap
+ // ? FilcIcons.kupak
+ // : _featureLevels[feature] == PremiumFeatureLevel.ink
+ // ? FilcIcons.tinta
+ // : FilcIcons.tinta;
+ // Color _getColor(BuildContext context) =>
+ // _featureLevels[feature] == PremiumFeatureLevel.gold
+ // ? const Color(0xFFC89B08)
+ // : Theme.of(context).brightness == Brightness.light
+ // ? const Color(0xff691A9B)
+ // : const Color(0xffA66FC8);
+ // String? _getAsset() => _featureAssets[feature];
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ decoration: BoxDecoration(
+ color: Theme.of(context).scaffoldBackgroundColor,
+ borderRadius: const BorderRadius.vertical(
+ top: Radius.circular(12.0),
+ ),
+ ),
+ child: Stack(
+ children: [
+ SvgPicture.asset(
+ "assets/svg/mesh_bg.svg",
+ // ignore: deprecated_member_use
+ color: ColorsUtils().fade(
+ context, Theme.of(context).scaffoldBackgroundColor,
+ darkenAmount: 0.1, lightenAmount: 0.1),
+ width: MediaQuery.of(context).size.width,
+ ),
+ SizedBox(
+ width: MediaQuery.of(context).size.width,
+ child: Padding(
+ padding: const EdgeInsets.all(18.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Container(
+ width: 40,
+ height: 4,
+ decoration: BoxDecoration(
+ color: ColorsUtils().fade(
+ context, Theme.of(context).scaffoldBackgroundColor,
+ darkenAmount: 0.2, lightenAmount: 0.2),
+ borderRadius: BorderRadius.circular(
+ 2.0,
+ ),
+ ),
+ ),
+ const SizedBox(
+ height: 38.0,
+ ),
+ RoundBorderIcon(
+ icon: Icon(
+ SubjectIcon.resolveVariant(
+ context: context, subject: lesson.subject),
+ ),
+ ),
+ const SizedBox(
+ height: 55.0,
+ ),
+ Container(
+ width: double.infinity,
+ decoration: BoxDecoration(
+ color: Theme.of(context).colorScheme.background,
+ borderRadius: const BorderRadius.vertical(
+ top: Radius.circular(12.0),
+ bottom: Radius.circular(6.0),
+ ),
+ ),
+ padding: const EdgeInsets.all(14.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ '6:09 - 4:20',
+ style: TextStyle(
+ color: AppColors.of(context).text.withOpacity(0.85),
+ fontSize: 14.0,
+ fontWeight: FontWeight.w500,
+ ),
+ ),
+ const SizedBox(
+ height: 12.0,
+ ),
+ Text(
+ lesson.name,
+ style: TextStyle(
+ color: AppColors.of(context).text,
+ fontSize: 20.0,
+ fontWeight: FontWeight.w700,
+ ),
+ ),
+ const SizedBox(
+ height: 8.0,
+ ),
+ Text(
+ lesson.teacher.name,
+ style: TextStyle(
+ color: AppColors.of(context).text.withOpacity(0.9),
+ fontSize: 14.0,
+ fontWeight: FontWeight.w500,
+ ),
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(
+ height: 6.0,
+ ),
+ Container(
+ width: double.infinity,
+ decoration: BoxDecoration(
+ color: Theme.of(context).colorScheme.background,
+ borderRadius: const BorderRadius.vertical(
+ top: Radius.circular(6.0),
+ bottom: Radius.circular(12.0),
+ ),
+ ),
+ padding: const EdgeInsets.all(14.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ lesson.description,
+ style: TextStyle(
+ color: AppColors.of(context).text.withOpacity(0.9),
+ fontSize: 14.0,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(
+ height: 24.0,
+ ),
+ GestureDetector(
+ onTap: () {
+ Navigator.of(context, rootNavigator: true)
+ .pushReplacementNamed('/');
+ },
+ child: Container(
+ width: double.infinity,
+ decoration: BoxDecoration(
+ color: Theme.of(context).colorScheme.background,
+ borderRadius: BorderRadius.circular(12.0),
+ ),
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Text(
+ 'view_subject'.i18n,
+ style: TextStyle(
+ color:
+ AppColors.of(context).text.withOpacity(0.9),
+ fontSize: 18.0,
+ fontWeight: FontWeight.w500,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/refilc_mobile_ui/lib/pages/absences/absences_page.dart b/refilc_mobile_ui/lib/pages/absences/absences_page.dart
index 6b02ce1..ff339db 100644
--- a/refilc_mobile_ui/lib/pages/absences/absences_page.dart
+++ b/refilc_mobile_ui/lib/pages/absences/absences_page.dart
@@ -362,6 +362,7 @@ class AbsencesPageState extends State
List unexcused = [];
List excused = [];
+ List pending = [];
List absencePositions = [];
List finalChartColors = [];
@@ -375,13 +376,14 @@ class AbsencesPageState extends State
.where((e) =>
e.delay == 0 && e.state == Justification.excused)
.toList();
+ pending = absenceProvider.absences
+ .where((e) =>
+ e.delay == 0 && e.state == Justification.pending)
+ .toList();
value1 = excused.length;
value2 = unexcused.length;
- value3 = absenceProvider.absences
- .where((e) =>
- e.delay == 0 && e.state == Justification.pending)
- .length;
+ value3 = pending.length;
title1 = "stat_1".i18n;
title2 = "stat_2".i18n;
suffix = " ${"hr".i18n}";
@@ -394,15 +396,15 @@ class AbsencesPageState extends State
.where((e) =>
e.delay != 0 && e.state == Justification.excused)
.toList();
+ pending = absenceProvider.absences
+ .where((e) =>
+ e.delay != 0 && e.state == Justification.pending)
+ .toList();
value1 = excused.map((e) => e.delay).fold(0, (a, b) => a + b);
value2 =
unexcused.map((e) => e.delay).fold(0, (a, b) => a + b);
- value3 = absenceProvider.absences
- .where((e) =>
- e.delay != 0 && e.state == Justification.pending)
- .map((e) => e.delay)
- .fold(0, (a, b) => a + b);
+ value3 = pending.map((e) => e.delay).fold(0, (a, b) => a + b);
title1 = "stat_3".i18n;
title2 = "stat_4".i18n;
suffix = " ${"min".i18n}";
@@ -417,7 +419,7 @@ class AbsencesPageState extends State
int barTotal =
DateTime.now().difference(DateTime(yr, 09, 01)).inDays;
- [...unexcused, ...excused].forEachIndexed((i, a) {
+ [...unexcused, ...excused, ...pending].forEachIndexed((i, a) {
int abs = DateTime.now().difference(a.date).inDays;
double startPos = (barTotal - abs) / barTotal;
@@ -435,11 +437,14 @@ class AbsencesPageState extends State
end: endPos,
color: a.state == Justification.excused
? Colors.green
- : Colors.red,
+ : a.state == Justification.unexcused
+ ? Colors.red
+ : Colors.orange,
));
- if ([...unexcused, ...excused].length > i + 1) {
+ if ([...unexcused, ...excused, ...pending].length > i + 1) {
int nextAbs = DateTime.now()
- .difference([...unexcused, ...excused][i + 1].date)
+ .difference(
+ [...unexcused, ...excused, ...pending][i + 1].date)
.inDays;
double nextStartPos = (barTotal - nextAbs) / barTotal;
@@ -454,7 +459,8 @@ class AbsencesPageState extends State
// print(value2.toString() + '-total');
// print(absenceChartData.length.toString() + '-chartdata');
- if ((i + 1 == [...unexcused, ...excused].length) &&
+ if ((i + 1 ==
+ [...unexcused, ...excused, ...pending].length) &&
endPos < 0.999) {
absenceChartData.add(AbsenceChartData(
start: endPos,
diff --git a/refilc_mobile_ui/lib/pages/grades/grade_subject_view.dart b/refilc_mobile_ui/lib/pages/grades/grade_subject_view.dart
index 0bb1df2..bc321e0 100644
--- a/refilc_mobile_ui/lib/pages/grades/grade_subject_view.dart
+++ b/refilc_mobile_ui/lib/pages/grades/grade_subject_view.dart
@@ -19,6 +19,7 @@ import 'package:refilc_kreta_api/models/grade.dart';
import 'package:refilc_kreta_api/models/subject.dart';
import 'package:refilc_mobile_ui/common/average_display.dart';
import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart';
+import 'package:refilc_mobile_ui/common/empty.dart';
import 'package:refilc_mobile_ui/common/filter_bar.dart';
import 'package:refilc_mobile_ui/common/panel/panel.dart';
import 'package:refilc_mobile_ui/common/splitted_panel/splitted_panel.dart';
@@ -281,7 +282,7 @@ class _GradeSubjectViewState extends State
title: Text("exams".i18n),
children: _tiles,
))
- : const SizedBox(),
+ : const Empty(),
),
);
diff --git a/refilc_mobile_ui/lib/pages/home/home_page.dart b/refilc_mobile_ui/lib/pages/home/home_page.dart
index 449e521..8a7218e 100644
--- a/refilc_mobile_ui/lib/pages/home/home_page.dart
+++ b/refilc_mobile_ui/lib/pages/home/home_page.dart
@@ -214,7 +214,7 @@ class HomePageState extends State with TickerProviderStateMixin {
// TODO: REMOVE IN PRODUCTION BUILD!!!
// print(_liveCard.currentState);
- // _liveCard.currentState = LiveCardState.duringBreak;
+ // _liveCard.currentState = LiveCardState.duringLesson;
return Scaffold(
body: Stack(
@@ -330,7 +330,7 @@ class HomePageState extends State with TickerProviderStateMixin {
LiveCardState.duringLesson ||
_liveCard.currentState ==
LiveCardState.duringBreak)
- ? 288.0
+ ? 292.0
: 238.0)),
// Live Card
@@ -348,10 +348,15 @@ class HomePageState extends State with TickerProviderStateMixin {
? 0.0
: 62.0) +
MediaQuery.of(context).padding.top,
- bottom: _liveCard.currentState ==
- LiveCardState.morning
+ bottom: (_liveCard.currentState ==
+ LiveCardState.morning)
? 44.0
- : 52.0,
+ : ((_liveCard.currentState ==
+ LiveCardState.duringLesson ||
+ _liveCard.currentState ==
+ LiveCardState.duringBreak)
+ ? 55.0
+ : 52.0),
),
child: Transform.scale(
scale: _liveCardAnimation.value,
diff --git a/refilc_mobile_ui/lib/pages/home/live_card/live_card.dart b/refilc_mobile_ui/lib/pages/home/live_card/live_card.dart
index d6dbcf5..1d36bd2 100644
--- a/refilc_mobile_ui/lib/pages/home/live_card/live_card.dart
+++ b/refilc_mobile_ui/lib/pages/home/live_card/live_card.dart
@@ -6,6 +6,10 @@ import 'package:refilc/helpers/subject.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/ui/widgets/lesson/lesson_tile.dart';
+import 'package:refilc_kreta_api/models/category.dart';
+import 'package:refilc_kreta_api/models/lesson.dart';
+import 'package:refilc_kreta_api/models/subject.dart';
+import 'package:refilc_kreta_api/models/teacher.dart';
import 'package:refilc_mobile_ui/common/panel/panel.dart';
import 'package:refilc_mobile_ui/common/progress_bar.dart';
import 'package:refilc_mobile_ui/common/round_border_icon.dart';
@@ -67,30 +71,30 @@ class LiveCardStateA extends State {
// test
// TODO: REMOVE IN PRODUCTION BUILD!!!
- // liveCard.currentState = LiveCardState.duringBreak;
- // liveCard.nextLesson = Lesson(
- // date: DateTime.now().add(Duration(
- // minutes: 30,
- // )),
- // subject: GradeSubject(
- // category: Category(id: 'asd'), id: 'asd', name: 'Matematika'),
- // lessonIndex: '1',
- // teacher: Teacher(id: 'id', name: 'name'),
- // start: DateTime.now().subtract(Duration(
- // minutes: 30,
- // )),
- // end: DateTime.now().add(Duration(
- // minutes: 15,
- // )),
- // homeworkId: 'homeworkId',
- // id: 'id',
- // description: 'description',
- // room: 'ABC69',
- // groupName: 'groupName',
- // name: 'name',
- // );
+ /*liveCard.currentState = LiveCardState.duringLesson;
+ liveCard.currentLesson = Lesson(
+ date: DateTime.now().add(const Duration(
+ minutes: 30,
+ )),
+ subject: GradeSubject(
+ category: Category(id: 'asd'), id: 'asd', name: 'Matematika'),
+ lessonIndex: '1',
+ teacher: Teacher(id: 'id', name: 'name'),
+ start: DateTime.now().subtract(const Duration(
+ minutes: 30,
+ )),
+ end: DateTime.now().add(const Duration(
+ minutes: 15,
+ )),
+ homeworkId: 'homeworkId',
+ id: 'id',
+ description: 'description',
+ room: 'ABC69',
+ groupName: 'groupName',
+ name: 'name',
+ );*/
- // liveCard.prevLesson = liveCard.nextLesson;
+ liveCard.nextLesson = liveCard.currentLesson;
// final dt = DateTime(2024, 3, 22, 17, 12, 1, 1, 1);
@@ -408,8 +412,9 @@ class LiveCardStateA extends State {
swapRoom: true,
currentLessonIndicator: false,
padding:
- const EdgeInsets.only(top: 8.0, bottom: 4.0),
+ const EdgeInsets.only(top: 6.0, bottom: 4.0),
contentPadding: EdgeInsets.zero,
+ showSubTiles: false,
),
if (!(nextSubject == null &&
progressCurrent == null &&
@@ -520,7 +525,7 @@ class LiveCardStateA extends State {
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
- .secondary
+ .tertiary
.withOpacity(.15),
borderRadius:
BorderRadius.circular(10.0),
diff --git a/refilc_mobile_ui/lib/pages/notes/notes_page.dart b/refilc_mobile_ui/lib/pages/notes/notes_page.dart
index c5ee6c5..61ff85c 100644
--- a/refilc_mobile_ui/lib/pages/notes/notes_page.dart
+++ b/refilc_mobile_ui/lib/pages/notes/notes_page.dart
@@ -135,13 +135,19 @@ class NotesPageState extends State with TickerProviderStateMixin {
title: Text('your_notes'.i18n),
padding: EdgeInsets.zero,
isTransparent: true,
- child: Center(
- child: Wrap(
- spacing: 18.0,
- runSpacing: 18.0,
- children: selfNoteTiles,
- ),
- ),
+ child: selfNoteTiles.length > 1
+ ? Center(
+ child: Wrap(
+ spacing: 18.0,
+ runSpacing: 18.0,
+ children: selfNoteTiles,
+ ),
+ )
+ : Wrap(
+ spacing: 18.0,
+ runSpacing: 18.0,
+ children: selfNoteTiles,
+ ),
));
}
diff --git a/refilc_mobile_ui/lib/screens/login/login_screen.dart b/refilc_mobile_ui/lib/screens/login/login_screen.dart
index 13307f8..a9f2dbd 100644
--- a/refilc_mobile_ui/lib/screens/login/login_screen.dart
+++ b/refilc_mobile_ui/lib/screens/login/login_screen.dart
@@ -1,10 +1,9 @@
// import 'dart:async';
-import 'package:flutter/cupertino.dart';
-import 'package:flutter/widgets.dart';
import 'package:refilc/api/client.dart';
import 'package:refilc/api/login.dart';
import 'package:refilc/theme/colors/colors.dart';
+import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart';
import 'package:refilc_mobile_ui/common/custom_snack_bar.dart';
import 'package:refilc_mobile_ui/common/system_chrome.dart';
import 'package:refilc_mobile_ui/common/widgets/absence/absence_display.dart';
@@ -17,7 +16,6 @@ import 'package:flutter/services.dart';
import 'login_screen.i18n.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter_svg/flutter_svg.dart';
-import 'package:flutter_portal/flutter_portal.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key, this.back = false});
@@ -85,366 +83,479 @@ class LoginScreenState extends State {
precacheImage(const AssetImage('assets/images/showcase2.png'), context);
precacheImage(const AssetImage('assets/images/showcase3.png'), context);
precacheImage(const AssetImage('assets/images/showcase4.png'), context);
+ bool selected = false;
- return Portal(
- child: Scaffold(
- body: Container(
- decoration: const BoxDecoration(color: Color(0xFFDAE4F7)),
- child: SingleChildScrollView(
- physics: const ClampingScrollPhysics(),
- controller: _scrollController,
- child: Container(
- decoration: const BoxDecoration(color: Color(0xFFDAE4F7)),
- width: MediaQuery.of(context).size.width,
- height: MediaQuery.of(context).size.height,
- child: SafeArea(
- child: Column(
- children: [
- // app icon
- Padding(
- padding: const EdgeInsets.only(left: 24, top: 20),
- child: Row(
- children: [
- Image.asset(
- 'assets/icons/ic_rounded.png',
- width: 30.0,
- ),
- const SizedBox(width: 8),
- const Text(
- 'reFilc',
- style: TextStyle(
- color: Color(0xFF050B15),
- fontSize: 18.0,
- fontWeight: FontWeight.bold,
- fontFamily: 'Montserrat'),
- ),
- Material(
- type: MaterialType.transparency,
- child: showBack
- ? BackButton(
- color: AppColors.of(context).text)
- : const SizedBox(height: 48.0),
- ),
- ],
- )),
- Stack(
- alignment: Alignment.bottomCenter,
- children: [
- // Column(
- // mainAxisAlignment: MainAxisAlignment.center,
- // crossAxisAlignment: CrossAxisAlignment.center,
- // children: [
- // const SizedBox(height: 21),
- // CarouselSlider(
- // options: CarouselOptions(
- // height: MediaQuery.of(context).size.height,
- // viewportFraction: 1,
- // autoPlay: true,
- // autoPlayInterval: const Duration(seconds: 6),
- // pauseAutoPlayOnTouch: true),
- // items: [1, 2, 3, 4].map((i) {
- // return Builder(
- // builder: (BuildContext context) {
- // return Column(
- // crossAxisAlignment:
- // CrossAxisAlignment.start,
- // mainAxisAlignment:
- // MainAxisAlignment.start,
- // children: [
- // Padding(
- // padding:
- // const EdgeInsets.only(left: 24),
- // child: Column(
- // crossAxisAlignment:
- // CrossAxisAlignment.start,
- // mainAxisAlignment:
- // MainAxisAlignment.start,
- // children: [
- // Text(
- // "welcome_title_$i".i18n,
- // style: const TextStyle(
- // color: Color(0xFF050B15),
- // fontSize: 19,
- // fontFamily: 'Montserrat',
- // fontWeight:
- // FontWeight.w700,
- // height: 1.3),
- // ),
- // const SizedBox(
- // height: 14.375), //meth
- // Padding(
- // padding:
- // const EdgeInsets.only(
- // right: 20),
- // child: Text(
- // "welcome_text_$i".i18n,
- // style: const TextStyle(
- // color:
- // Color(0xFF050B15),
- // fontFamily: 'FigTree',
- // fontWeight:
- // FontWeight.w500,
- // fontSize: 17,
- // height: 1.3),
- // ),
- // ),
- // ],
- // )),
- // const SizedBox(height: 15.625),
- // Padding(
- // padding: const EdgeInsets.only(
- // left: 16, right: 16),
- // child: Image.asset(
- // 'assets/images/showcase$i.png'))
- // ],
- // );
- // },
- // );
- // }).toList(),
- // ),
- // ],
- // ),
- // Container(
- // height: 250,
- // width: double.infinity,
- // decoration: const BoxDecoration(
- // gradient: LinearGradient(
- // colors: [Color(0x00DAE4F7), Color(0xFFDAE4F7)],
- // stops: [0, 0.1],
- // begin: Alignment.topCenter,
- // end: Alignment.bottomCenter,
- // ),
- // ),
- // child: Padding(
- // padding: const EdgeInsets.only(top: 3),
- // child: Column(
- // children: [
- // SizedBox(
- // height: 48,
- // width: double.infinity,
- // child: Padding(
- // padding: const EdgeInsets.symmetric(
- // horizontal: 16),
- // child: FilledButton(
- // style: ButtonStyle(
- // shape: MaterialStateProperty.all<
- // RoundedRectangleBorder>(
- // const RoundedRectangleBorder(
- // borderRadius: BorderRadius.all(
- // Radius.circular(12)),
- // ))),
- // onPressed: () {},
- // child: Text(
- // "login".i18n,
- // style: const TextStyle(
- // fontFamily: 'Montserrat',
- // fontSize: 20,
- // fontWeight: FontWeight.w700),
- // )),
- // ),
- // ),
- // const SizedBox(height: 8),
- // ],
- // ),
- // ),
- // )
- //
- //
- // TODO: OLD LOGIN FROM HERE
- Column(
- //login buttons and ui starts here
- mainAxisAlignment: MainAxisAlignment.end,
- crossAxisAlignment: CrossAxisAlignment.end,
- children: [
- Padding(
- padding: const EdgeInsets.only(
- left: 22.0,
- right: 22.0,
- top: 0.0,
- ),
- child: AutofillGroup(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.end,
- children: [
- // username
- Padding(
- padding:
- const EdgeInsets.only(bottom: 6.0),
- child: Row(
- mainAxisAlignment:
- MainAxisAlignment.spaceBetween,
- children: [
- Expanded(
- child: Text(
- "username".i18n,
- maxLines: 1,
- style: TextStyle(
- color: AppColors.of(context)
- .loginPrimary,
- fontWeight: FontWeight.w500,
- fontSize: 12.0,
- ),
- ),
- ),
- Expanded(
- child: Text(
- "usernameHint".i18n,
- maxLines: 1,
- textAlign: TextAlign.right,
- style: TextStyle(
- color: AppColors.of(context)
- .loginSecondary,
- fontWeight: FontWeight.w500,
- fontSize: 12.0,
- ),
- ),
- ),
- ],
- ),
- ),
- Padding(
- padding:
- const EdgeInsets.only(bottom: 12.0),
- child: LoginInput(
- style: LoginInputStyle.username,
- controller: usernameController,
- ),
- ),
-
- // password
- Padding(
- padding:
- const EdgeInsets.only(bottom: 6.0),
- child: Row(
- mainAxisAlignment:
- MainAxisAlignment.spaceBetween,
- children: [
- Expanded(
- child: Text(
- "password".i18n,
- maxLines: 1,
- style: TextStyle(
- color: AppColors.of(context)
- .loginPrimary,
- fontWeight: FontWeight.w500,
- fontSize: 12.0,
- ),
- ),
- ),
- Expanded(
- child: Text(
- "passwordHint".i18n,
- maxLines: 1,
- textAlign: TextAlign.right,
- style: TextStyle(
- color: AppColors.of(context)
- .loginSecondary,
- fontWeight: FontWeight.w500,
- fontSize: 12.0,
- ),
- ),
- ),
- ],
- ),
- ),
- Padding(
- padding:
- const EdgeInsets.only(bottom: 12.0),
- child: LoginInput(
- style: LoginInputStyle.password,
- controller: passwordController,
- ),
- ),
-
- // school
- Padding(
- padding:
- const EdgeInsets.only(bottom: 6.0),
- child: Text(
- "school".i18n,
- maxLines: 1,
- style: TextStyle(
- color: AppColors.of(context)
- .loginPrimary,
- fontWeight: FontWeight.w500,
- fontSize: 12.0,
- ),
- ),
- ),
- SchoolInput(
- scroll: _scrollController,
- controller: schoolController,
- ),
- ],
- ),
- ),
- ),
- Padding(
- padding: const EdgeInsets.only(
- top: 35.0,
- left: 22.0,
- right: 22.0,
- ),
- child: Visibility(
- visible: _loginState != LoginState.inProgress,
- replacement: const Padding(
- padding: EdgeInsets.symmetric(vertical: 6.0),
- child: CircularProgressIndicator(
- valueColor: AlwaysStoppedAnimation(
- Colors.white),
- ),
- ),
- child: LoginButton(
- child: Text("login".i18n,
- maxLines: 1,
- style: const TextStyle(
- fontWeight: FontWeight.bold,
- fontSize: 20.0,
- )),
- onPressed: () => _loginAPI(context: context),
- ),
- ),
- ),
- ],
- ),
- // TODO: OLD LOGIN FROM HERE
- ],
- ),
-
- if (_loginState == LoginState.missingFields ||
- _loginState == LoginState.invalidGrant ||
- _loginState == LoginState.failed)
- Padding(
- padding: const EdgeInsets.only(
- top: 8.0, left: 12.0, right: 12.0),
- child: Text(
- [
- "missing_fields",
- "invalid_grant",
- "error"
- ][_loginState.index]
- .i18n,
- style: const TextStyle(
- color: Colors.red,
- fontWeight: FontWeight.w500,
+ return Scaffold(
+ body: Container(
+ decoration: const BoxDecoration(color: Color(0xFFDAE4F7)),
+ child: SingleChildScrollView(
+ physics: const ClampingScrollPhysics(),
+ controller: _scrollController,
+ child: Container(
+ decoration: const BoxDecoration(color: Color(0xFFDAE4F7)),
+ width: MediaQuery.of(context).size.width,
+ height: MediaQuery.of(context).size.height,
+ child: SafeArea(
+ child: Column(
+ children: [
+ // app icon
+ Padding(
+ padding: const EdgeInsets.only(left: 24, top: 20),
+ child: Row(
+ children: [
+ Image.asset(
+ 'assets/icons/ic_rounded.png',
+ width: 30.0,
+ ),
+ const SizedBox(width: 8),
+ const Text(
+ 'reFilc',
+ style: TextStyle(
+ color: Color(0xFF050B15),
+ fontSize: 18.0,
+ fontWeight: FontWeight.bold,
+ fontFamily: 'Montserrat'),
+ ),
+ Material(
+ type: MaterialType.transparency,
+ child: showBack
+ ? BackButton(color: AppColors.of(context).text)
+ : const SizedBox(height: 48.0),
+ ),
+ ],
+ )),
+ Stack(
+ alignment: Alignment.bottomCenter,
+ children: [
+ Column(
+ //login buttons and ui starts here
+ mainAxisAlignment: MainAxisAlignment.end,
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ const SizedBox(height: 21),
+ CarouselSlider(
+ options: CarouselOptions(
+ height: MediaQuery.of(context).size.height,
+ viewportFraction: 1,
+ autoPlay: true,
+ autoPlayInterval: const Duration(seconds: 6),
+ pauseAutoPlayOnTouch: true),
+ items: [1, 2, 3, 4].map((i) {
+ return Builder(
+ builder: (BuildContext context) {
+ return Column(
+ crossAxisAlignment:
+ CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Padding(
+ padding:
+ const EdgeInsets.only(left: 24),
+ child: Column(
+ crossAxisAlignment:
+ CrossAxisAlignment.start,
+ mainAxisAlignment:
+ MainAxisAlignment.start,
+ children: [
+ Text(
+ "welcome_title_$i".i18n,
+ style: const TextStyle(
+ color: Color(0xFF050B15),
+ fontSize: 19,
+ fontFamily: 'Montserrat',
+ fontWeight: FontWeight.w700,
+ height: 1.3),
+ ),
+ const SizedBox(
+ height: 14.375), //meth
+ Padding(
+ padding: const EdgeInsets.only(
+ right: 20),
+ child: Text(
+ "welcome_text_$i".i18n,
+ style: const TextStyle(
+ color: Color(0xFF050B15),
+ fontFamily: 'FigTree',
+ fontWeight:
+ FontWeight.w500,
+ fontSize: 17,
+ height: 1.3),
+ ),
+ ),
+ ],
+ )),
+ const SizedBox(height: 15.625),
+ Padding(
+ padding: const EdgeInsets.only(
+ left: 16, right: 16),
+ child: Image.asset(
+ 'assets/images/showcase$i.png'))
+ ],
+ );
+ },
+ );
+ }).toList(),
+ ),
+ ],
+ ),
+ Container(
+ height: 300,
+ width: double.infinity,
+ decoration: const BoxDecoration(
+ gradient: LinearGradient(
+ colors: [Color(0x00DAE4F7), Color(0xFFDAE4F7)],
+ stops: [0, 0.12],
+ begin: Alignment.topCenter,
+ end: Alignment.bottomCenter,
+ ),
+ ),
+ child: Padding(
+ padding: EdgeInsets.only(top: 50, bottom: MediaQuery.of(context).viewInsets.bottom),
+ child: Column(
+ children: [
+ SizedBox(
+ height: 48,
+ width: double.infinity,
+ child: Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 16),
+ child: FilledButton(
+ style: ButtonStyle(
+ shape: MaterialStateProperty.all<
+ RoundedRectangleBorder>(
+ const RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(
+ Radius.circular(12)),
+ ))),
+ onPressed: () {
+ showModalBottomSheet(
+ backgroundColor: Colors.transparent,
+ context: context,
+ builder: (BuildContext context) {
+ return Container(
+ height: MediaQuery.of(context)
+ .size
+ .height *
+ 0.5 + MediaQuery.of(context).viewInsets.bottom,
+ decoration: const BoxDecoration(
+ color: Color(0xFFDAE4F7),
+ borderRadius: BorderRadius.only(
+ topRight:
+ Radius.circular(24.0),
+ topLeft:
+ Radius.circular(24.0),
+ ),
+ ),
+ child: Column(
+ crossAxisAlignment:
+ CrossAxisAlignment.center,
+ mainAxisAlignment:
+ MainAxisAlignment.start,
+ children: [
+ Padding(
+ padding:
+ const EdgeInsets.only(
+ top: 18),
+ child: Container(
+ decoration:
+ const BoxDecoration(
+ color:
+ Color(0xFFB9C8E5),
+ borderRadius:
+ BorderRadius.only(
+ topRight:
+ Radius.circular(
+ 2.0),
+ topLeft:
+ Radius.circular(
+ 2.0),
+ ),
+ ),
+ width: 40,
+ height: 4,
+ ),
+ ),
+ Container(
+ width: double.infinity,
+ child: AutofillGroup(
+ child: Column(
+ crossAxisAlignment:
+ CrossAxisAlignment
+ .end,
+ children: [
+ // username
+ Padding(
+ padding:
+ const EdgeInsets
+ .only(
+ bottom:
+ 6.0),
+ child: Row(
+ mainAxisAlignment:
+ MainAxisAlignment
+ .spaceBetween,
+ children: [
+ Expanded(
+ child: Text(
+ "username"
+ .i18n,
+ maxLines:
+ 1,
+ style:
+ TextStyle(
+ color: AppColors.of(context)
+ .loginPrimary,
+ fontWeight:
+ FontWeight.w500,
+ fontSize:
+ 12.0,
+ ),
+ ),
+ ),
+ Expanded(
+ child: Text(
+ "usernameHint"
+ .i18n,
+ maxLines:
+ 1,
+ textAlign:
+ TextAlign
+ .right,
+ style:
+ TextStyle(
+ color: AppColors.of(context)
+ .loginSecondary,
+ fontWeight:
+ FontWeight.w500,
+ fontSize:
+ 12.0,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ Padding(
+ padding:
+ const EdgeInsets
+ .only(
+ bottom:
+ 12.0),
+ child: LoginInput(
+ style:
+ LoginInputStyle
+ .username,
+ controller:
+ usernameController,
+ ),
+ ),
+
+ // password
+ Padding(
+ padding:
+ const EdgeInsets
+ .only(
+ bottom:
+ 6.0),
+ child: Row(
+ mainAxisAlignment:
+ MainAxisAlignment
+ .spaceBetween,
+ children: [
+ Expanded(
+ child: Text(
+ "password"
+ .i18n,
+ maxLines:
+ 1,
+ style:
+ TextStyle(
+ color: AppColors.of(context)
+ .loginPrimary,
+ fontWeight:
+ FontWeight.w500,
+ fontSize:
+ 12.0,
+ ),
+ ),
+ ),
+ Expanded(
+ child: Text(
+ "passwordHint"
+ .i18n,
+ maxLines:
+ 1,
+ textAlign:
+ TextAlign
+ .right,
+ style:
+ TextStyle(
+ color: AppColors.of(context)
+ .loginSecondary,
+ fontWeight:
+ FontWeight.w500,
+ fontSize:
+ 12.0,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ Padding(
+ padding:
+ const EdgeInsets
+ .only(
+ bottom:
+ 12.0),
+ child: LoginInput(
+ style:
+ LoginInputStyle
+ .password,
+ controller:
+ passwordController,
+ ),
+ ),
+
+ // school
+ Padding(
+ padding:
+ const EdgeInsets
+ .only(
+ bottom:
+ 6.0),
+ child: Text(
+ "school".i18n,
+ maxLines: 1,
+ style:
+ TextStyle(
+ color: AppColors.of(
+ context)
+ .loginPrimary,
+ fontWeight:
+ FontWeight
+ .w500,
+ fontSize:
+ 12.0,
+ ),
+ ),
+ ),
+ SchoolInput(
+ scroll:
+ _scrollController,
+ controller:
+ schoolController,
+ ),
+ ],
+ ),
+ ),
+ ),
+ const Padding(
+ padding: EdgeInsets.only(
+ left: 22.0,
+ right: 22.0,
+ top: 0.0,
+ ),
+ ),
+ Padding(
+ padding:
+ const EdgeInsets.only(
+ top: 35.0,
+ left: 22.0,
+ right: 22.0,
+ ),
+ child: Visibility(
+ visible: _loginState !=
+ LoginState
+ .inProgress,
+ replacement:
+ const Padding(
+ padding: EdgeInsets
+ .symmetric(
+ vertical:
+ 6.0),
+ child:
+ CircularProgressIndicator(
+ valueColor:
+ AlwaysStoppedAnimation<
+ Color>(
+ Colors
+ .white),
+ ),
+ ),
+ child: LoginButton(
+ child: Text(
+ "login".i18n,
+ maxLines: 1,
+ style:
+ const TextStyle(
+ fontWeight:
+ FontWeight
+ .bold,
+ fontSize: 20.0,
+ )),
+ onPressed: () =>
+ _loginAPI(
+ context:
+ context),
+ ),
+ ),
+ ),
+ ]),
+ );
+ },
+ );
+ },
+ child: Text(
+ "login".i18n,
+ style: const TextStyle(
+ fontFamily: 'Montserrat',
+ fontSize: 20,
+ fontWeight: FontWeight.w700),
+ )),
+ ),
+ ),
+ const SizedBox(height: 8),
+ ],
),
- textAlign: TextAlign.center,
),
),
- // privacy policy
- GestureDetector(
- onTap: () => PrivacyView.show(context),
+ ],
+ ),
+
+ if (_loginState == LoginState.missingFields ||
+ _loginState == LoginState.invalidGrant ||
+ _loginState == LoginState.failed)
+ Padding(
+ padding: const EdgeInsets.only(
+ top: 8.0, left: 12.0, right: 12.0),
child: Text(
- 'privacy'.i18n,
- style: TextStyle(
- color: AppColors.of(context).loginSecondary,
+ [
+ "missing_fields",
+ "invalid_grant",
+ "error"
+ ][_loginState.index]
+ .i18n,
+ style: const TextStyle(
+ color: Colors.red,
fontWeight: FontWeight.w500,
- fontSize: 14.0,
),
+ textAlign: TextAlign.center,
),
),
- ],
- ),
+ // privacy policy
+ GestureDetector(
+ onTap: () => PrivacyView.show(context),
+ child: Text(
+ 'privacy'.i18n,
+ style: TextStyle(
+ color: AppColors.of(context).loginSecondary,
+ fontWeight: FontWeight.w500,
+ fontSize: 14.0,
+ ),
+ ),
+ ),
+ ],
),
),
),
diff --git a/refilc_mobile_ui/lib/screens/settings/settings_helper.dart b/refilc_mobile_ui/lib/screens/settings/settings_helper.dart
index 83c0e6a..e566eea 100644
--- a/refilc_mobile_ui/lib/screens/settings/settings_helper.dart
+++ b/refilc_mobile_ui/lib/screens/settings/settings_helper.dart
@@ -4,6 +4,7 @@ import 'dart:io';
import 'package:flutter_svg/svg.dart';
import 'package:refilc/api/providers/database_provider.dart';
+import 'package:refilc/api/providers/live_card_provider.dart';
import 'package:refilc/api/providers/user_provider.dart';
import 'package:refilc/helpers/quick_actions.dart';
import 'package:refilc/models/settings.dart';
@@ -750,6 +751,9 @@ class _BellDelaySettingState extends State
Provider.of(context, listen: false)
.update(bellDelay: currentDelay.inSeconds);
_tabController.index = currentDelay.inSeconds > 0 ? 1 : 0;
+ if(Platform.isIOS){
+ LiveCardProvider.hasActivitySettingsChanged = true;
+ }
setState(() {});
}
},
@@ -760,6 +764,9 @@ class _BellDelaySettingState extends State
//Provider.of(context, listen: false).update(context, rounding: (r * 10).toInt());
Provider.of(context, listen: false)
.update(bellDelay: currentDelay.inSeconds);
+ if(Platform.isIOS){
+ LiveCardProvider.hasActivitySettingsChanged = true;
+ }
Navigator.of(context).maybePop();
},
),
@@ -897,6 +904,7 @@ class _LiveActivityColorSettingState extends State {
currentColor = k as Color;
settings.update(
liveActivityColor: currentColor.withAlpha(255));
+ LiveCardProvider.hasActivitySettingsChanged = true;
Navigator.of(context).maybePop();
});
},
@@ -913,6 +921,7 @@ class _LiveActivityColorSettingState extends State {
var defaultColors =
SettingsProvider.defaultSettings().liveActivityColor;
settings.update(liveActivityColor: defaultColors);
+ LiveCardProvider.hasActivitySettingsChanged = true;
Navigator.of(context).maybePop();
},
child: Text(SettingsLocalization("reset").i18n),