Merge branch 'dev' of github.com:refilc/naplo into dev

This commit is contained in:
kima 2024-05-04 11:45:00 +02:00
commit 6803ac8642
31 changed files with 1797 additions and 1002 deletions

28
refilc/.gitignore vendored
View File

@ -47,3 +47,31 @@ app.*.map.json
Pods Pods
Podfile.lock Podfile.lock
UserInterfaceState.xcuserstate 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.*

0
refilc/build-ipa.sh Normal file → Executable file
View File

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<!-- [1] background_fetch: UserDefaults -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>
</dict>
</plist>

View File

@ -17,7 +17,13 @@
3127F7A828EAEE8500C2EFB3 /* lesson_model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3127F7A728EAEE8500C2EFB3 /* lesson_model.swift */; }; 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 */; }; 373A6ECB5FC71FE9D8AF2EDB /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F0ADD56276103500A3016C8 /* Pods_Runner.framework */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 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 */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 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 = "<group>"; }; 3127F7A728EAEE8500C2EFB3 /* lesson_model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = lesson_model.swift; sourceTree = "<group>"; };
317DE77A294F6FFB002E323E /* livecard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = livecard.entitlements; sourceTree = "<group>"; }; 317DE77A294F6FFB002E323E /* livecard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = livecard.entitlements; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
4F35BF322BE2FFA30098EF72 /* public_vars.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = public_vars.swift; sourceTree = "<group>"; };
4F35BF342BE2FFD80098EF72 /* LiveActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveActivityManager.swift; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; }; 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 = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@ -118,6 +128,7 @@
3127F79728EAEDE300C2EFB3 /* Assets.xcassets */, 3127F79728EAEDE300C2EFB3 /* Assets.xcassets */,
3127F79928EAEDE300C2EFB3 /* Info.plist */, 3127F79928EAEDE300C2EFB3 /* Info.plist */,
3127F7A528EAEE5900C2EFB3 /* livecard.swift */, 3127F7A528EAEE5900C2EFB3 /* livecard.swift */,
4F35BF342BE2FFD80098EF72 /* LiveActivityManager.swift */,
); );
path = livecard; path = livecard;
sourceTree = "<group>"; sourceTree = "<group>";
@ -125,6 +136,7 @@
6640A963014A9D4F31026053 /* Frameworks */ = { 6640A963014A9D4F31026053 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4F35BF3B2BE303A40098EF72 /* app_group_directory.framework */,
1F0ADD56276103500A3016C8 /* Pods_Runner.framework */, 1F0ADD56276103500A3016C8 /* Pods_Runner.framework */,
3127F73F28EAEC8A00C2EFB3 /* IntentsUI.framework */, 3127F73F28EAEC8A00C2EFB3 /* IntentsUI.framework */,
3127F75528EAECC800C2EFB3 /* WidgetKit.framework */, 3127F75528EAECC800C2EFB3 /* WidgetKit.framework */,
@ -157,6 +169,7 @@
97C146E51CF9000F007C117D = { 97C146E51CF9000F007C117D = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4F35BF3D2BE304550098EF72 /* PrivacyInfo.xcprivacy */,
9740EEB11CF90186004384FC /* Flutter */, 9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
3127F78F28EAEDE200C2EFB3 /* livecard */, 3127F78F28EAEDE200C2EFB3 /* livecard */,
@ -187,6 +200,7 @@
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
4F35BF322BE2FFA30098EF72 /* public_vars.swift */,
); );
path = Runner; path = Runner;
sourceTree = "<group>"; sourceTree = "<group>";
@ -242,7 +256,7 @@
97C146E61CF9000F007C117D /* Project object */ = { 97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 1410; LastSwiftUpdateCheck = 1530;
LastUpgradeCheck = 1510; LastUpgradeCheck = 1510;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
@ -290,6 +304,7 @@
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
4F35BF3E2BE304550098EF72 /* PrivacyInfo.xcprivacy in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -320,6 +335,8 @@
buildActionMask = 12; buildActionMask = 12;
files = ( files = (
); );
inputFileListPaths = (
);
inputPaths = ( inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
); );
@ -372,7 +389,7 @@
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 12;
files = ( files = (
); );
inputPaths = ( inputPaths = (
@ -391,9 +408,11 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
4F35BF362BE2FFD80098EF72 /* LiveActivityManager.swift in Sources */,
3127F7A828EAEE8500C2EFB3 /* lesson_model.swift in Sources */, 3127F7A828EAEE8500C2EFB3 /* lesson_model.swift in Sources */,
3127F7A428EAEE3D00C2EFB3 /* livecard.intentdefinition in Sources */, 3127F7A428EAEE3D00C2EFB3 /* livecard.intentdefinition in Sources */,
3127F7A628EAEE5900C2EFB3 /* livecard.swift in Sources */, 3127F7A628EAEE5900C2EFB3 /* livecard.swift in Sources */,
4F35BF3A2BE301180098EF72 /* public_vars.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -401,8 +420,11 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( 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 */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
4F35BF332BE2FFA30098EF72 /* public_vars.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -495,7 +517,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 250; CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@ -527,7 +549,7 @@
CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements; CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 250; CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@ -535,7 +557,7 @@
INFOPLIST_KEY_CFBundleDisplayName = livecard; INFOPLIST_KEY_CFBundleDisplayName = livecard;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSSupportsLiveActivities = YES; INFOPLIST_KEY_NSSupportsLiveActivities = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.1; IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -569,7 +591,7 @@
CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements; CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 250; CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@ -577,7 +599,7 @@
INFOPLIST_KEY_CFBundleDisplayName = livecard; INFOPLIST_KEY_CFBundleDisplayName = livecard;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSSupportsLiveActivities = YES; INFOPLIST_KEY_NSSupportsLiveActivities = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.1; IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -609,7 +631,7 @@
CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements; CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 250; CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@ -617,7 +639,7 @@
INFOPLIST_KEY_CFBundleDisplayName = livecard; INFOPLIST_KEY_CFBundleDisplayName = livecard;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_NSSupportsLiveActivities = YES; INFOPLIST_KEY_NSSupportsLiveActivities = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.1; IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -753,7 +775,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 250; CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@ -781,7 +803,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 250; CURRENT_PROJECT_VERSION = 255;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;

View File

@ -12,7 +12,7 @@
<key>livecard.xcscheme_^#shared#^_</key> <key>livecard.xcscheme_^#shared#^_</key>
<dict> <dict>
<key>orderHint</key> <key>orderHint</key>
<integer>78</integer> <integer>83</integer>
</dict> </dict>
</dict> </dict>
</dict> </dict>

View File

@ -1,25 +1,113 @@
import UIKit import UIKit
import background_fetch
import ActivityKit
import Flutter import Flutter
@UIApplicationMain @UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate {
private var methodChannel: FlutterMethodChannel?
override func application( override func application(
_ application: UIApplication, _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
GeneratedPluginRegistrant.register(with: self) GeneratedPluginRegistrant.register(with: self)
guard let controller = window?.rootViewController as? FlutterViewController else {
// here, Without this code the task will not work. fatalError("rootViewController is not type FlutterViewController")
//SwiftFlutterForegroundTaskPlugin.setPluginRegistrantCallback(registerPlugins)
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
} }
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) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }
override func applicationWillTerminate(_ application: UIApplication) {
if #available(iOS 16.2, *) {
LiveActivityManager.stop()
}
} }
// here private func handleMethodCall(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
func registerPlugins(registry: FlutterPluginRegistry) { if call.method == "createLiveActivity" {
GeneratedPluginRegistrant.register(with: registry) 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
}
} }

View File

@ -4,7 +4,8 @@
<dict> <dict>
<key>BGTaskSchedulerPermittedIdentifiers</key> <key>BGTaskSchedulerPermittedIdentifiers</key>
<array> <array>
<string>com.transistorsoft.fetch</string> <string>com.transistorsoft.refilcnotification</string>
<string>com.transistorsoft.refilcliveactivity</string>
</array> </array>
<key>CADisableMinimumFrameDurationOnPhone</key> <key>CADisableMinimumFrameDurationOnPhone</key>
<true/> <true/>

View File

@ -5,8 +5,6 @@
<key>aps-environment</key> <key>aps-environment</key>
<string>development</string> <string>development</string>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array> <array/>
<string>group.refilc2.livecard</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -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? = ""

View File

@ -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<Date>
var nextSubject: String
var nextRoom: String
}
public var id = UUID()
}
@available(iOS 16.2, *)
final class LiveActivityManager {
static let shared = LiveActivityManager()
var currentActivity: Activity<LiveActivitiesAppAttributes>?
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<LiveActivitiesAppAttributes>.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<LiveActivitiesAppAttributes>.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<LiveActivitiesAppAttributes>.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<LiveActivitiesAppAttributes>.activities {
if activity.id == activityID {
return true
}
}
return false
}
}

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import ActivityKit
class LessonData { public struct LessonData {
var color: String var color: String
var icon: String var icon: String
var index: String var index: String
@ -13,19 +14,27 @@ class LessonData {
var nextSubject: String var nextSubject: String
var nextRoom: String var nextRoom: String
init?() { init(from dictionary: [String: Any]) {
let sharedDefault = UserDefaults(suiteName: "group.refilc2.livecard")! 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 ?? ""
self.color = sharedDefault.string(forKey: "color")! if let startDateStr = dictionary["startDate"] as? String, let startDateInt = Int(startDateStr) {
self.icon = sharedDefault.string(forKey: "icon")! self.startDate = Date(timeIntervalSince1970: TimeInterval(startDateInt) / 1000)
self.index = sharedDefault.string(forKey: "index")! } else {
self.title = sharedDefault.string(forKey: "title")! self.startDate = Date()
self.subtitle = sharedDefault.string(forKey: "subtitle")! }
self.description = sharedDefault.string(forKey: "description")!
self.startDate = Date(timeIntervalSince1970: Double(sharedDefault.string(forKey: "startDate")!)! / 1000) if let endDateStr = dictionary["endDate"] as? String, let endDateInt = Int(endDateStr) {
self.endDate = Date(timeIntervalSince1970: Double(sharedDefault.string(forKey: "endDate")!)! / 1000) self.endDate = Date(timeIntervalSince1970: TimeInterval(endDateInt) / 1000)
} else {
self.endDate = Date()
}
date = self.startDate...self.endDate date = self.startDate...self.endDate
self.nextSubject = sharedDefault.string(forKey: "nextSubject")!
self.nextRoom = sharedDefault.string(forKey: "nextRoom")!
} }
} }

View File

@ -5,8 +5,6 @@
<key>aps-environment</key> <key>aps-environment</key>
<string>development</string> <string>development</string>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array> <array/>
<string>group.refilc2.livecard</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -5,7 +5,7 @@ import SwiftUI
@main @main
struct Widgets: WidgetBundle { struct Widgets: WidgetBundle {
var body: some Widget { var body: some Widget {
if #available(iOS 16.1, *) { if #available(iOS 16.2, *) {
LiveCardWidget() LiveCardWidget()
} }
} }
@ -37,58 +37,56 @@ extension Color {
} }
} }
// We need to redefined live activities pipe
struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable {
public struct ContentState: Codable, Hashable { }
var id = UUID()
}
struct LockScreenLiveActivityView: View { struct LockScreenLiveActivityView: View {
let context: ActivityViewContext<LiveActivitiesAppAttributes> let context: ActivityViewContext<LiveActivitiesAppAttributes>
let lesson = LessonData()
var body: some View { var body: some View {
HStack(alignment: .center) { HStack(alignment: .center) {
Image(systemName: lesson!.icon) // Ikon
Image(systemName: context.state.icon)
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: CGFloat(30), height: CGFloat(30)) .frame(width: CGFloat(30), height: CGFloat(30))
.padding(.leading, CGFloat(24)) .padding(.leading, CGFloat(24))
VStack(alignment: .leading) { VStack(alignment: .center) {
HStack(alignment: .center) { // Jelenlegi óra
Text(lesson!.index + lesson!.title) VStack {
.font(.title3) Text(context.state.index + " " + context.state.title)
.font(.body)
.bold() .bold()
.multilineTextAlignment(.center)
Text(lesson!.subtitle) Text("Terem: \(context.state.subtitle)")
.font(.subheadline) .italic()
.padding(.trailing, 12) .font(.caption)
} }
if (lesson!.description != "") { // Leírás
Text(lesson!.description) if (context.state.description != "") {
Text(context.state.description)
.font(.subheadline) .font(.subheadline)
} }
// Következő óra
HStack { HStack {
Image(systemName: "arrow.right") Image(systemName: "arrow.right")
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: CGFloat(8), height: CGFloat(8)) .frame(width: CGFloat(8), height: CGFloat(8))
Text(lesson!.nextSubject) Text(context.state.nextSubject)
.font(.caption) .font(.caption)
Text(lesson!.nextRoom) Text(context.state.nextRoom)
.font(.caption2) .font(.caption2)
} }
}.padding(15) .multilineTextAlignment(.center)
}
.padding(15)
Spacer() Spacer()
Text(timerInterval: lesson!.date, countsDown: true) // Visszaszámláló
Text(timerInterval: context.state.date, countsDown: true)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.frame(width: 85) .frame(width: 85)
.font(.title2) .font(.title2)
@ -96,15 +94,14 @@ struct LockScreenLiveActivityView: View {
.padding(.trailing, CGFloat(24)) .padding(.trailing, CGFloat(24))
} }
.activityBackgroundTint( .activityBackgroundTint(
lesson!.color != "#676767" context.state.color != "#676767"
? Color(hex: lesson!.color) ? Color(hex: context.state.color)
// Ha nem megy hat nem megy
: Color.clear : Color.clear
) )
} }
} }
@available(iOSApplicationExtension 16.1, *) @available(iOSApplicationExtension 16.2, *)
struct LiveCardWidget: Widget { struct LiveCardWidget: Widget {
var body: some WidgetConfiguration { var body: some WidgetConfiguration {
/// Live Activity Notification /// Live Activity Notification
@ -112,7 +109,6 @@ struct LiveCardWidget: Widget {
LockScreenLiveActivityView(context: context) LockScreenLiveActivityView(context: context)
/// Dynamic Island /// Dynamic Island
} dynamicIsland: { context in } dynamicIsland: { context in
let lesson = LessonData()
/// Expanded /// Expanded
return DynamicIsland { return DynamicIsland {
@ -120,16 +116,16 @@ struct LiveCardWidget: Widget {
VStack { VStack {
Spacer() Spacer()
ProgressView( ProgressView(
timerInterval: lesson!.date, timerInterval: context.state.date,
countsDown: true, countsDown: true,
label: { label: {
Image(systemName: lesson!.icon) Image(systemName: context.state.icon)
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: CGFloat(32), height: CGFloat(32)) .frame(width: CGFloat(32), height: CGFloat(32))
}, },
currentValueLabel: { currentValueLabel: {
Image(systemName: lesson!.icon) Image(systemName: context.state.icon)
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: CGFloat(32), height: CGFloat(32)) .frame(width: CGFloat(32), height: CGFloat(32))
@ -138,38 +134,34 @@ struct LiveCardWidget: Widget {
} }
} }
DynamicIslandExpandedRegion(.center) { DynamicIslandExpandedRegion(.center) {
VStack(alignment: .leading) { VStack(alignment: .center) {
Text(lesson!.index + lesson!.title) Text(context.state.index + context.state.title)
.lineLimit(1) .lineLimit(1)
.font(.title3) .font(.body)
.bold() .bold()
Text(lesson!.description) Text(context.state.subtitle)
.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) .lineLimit(1)
.font(.subheadline) .font(.subheadline)
Spacer() Spacer()
}
Text(context.state.description)
.lineLimit(2)
.font(.caption)
}.padding(EdgeInsets(top: 0.0, leading: 5.0, bottom: 0.0, trailing: 0.0))
} }
/// Compact /// Compact
} compactLeading: { } compactLeading: {
Label { Label {
Text(lesson!.title) Text(context.state.title)
} icon: { } icon: {
Image(systemName: lesson!.icon) Image(systemName: context.state.icon)
} }
.font(.caption2) .font(.caption2)
} }
compactTrailing: { compactTrailing: {
Text(timerInterval: lesson!.date, countsDown: true) Text(timerInterval: context.state.date, countsDown: true)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.frame(width: 40) .frame(width: 40)
.font(.caption2) .font(.caption2)
@ -178,16 +170,16 @@ struct LiveCardWidget: Widget {
} minimal: { } minimal: {
VStack(alignment: .center, content: { VStack(alignment: .center, content: {
ProgressView( ProgressView(
timerInterval: lesson!.date, timerInterval: context.state.date,
countsDown: true, countsDown: true,
label: { label: {
Image(systemName: lesson!.icon) Image(systemName: context.state.icon)
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: CGFloat(12), height: CGFloat(12)) .frame(width: CGFloat(12), height: CGFloat(12))
}, },
currentValueLabel: { currentValueLabel: {
Image(systemName: lesson!.icon) Image(systemName: context.state.icon)
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: CGFloat(12), height: CGFloat(12)) .frame(width: CGFloat(12), height: CGFloat(12))
@ -196,8 +188,8 @@ struct LiveCardWidget: Widget {
}) })
} }
.keylineTint( .keylineTint(
lesson!.color != "#676767" context.state.color != "#676767"
? Color(hex: lesson!.color) ? Color(hex: context.state.color)
: Color.clear : Color.clear
) )
} }

View File

@ -3,6 +3,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:refilc/api/providers/liveactivity/platform_channel.dart';
import 'package:refilc/helpers/subject.dart'; import 'package:refilc/helpers/subject.dart';
import 'package:refilc/models/settings.dart'; import 'package:refilc/models/settings.dart';
import 'package:refilc_kreta_api/models/lesson.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/utils/format.dart';
import 'package:refilc_kreta_api/providers/timetable_provider.dart'; import 'package:refilc_kreta_api/providers/timetable_provider.dart';
import 'package:flutter/foundation.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'; import 'package:refilc_mobile_ui/pages/home/live_card/live_card.i18n.dart';
enum LiveCardState { enum LiveCardState {
@ -29,6 +29,15 @@ class LiveCardProvider extends ChangeNotifier {
Lesson? prevLesson; Lesson? prevLesson;
List<Lesson>? nextLessons; List<Lesson>? nextLessons;
// new variables
static bool hasActivityStarted = false;
static bool hasDayEnd = false;
static DateTime? storeFirstRunDate;
static bool hasActivitySettingsChanged = false;
static Map<String, String> LAData = {};
static DateTime? now;
//
LiveCardState currentState = LiveCardState.empty; LiveCardState currentState = LiveCardState.empty;
late Timer _timer; late Timer _timer;
late final TimetableProvider _timetable; late final TimetableProvider _timetable;
@ -36,9 +45,6 @@ class LiveCardProvider extends ChangeNotifier {
late Duration _delay; late Duration _delay;
final _liveActivitiesPlugin = LiveActivities();
String? _latestActivityId;
Map<String, String> _lastActivity = {};
bool _hasCheckedTimetable = false; bool _hasCheckedTimetable = false;
@ -47,23 +53,6 @@ class LiveCardProvider extends ChangeNotifier {
required SettingsProvider settings, required SettingsProvider settings,
}) : _timetable = timetable, }) : _timetable = timetable,
_settings = settings { _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()); _timer = Timer.periodic(const Duration(seconds: 1), (timer) => update());
_delay = settings.bellDelayEnabled _delay = settings.bellDelayEnabled
? Duration(seconds: settings.bellDelay) ? Duration(seconds: settings.bellDelay)
@ -71,21 +60,6 @@ class LiveCardProvider extends ChangeNotifier {
update(); update();
} }
@override
void dispose() {
_timer.cancel();
if (Platform.isIOS) {
_liveActivitiesPlugin.areActivitiesEnabled().then((value) {
if (value) {
if (_latestActivityId != null) {
_liveActivitiesPlugin.endActivity(_latestActivityId!);
}
}
});
}
super.dispose();
}
// Debugging // Debugging
static DateTime _now() { static DateTime _now() {
// return DateTime(2023, 9, 27, 9, 30); // return DateTime(2023, 9, 27, 9, 30);
@ -110,6 +84,66 @@ class LiveCardProvider extends ChangeNotifier {
Map<String, String> toMap() { Map<String, String> toMap() {
switch (currentState) { 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: case LiveCardState.duringLesson:
return { return {
"color": "color":
@ -120,9 +154,7 @@ class LiveCardProvider extends ChangeNotifier {
"index": "index":
currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "", currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
"title": currentLesson != null "title": currentLesson != null
? currentLesson?.subject.renamedTo ?? ? currentLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: currentLesson?.subject).capital()
ShortSubject.resolve(subject: currentLesson?.subject)
.capital()
: "", : "",
"subtitle": currentLesson?.room.replaceAll("_", " ") ?? "", "subtitle": currentLesson?.room.replaceAll("_", " ") ?? "",
"description": currentLesson?.description ?? "", "description": currentLesson?.description ?? "",
@ -133,8 +165,7 @@ class LiveCardProvider extends ChangeNotifier {
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": nextLesson != null "nextSubject": nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital()
ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "", : "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
@ -163,9 +194,7 @@ class LiveCardProvider extends ChangeNotifier {
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": (nextLesson != null "nextSubject": (nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital()
ShortSubject.resolve(subject: nextLesson?.subject)
.capital()
: "") : "")
.capital(), .capital(),
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
@ -178,37 +207,6 @@ class LiveCardProvider extends ChangeNotifier {
} }
void update() async { 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<Lesson> today = _today(_timetable); List<Lesson> today = _today(_timetable);
if (today.isEmpty && !_hasCheckedTimetable) { if (today.isEmpty && !_hasCheckedTimetable) {
@ -221,7 +219,14 @@ class LiveCardProvider extends ChangeNotifier {
? Duration(seconds: _settings.bellDelay) ? Duration(seconds: _settings.bellDelay)
: Duration.zero; : 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 cancelled lessons #20
// Filter label lessons #128 // Filter label lessons #128
@ -283,11 +288,65 @@ class LiveCardProvider extends ChangeNotifier {
currentState = LiveCardState.empty; 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(); notifyListeners();
} }
bool get show => currentState != LiveCardState.empty; bool get show => currentState != LiveCardState.empty;
Duration get delay => _delay; Duration get delay => _delay;
bool _sameDate(DateTime a, DateTime b) => bool _sameDate(DateTime a, DateTime b) =>

View File

@ -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<void> createLiveActivity(
Map<String, dynamic> 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<void> updateLiveActivity(
Map<String, dynamic> 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<void> 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}");
}
}
}
}

View File

@ -22,6 +22,9 @@ import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:home_widget/home_widget.dart'; import 'package:home_widget/home_widget.dart';
import 'live_card_provider.dart';
import 'liveactivity/platform_channel.dart';
// Mutex // Mutex
bool lock = false; bool lock = false;
@ -86,10 +89,17 @@ Future<void> syncAll(BuildContext context) {
return false; return false;
} }
return Future.wait(tasks).then((value) { return Future.wait(tasks).then((value) {
// Unlock // Unlock
lock = false; lock = false;
if(Platform.isIOS && LiveCardProvider.hasActivityStarted == true){
PlatformChannel.endLiveActivity();
LiveCardProvider.hasActivityStarted = false;
}
// Update Widget // Update Widget
if (Platform.isAndroid) updateWidget(); if (Platform.isAndroid) updateWidget();
}); });

View File

@ -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();
}
}
}

View File

@ -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:refilc_mobile_ui/screens/error_report_screen.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'helpers/live_activity_helper.dart';
// days without touching grass: 5,843 (16 yrs) // days without touching grass: 5,843 (16 yrs)
void main() async { void main() async {
@ -84,6 +86,7 @@ class Startup {
// Notifications setup // Notifications setup
if (!kIsWeb) { if (!kIsWeb) {
initPlatformState(); initPlatformState();
initAdditionalBackgroundFetch();
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
} }
@ -196,7 +199,12 @@ Future<void> initPlatformState() async {
if (kDebugMode) { if (kDebugMode) {
print("[BackgroundFetch] Event received $taskId"); print("[BackgroundFetch] Event received $taskId");
} }
if (taskId == "com.transistorsoft.refilcliveactivity") {
if (!Platform.isIOS) return;
LiveActivityHelper().backgroundJob();
} else {
NotificationsHelper().backgroundJob(); NotificationsHelper().backgroundJob();
}
BackgroundFetch.finish(taskId); BackgroundFetch.finish(taskId);
}, (String taskId) async { }, (String taskId) async {
// <-- Task timeout handler. // <-- Task timeout handler.
@ -231,6 +239,50 @@ void backgroundHeadlessTask(HeadlessTask task) {
if (kDebugMode) { if (kDebugMode) {
print('[BackgroundFetch] Headless event received.'); print('[BackgroundFetch] Headless event received.');
} }
if (taskId == "com.transistorsoft.refilcliveactivity") {
if (!Platform.isIOS) return;
LiveActivityHelper().backgroundJob();
} else {
NotificationsHelper().backgroundJob(); NotificationsHelper().backgroundJob();
BackgroundFetch.finish(task.taskId); } BackgroundFetch.finish(task.taskId);
}
Future<void> 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));
} }

View File

@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'dart:io';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:refilc/api/providers/database_provider.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:flutter/material.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import '../api/providers/live_card_provider.dart';
enum Pages { home, grades, timetable, notes, absences } enum Pages { home, grades, timetable, notes, absences }
enum UpdateChannel { stable, beta, dev } enum UpdateChannel { stable, beta, dev }
@ -691,6 +694,9 @@ class SettingsProvider extends ChangeNotifier {
if (bellDelay != null && bellDelay != _bellDelay) _bellDelay = bellDelay; if (bellDelay != null && bellDelay != _bellDelay) _bellDelay = bellDelay;
if (bellDelayEnabled != null && bellDelayEnabled != _bellDelayEnabled) { if (bellDelayEnabled != null && bellDelayEnabled != _bellDelayEnabled) {
_bellDelayEnabled = bellDelayEnabled; _bellDelayEnabled = bellDelayEnabled;
if(Platform.isIOS){
LiveCardProvider.hasActivitySettingsChanged = true;
}
} }
if (gradeOpeningFun != null && gradeOpeningFun != _gradeOpeningFun) { if (gradeOpeningFun != null && gradeOpeningFun != _gradeOpeningFun) {
_gradeOpeningFun = gradeOpeningFun; _gradeOpeningFun = gradeOpeningFun;

View File

@ -187,7 +187,7 @@ class AppTheme {
accentColor == AccentColor.ogfilc) || accentColor == AccentColor.ogfilc) ||
!settings.newColors !settings.newColors
? accent ? accent
: ColorsUtils().lighten(accent, amount: 0.3); : ColorsUtils().lighten(accent, amount: 0.22);
// Color newScaffoldBg = ColorsUtils().lighten(accent, amount: 0.4); // Color newScaffoldBg = ColorsUtils().lighten(accent, amount: 0.4);
Color newTertiary = (accentColor == AccentColor.adaptive || Color newTertiary = (accentColor == AccentColor.adaptive ||
accentColor == AccentColor.custom || accentColor == AccentColor.custom ||

View File

@ -27,7 +27,7 @@ class LessonTile extends StatelessWidget {
this.currentLessonIndicator = true, this.currentLessonIndicator = true,
this.padding, this.padding,
this.contentPadding, this.contentPadding,
this.showSubTiles = false, this.showSubTiles = true,
}); });
final Lesson lesson; final Lesson lesson;
@ -151,7 +151,8 @@ class LessonTile extends StatelessWidget {
child: PanelTitle(title: Text(lesson.name)), child: PanelTitle(title: Text(lesson.name)),
), ),
child: Padding( 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( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -245,7 +246,7 @@ class LessonTile extends StatelessWidget {
? accent.withOpacity(.15) ? accent.withOpacity(.15)
: Theme.of(context) : Theme.of(context)
.colorScheme .colorScheme
.secondary .tertiary
.withOpacity(.15), .withOpacity(.15),
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
), ),
@ -397,7 +398,7 @@ class LessonTile extends StatelessWidget {
? accent.withOpacity(.15) ? accent.withOpacity(.15)
: Theme.of(context) : Theme.of(context)
.colorScheme .colorScheme
.secondary .tertiary
.withOpacity(.15), .withOpacity(.15),
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
), ),

View File

@ -3,7 +3,7 @@ description: "Egy nem hivatalos e-KRÉTA kliens, diákoktól diákoknak."
homepage: https://refilc.hu homepage: https://refilc.hu
publish_to: "none" publish_to: "none"
version: 5.0.0+253 version: 5.0.0+255
environment: environment:
sdk: ">=2.17.0 <=3.3.2" sdk: ">=2.17.0 <=3.3.2"

View File

@ -1,9 +1,15 @@
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:refilc/api/providers/database_provider.dart'; import 'package:refilc/api/providers/database_provider.dart';
import 'package:refilc/api/providers/user_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_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/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/viewable.dart';
import 'package:refilc_mobile_ui/common/widgets/card_handle.dart'; import 'package:refilc_mobile_ui/common/widgets/card_handle.dart';
import 'package:refilc/ui/widgets/lesson/lesson_tile.dart'; import 'package:refilc/ui/widgets/lesson/lesson_tile.dart';
@ -49,98 +55,48 @@ class LessonViewableState extends State<LessonViewable> {
if (lsn.subject.id == '' || tile.lesson.isEmpty) return tile; if (lsn.subject.id == '' || tile.lesson.isEmpty) return tile;
return Viewable( return LessonTile(
tile: tile, lsn,
view: CardHandle(child: LessonView(lsn)), swapDesc: widget.swapDesc,
actions: [ onTap: () => TimetableLessonPopup.show(context: context, lesson: lsn),
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<PlusProvider>(context, listen: false) // return Viewable(
.hasScope(PremiumScopes.timetableNotes)) { // tile: tile,
PlusLockedFeaturePopup.show( // view: CardHandle(child: LessonView(lsn)),
context: context, feature: PremiumFeature.timetableNotes); // actions: [
// PanelButton(
return; // background: true,
} // title: Text(
// "edit_lesson".i18n,
showDialog( // textAlign: TextAlign.center,
context: context, // maxLines: 2,
builder: (context) => StatefulBuilder(builder: (context, setS) { // overflow: TextOverflow.ellipsis,
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 // onPressed: () {
// Navigator.of(context, rootNavigator: true).pop();
// if (!Provider.of<PlusProvider>(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( // TextField(
// controller: _descTxt, // 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( // decoration: InputDecoration(
// border: OutlineInputBorder( // border: OutlineInputBorder(
// borderSide: const BorderSide( // borderSide: const BorderSide(
@ -169,38 +125,94 @@ class LessonViewableState extends State<LessonViewable> {
// ), // ),
// ), // ),
// ), // ),
], // // const SizedBox(
), // // height: 14.0,
actions: [ // // ),
TextButton( // // // class
child: Text( // // TextField(
"cancel".i18n, // // controller: _descTxt,
style: const TextStyle(fontWeight: FontWeight.w500), // // onEditingComplete: () async {
), // // // SharedTheme? theme = await shareProvider.getThemeById(
onPressed: () { // // // context,
Navigator.of(context).maybePop(); // // // id: _paintId.text.replaceAll(' ', ''),
}, // // // );
),
TextButton(
child: Text(
"done".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () async {
saveLesson();
Navigator.of(context).pop(); // // // if (theme != null) {
setState(() {}); // // // // 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 { void saveLesson() async {
@ -218,3 +230,197 @@ class LessonViewableState extends State<LessonViewable> {
.storeCustomLessonDescriptions(lessonDesc, userId: user.id!); .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,
),
),
],
),
),
),
],
),
),
),
],
),
);
}
}

View File

@ -362,6 +362,7 @@ class AbsencesPageState extends State<AbsencesPage>
List<Absence> unexcused = []; List<Absence> unexcused = [];
List<Absence> excused = []; List<Absence> excused = [];
List<Absence> pending = [];
List<double> absencePositions = []; List<double> absencePositions = [];
List<Color> finalChartColors = []; List<Color> finalChartColors = [];
@ -375,13 +376,14 @@ class AbsencesPageState extends State<AbsencesPage>
.where((e) => .where((e) =>
e.delay == 0 && e.state == Justification.excused) e.delay == 0 && e.state == Justification.excused)
.toList(); .toList();
pending = absenceProvider.absences
.where((e) =>
e.delay == 0 && e.state == Justification.pending)
.toList();
value1 = excused.length; value1 = excused.length;
value2 = unexcused.length; value2 = unexcused.length;
value3 = absenceProvider.absences value3 = pending.length;
.where((e) =>
e.delay == 0 && e.state == Justification.pending)
.length;
title1 = "stat_1".i18n; title1 = "stat_1".i18n;
title2 = "stat_2".i18n; title2 = "stat_2".i18n;
suffix = " ${"hr".i18n}"; suffix = " ${"hr".i18n}";
@ -394,15 +396,15 @@ class AbsencesPageState extends State<AbsencesPage>
.where((e) => .where((e) =>
e.delay != 0 && e.state == Justification.excused) e.delay != 0 && e.state == Justification.excused)
.toList(); .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); value1 = excused.map((e) => e.delay).fold(0, (a, b) => a + b);
value2 = value2 =
unexcused.map((e) => e.delay).fold(0, (a, b) => a + b); unexcused.map((e) => e.delay).fold(0, (a, b) => a + b);
value3 = absenceProvider.absences value3 = pending.map((e) => e.delay).fold(0, (a, b) => a + b);
.where((e) =>
e.delay != 0 && e.state == Justification.pending)
.map((e) => e.delay)
.fold(0, (a, b) => a + b);
title1 = "stat_3".i18n; title1 = "stat_3".i18n;
title2 = "stat_4".i18n; title2 = "stat_4".i18n;
suffix = " ${"min".i18n}"; suffix = " ${"min".i18n}";
@ -417,7 +419,7 @@ class AbsencesPageState extends State<AbsencesPage>
int barTotal = int barTotal =
DateTime.now().difference(DateTime(yr, 09, 01)).inDays; 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; int abs = DateTime.now().difference(a.date).inDays;
double startPos = (barTotal - abs) / barTotal; double startPos = (barTotal - abs) / barTotal;
@ -435,11 +437,14 @@ class AbsencesPageState extends State<AbsencesPage>
end: endPos, end: endPos,
color: a.state == Justification.excused color: a.state == Justification.excused
? Colors.green ? 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() int nextAbs = DateTime.now()
.difference([...unexcused, ...excused][i + 1].date) .difference(
[...unexcused, ...excused, ...pending][i + 1].date)
.inDays; .inDays;
double nextStartPos = (barTotal - nextAbs) / barTotal; double nextStartPos = (barTotal - nextAbs) / barTotal;
@ -454,7 +459,8 @@ class AbsencesPageState extends State<AbsencesPage>
// print(value2.toString() + '-total'); // print(value2.toString() + '-total');
// print(absenceChartData.length.toString() + '-chartdata'); // print(absenceChartData.length.toString() + '-chartdata');
if ((i + 1 == [...unexcused, ...excused].length) && if ((i + 1 ==
[...unexcused, ...excused, ...pending].length) &&
endPos < 0.999) { endPos < 0.999) {
absenceChartData.add(AbsenceChartData( absenceChartData.add(AbsenceChartData(
start: endPos, start: endPos,

View File

@ -19,6 +19,7 @@ import 'package:refilc_kreta_api/models/grade.dart';
import 'package:refilc_kreta_api/models/subject.dart'; import 'package:refilc_kreta_api/models/subject.dart';
import 'package:refilc_mobile_ui/common/average_display.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/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/filter_bar.dart';
import 'package:refilc_mobile_ui/common/panel/panel.dart'; import 'package:refilc_mobile_ui/common/panel/panel.dart';
import 'package:refilc_mobile_ui/common/splitted_panel/splitted_panel.dart'; import 'package:refilc_mobile_ui/common/splitted_panel/splitted_panel.dart';
@ -281,7 +282,7 @@ class _GradeSubjectViewState extends State<GradeSubjectView>
title: Text("exams".i18n), title: Text("exams".i18n),
children: _tiles, children: _tiles,
)) ))
: const SizedBox(), : const Empty(),
), ),
); );

View File

@ -214,7 +214,7 @@ class HomePageState extends State<HomePage> with TickerProviderStateMixin {
// TODO: REMOVE IN PRODUCTION BUILD!!! // TODO: REMOVE IN PRODUCTION BUILD!!!
// print(_liveCard.currentState); // print(_liveCard.currentState);
// _liveCard.currentState = LiveCardState.duringBreak; // _liveCard.currentState = LiveCardState.duringLesson;
return Scaffold( return Scaffold(
body: Stack( body: Stack(
@ -330,7 +330,7 @@ class HomePageState extends State<HomePage> with TickerProviderStateMixin {
LiveCardState.duringLesson || LiveCardState.duringLesson ||
_liveCard.currentState == _liveCard.currentState ==
LiveCardState.duringBreak) LiveCardState.duringBreak)
? 288.0 ? 292.0
: 238.0)), : 238.0)),
// Live Card // Live Card
@ -348,10 +348,15 @@ class HomePageState extends State<HomePage> with TickerProviderStateMixin {
? 0.0 ? 0.0
: 62.0) + : 62.0) +
MediaQuery.of(context).padding.top, MediaQuery.of(context).padding.top,
bottom: _liveCard.currentState == bottom: (_liveCard.currentState ==
LiveCardState.morning LiveCardState.morning)
? 44.0 ? 44.0
: 52.0, : ((_liveCard.currentState ==
LiveCardState.duringLesson ||
_liveCard.currentState ==
LiveCardState.duringBreak)
? 55.0
: 52.0),
), ),
child: Transform.scale( child: Transform.scale(
scale: _liveCardAnimation.value, scale: _liveCardAnimation.value,

View File

@ -6,6 +6,10 @@ import 'package:refilc/helpers/subject.dart';
import 'package:refilc/models/settings.dart'; import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/ui/widgets/lesson/lesson_tile.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/panel/panel.dart';
import 'package:refilc_mobile_ui/common/progress_bar.dart'; import 'package:refilc_mobile_ui/common/progress_bar.dart';
import 'package:refilc_mobile_ui/common/round_border_icon.dart'; import 'package:refilc_mobile_ui/common/round_border_icon.dart';
@ -67,30 +71,30 @@ class LiveCardStateA extends State<LiveCard> {
// test // test
// TODO: REMOVE IN PRODUCTION BUILD!!! // TODO: REMOVE IN PRODUCTION BUILD!!!
// liveCard.currentState = LiveCardState.duringBreak; /*liveCard.currentState = LiveCardState.duringLesson;
// liveCard.nextLesson = Lesson( liveCard.currentLesson = Lesson(
// date: DateTime.now().add(Duration( date: DateTime.now().add(const Duration(
// minutes: 30, minutes: 30,
// )), )),
// subject: GradeSubject( subject: GradeSubject(
// category: Category(id: 'asd'), id: 'asd', name: 'Matematika'), category: Category(id: 'asd'), id: 'asd', name: 'Matematika'),
// lessonIndex: '1', lessonIndex: '1',
// teacher: Teacher(id: 'id', name: 'name'), teacher: Teacher(id: 'id', name: 'name'),
// start: DateTime.now().subtract(Duration( start: DateTime.now().subtract(const Duration(
// minutes: 30, minutes: 30,
// )), )),
// end: DateTime.now().add(Duration( end: DateTime.now().add(const Duration(
// minutes: 15, minutes: 15,
// )), )),
// homeworkId: 'homeworkId', homeworkId: 'homeworkId',
// id: 'id', id: 'id',
// description: 'description', description: 'description',
// room: 'ABC69', room: 'ABC69',
// groupName: 'groupName', groupName: 'groupName',
// name: 'name', name: 'name',
// ); );*/
// liveCard.prevLesson = liveCard.nextLesson; liveCard.nextLesson = liveCard.currentLesson;
// final dt = DateTime(2024, 3, 22, 17, 12, 1, 1, 1); // final dt = DateTime(2024, 3, 22, 17, 12, 1, 1, 1);
@ -408,8 +412,9 @@ class LiveCardStateA extends State<LiveCard> {
swapRoom: true, swapRoom: true,
currentLessonIndicator: false, currentLessonIndicator: false,
padding: padding:
const EdgeInsets.only(top: 8.0, bottom: 4.0), const EdgeInsets.only(top: 6.0, bottom: 4.0),
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
showSubTiles: false,
), ),
if (!(nextSubject == null && if (!(nextSubject == null &&
progressCurrent == null && progressCurrent == null &&
@ -520,7 +525,7 @@ class LiveCardStateA extends State<LiveCard> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.secondary .tertiary
.withOpacity(.15), .withOpacity(.15),
borderRadius: borderRadius:
BorderRadius.circular(10.0), BorderRadius.circular(10.0),

View File

@ -135,12 +135,18 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
title: Text('your_notes'.i18n), title: Text('your_notes'.i18n),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
isTransparent: true, isTransparent: true,
child: Center( child: selfNoteTiles.length > 1
? Center(
child: Wrap( child: Wrap(
spacing: 18.0, spacing: 18.0,
runSpacing: 18.0, runSpacing: 18.0,
children: selfNoteTiles, children: selfNoteTiles,
), ),
)
: Wrap(
spacing: 18.0,
runSpacing: 18.0,
children: selfNoteTiles,
), ),
)); ));
} }

View File

@ -1,10 +1,9 @@
// import 'dart:async'; // import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
import 'package:refilc/api/client.dart'; import 'package:refilc/api/client.dart';
import 'package:refilc/api/login.dart'; import 'package:refilc/api/login.dart';
import 'package:refilc/theme/colors/colors.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/custom_snack_bar.dart';
import 'package:refilc_mobile_ui/common/system_chrome.dart'; import 'package:refilc_mobile_ui/common/system_chrome.dart';
import 'package:refilc_mobile_ui/common/widgets/absence/absence_display.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 'login_screen.i18n.dart';
import 'package:carousel_slider/carousel_slider.dart'; import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_portal/flutter_portal.dart';
class LoginScreen extends StatefulWidget { class LoginScreen extends StatefulWidget {
const LoginScreen({super.key, this.back = false}); const LoginScreen({super.key, this.back = false});
@ -85,9 +83,9 @@ class LoginScreenState extends State<LoginScreen> {
precacheImage(const AssetImage('assets/images/showcase2.png'), context); precacheImage(const AssetImage('assets/images/showcase2.png'), context);
precacheImage(const AssetImage('assets/images/showcase3.png'), context); precacheImage(const AssetImage('assets/images/showcase3.png'), context);
precacheImage(const AssetImage('assets/images/showcase4.png'), context); precacheImage(const AssetImage('assets/images/showcase4.png'), context);
bool selected = false;
return Portal( return Scaffold(
child: Scaffold(
body: Container( body: Container(
decoration: const BoxDecoration(color: Color(0xFFDAE4F7)), decoration: const BoxDecoration(color: Color(0xFFDAE4F7)),
child: SingleChildScrollView( child: SingleChildScrollView(
@ -121,8 +119,7 @@ class LoginScreenState extends State<LoginScreen> {
Material( Material(
type: MaterialType.transparency, type: MaterialType.transparency,
child: showBack child: showBack
? BackButton( ? BackButton(color: AppColors.of(context).text)
color: AppColors.of(context).text)
: const SizedBox(height: 48.0), : const SizedBox(height: 48.0),
), ),
], ],
@ -130,172 +127,208 @@ class LoginScreenState extends State<LoginScreen> {
Stack( Stack(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
children: [ 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( Column(
//login buttons and ui starts here //login buttons and ui starts here
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ 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(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 22.0, right: 20),
right: 22.0, child: Text(
top: 0.0, "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: AutofillGroup(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment:
CrossAxisAlignment
.end,
children: [ children: [
// username // username
Padding( Padding(
padding: padding:
const EdgeInsets.only(bottom: 6.0), const EdgeInsets
.only(
bottom:
6.0),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.spaceBetween, MainAxisAlignment
.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
"username".i18n, "username"
maxLines: 1, .i18n,
style: TextStyle( maxLines:
1,
style:
TextStyle(
color: AppColors.of(context) color: AppColors.of(context)
.loginPrimary, .loginPrimary,
fontWeight: FontWeight.w500, fontWeight:
fontSize: 12.0, FontWeight.w500,
fontSize:
12.0,
), ),
), ),
), ),
Expanded( Expanded(
child: Text( child: Text(
"usernameHint".i18n, "usernameHint"
maxLines: 1, .i18n,
textAlign: TextAlign.right, maxLines:
style: TextStyle( 1,
textAlign:
TextAlign
.right,
style:
TextStyle(
color: AppColors.of(context) color: AppColors.of(context)
.loginSecondary, .loginSecondary,
fontWeight: FontWeight.w500, fontWeight:
fontSize: 12.0, FontWeight.w500,
fontSize:
12.0,
), ),
), ),
), ),
@ -304,43 +337,65 @@ class LoginScreenState extends State<LoginScreen> {
), ),
Padding( Padding(
padding: padding:
const EdgeInsets.only(bottom: 12.0), const EdgeInsets
.only(
bottom:
12.0),
child: LoginInput( child: LoginInput(
style: LoginInputStyle.username, style:
controller: usernameController, LoginInputStyle
.username,
controller:
usernameController,
), ),
), ),
// password // password
Padding( Padding(
padding: padding:
const EdgeInsets.only(bottom: 6.0), const EdgeInsets
.only(
bottom:
6.0),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.spaceBetween, MainAxisAlignment
.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
"password".i18n, "password"
maxLines: 1, .i18n,
style: TextStyle( maxLines:
1,
style:
TextStyle(
color: AppColors.of(context) color: AppColors.of(context)
.loginPrimary, .loginPrimary,
fontWeight: FontWeight.w500, fontWeight:
fontSize: 12.0, FontWeight.w500,
fontSize:
12.0,
), ),
), ),
), ),
Expanded( Expanded(
child: Text( child: Text(
"passwordHint".i18n, "passwordHint"
maxLines: 1, .i18n,
textAlign: TextAlign.right, maxLines:
style: TextStyle( 1,
textAlign:
TextAlign
.right,
style:
TextStyle(
color: AppColors.of(context) color: AppColors.of(context)
.loginSecondary, .loginSecondary,
fontWeight: FontWeight.w500, fontWeight:
fontSize: 12.0, FontWeight.w500,
fontSize:
12.0,
), ),
), ),
), ),
@ -349,65 +404,122 @@ class LoginScreenState extends State<LoginScreen> {
), ),
Padding( Padding(
padding: padding:
const EdgeInsets.only(bottom: 12.0), const EdgeInsets
.only(
bottom:
12.0),
child: LoginInput( child: LoginInput(
style: LoginInputStyle.password, style:
controller: passwordController, LoginInputStyle
.password,
controller:
passwordController,
), ),
), ),
// school // school
Padding( Padding(
padding: padding:
const EdgeInsets.only(bottom: 6.0), const EdgeInsets
.only(
bottom:
6.0),
child: Text( child: Text(
"school".i18n, "school".i18n,
maxLines: 1, maxLines: 1,
style: TextStyle( style:
color: AppColors.of(context) TextStyle(
color: AppColors.of(
context)
.loginPrimary, .loginPrimary,
fontWeight: FontWeight.w500, fontWeight:
fontSize: 12.0, FontWeight
.w500,
fontSize:
12.0,
), ),
), ),
), ),
SchoolInput( SchoolInput(
scroll: _scrollController, scroll:
controller: schoolController, _scrollController,
controller:
schoolController,
), ),
], ],
), ),
), ),
), ),
const Padding(
padding: EdgeInsets.only(
left: 22.0,
right: 22.0,
top: 0.0,
),
),
Padding( Padding(
padding: const EdgeInsets.only( padding:
const EdgeInsets.only(
top: 35.0, top: 35.0,
left: 22.0, left: 22.0,
right: 22.0, right: 22.0,
), ),
child: Visibility( child: Visibility(
visible: _loginState != LoginState.inProgress, visible: _loginState !=
replacement: const Padding( LoginState
padding: EdgeInsets.symmetric(vertical: 6.0), .inProgress,
child: CircularProgressIndicator( replacement:
valueColor: AlwaysStoppedAnimation<Color>( const Padding(
Colors.white), padding: EdgeInsets
.symmetric(
vertical:
6.0),
child:
CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<
Color>(
Colors
.white),
), ),
), ),
child: LoginButton( child: LoginButton(
child: Text("login".i18n, child: Text(
"login".i18n,
maxLines: 1, maxLines: 1,
style: const TextStyle( style:
fontWeight: FontWeight.bold, const TextStyle(
fontWeight:
FontWeight
.bold,
fontSize: 20.0, fontSize: 20.0,
)), )),
onPressed: () => _loginAPI(context: context), onPressed: () =>
_loginAPI(
context:
context),
), ),
), ),
), ),
]),
);
},
);
},
child: Text(
"login".i18n,
style: const TextStyle(
fontFamily: 'Montserrat',
fontSize: 20,
fontWeight: FontWeight.w700),
)),
),
),
const SizedBox(height: 8),
], ],
), ),
// TODO: OLD LOGIN FROM HERE ),
),
], ],
), ),
@ -449,7 +561,6 @@ class LoginScreenState extends State<LoginScreen> {
), ),
), ),
), ),
),
); );
} }

View File

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:refilc/api/providers/database_provider.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/api/providers/user_provider.dart';
import 'package:refilc/helpers/quick_actions.dart'; import 'package:refilc/helpers/quick_actions.dart';
import 'package:refilc/models/settings.dart'; import 'package:refilc/models/settings.dart';
@ -750,6 +751,9 @@ class _BellDelaySettingState extends State<BellDelaySetting>
Provider.of<SettingsProvider>(context, listen: false) Provider.of<SettingsProvider>(context, listen: false)
.update(bellDelay: currentDelay.inSeconds); .update(bellDelay: currentDelay.inSeconds);
_tabController.index = currentDelay.inSeconds > 0 ? 1 : 0; _tabController.index = currentDelay.inSeconds > 0 ? 1 : 0;
if(Platform.isIOS){
LiveCardProvider.hasActivitySettingsChanged = true;
}
setState(() {}); setState(() {});
} }
}, },
@ -760,6 +764,9 @@ class _BellDelaySettingState extends State<BellDelaySetting>
//Provider.of<SettingsProvider>(context, listen: false).update(context, rounding: (r * 10).toInt()); //Provider.of<SettingsProvider>(context, listen: false).update(context, rounding: (r * 10).toInt());
Provider.of<SettingsProvider>(context, listen: false) Provider.of<SettingsProvider>(context, listen: false)
.update(bellDelay: currentDelay.inSeconds); .update(bellDelay: currentDelay.inSeconds);
if(Platform.isIOS){
LiveCardProvider.hasActivitySettingsChanged = true;
}
Navigator.of(context).maybePop(); Navigator.of(context).maybePop();
}, },
), ),
@ -897,6 +904,7 @@ class _LiveActivityColorSettingState extends State<LiveActivityColorSetting> {
currentColor = k as Color; currentColor = k as Color;
settings.update( settings.update(
liveActivityColor: currentColor.withAlpha(255)); liveActivityColor: currentColor.withAlpha(255));
LiveCardProvider.hasActivitySettingsChanged = true;
Navigator.of(context).maybePop(); Navigator.of(context).maybePop();
}); });
}, },
@ -913,6 +921,7 @@ class _LiveActivityColorSettingState extends State<LiveActivityColorSetting> {
var defaultColors = var defaultColors =
SettingsProvider.defaultSettings().liveActivityColor; SettingsProvider.defaultSettings().liveActivityColor;
settings.update(liveActivityColor: defaultColors); settings.update(liveActivityColor: defaultColors);
LiveCardProvider.hasActivitySettingsChanged = true;
Navigator.of(context).maybePop(); Navigator.of(context).maybePop();
}, },
child: Text(SettingsLocalization("reset").i18n), child: Text(SettingsLocalization("reset").i18n),