Compare commits

...

100 Commits

Author SHA1 Message Date
unknown
8ab96a32c3 changelog 2021-10-02 00:14:11 +02:00
unknown
22c8a285ab kreten 2021-10-02 00:07:15 +02:00
unknown
d819245e31 bump 3.0.6 2021-09-30 23:09:45 +02:00
unknown
6b55721ec5 mobile 2021-09-30 22:58:57 +02:00
unknown
13062c4a9b kreten 2021-09-30 22:58:50 +02:00
unknown
2188eaf1c6 high refresh rate patch 2021-09-30 22:37:30 +02:00
unknown
922d252c57 mobile 2021-09-30 21:57:55 +02:00
unknown
7a5290efe5 kreten 2021-09-30 21:57:52 +02:00
unknown
d1e6cc1fbb connectivity testing 2021-09-30 21:57:45 +02:00
unknown
b6a8696911 fix network bug 2021-09-30 21:57:21 +02:00
unknown
f7efd65f5e mobile 2021-09-30 19:51:29 +02:00
unknown
9963f65ab2 mobile 2021-09-30 19:16:53 +02:00
unknown
8d8c3a54c2 use default user-agent for config 2021-09-29 18:18:50 +02:00
unknown
c49d93c7b1 mobile 2021-09-26 20:59:04 +02:00
unknown
b0a7ab20d9 changelog 2021-09-26 01:45:10 +02:00
unknown
59a9e0e236 bump 3.0.5 2021-09-26 01:40:29 +02:00
unknown
e83202ba29 cleanup 2021-09-26 01:39:41 +02:00
unknown
d4489dd9d4 kreten 2021-09-26 01:33:36 +02:00
Unknown
debb4cac5b Merge pull request #26 from filc/analytics
Analytics
2021-09-26 01:32:15 +02:00
unknown
acbdf2aecb Merge branch 'master' into analytics 2021-09-26 01:31:39 +02:00
unknown
5d9ea4311a mobile 2021-09-20 12:53:04 +02:00
unknown
8aa24d7a32 mobile 2021-09-20 12:39:07 +02:00
unknown
9fbcef357e error report 2021-09-20 12:38:06 +02:00
unknown
e9423a8535 mobile 2021-09-19 18:47:20 +02:00
unknown
2a7265256d analytics client 2021-09-19 17:56:38 +02:00
unknown
d5ba231fcc fix database migration 2021-09-18 16:30:17 +02:00
unknown
68d92c4462 changelog 2021-09-18 14:27:44 +02:00
unknown
a46f6130cb ios dist fix 2021-09-18 14:25:20 +02:00
unknown
c6021e7a69 version bump 2021-09-18 12:24:56 +02:00
unknown
3ceb40ddb8 mobile 2021-09-18 12:24:38 +02:00
unknown
593292e860 kreten 2021-09-18 12:24:36 +02:00
unknown
ab952daa10 vibration cleanup 2021-09-18 11:57:01 +02:00
unknown
56b6eb3d2b haptics 2021-09-18 11:17:41 +02:00
unknown
26be20ac28 version bump 2021-09-12 20:25:22 +02:00
unknown
afd004b980 migrate users db 2021-09-12 20:24:39 +02:00
unknown
903cbba69a basics 2021-09-12 19:33:26 +02:00
unknown
6eb6a0cf16 kreten 2021-09-12 18:32:43 +02:00
unknown
abf9f9b13d todo 2021-09-11 19:26:53 +02:00
unknown
0471843919 mobile 2021-09-11 19:13:04 +02:00
unknown
bb83dd2137 version bump 2021-09-11 19:11:04 +02:00
unknown
d9b07525a4 mobile 2021-09-11 19:10:40 +02:00
unknown
92334406c5 kreten 2021-09-11 19:10:35 +02:00
unknown
506af7fa71 mobile 2021-09-11 18:41:52 +02:00
unknown
f5be03e5ce add role 2021-09-11 18:40:11 +02:00
unknown
2047784d8f mobile 2021-09-11 17:58:31 +02:00
unknown
037cf1df48 kreten 2021-09-11 17:58:27 +02:00
unknown
8238cc0678 role 2021-09-11 17:55:27 +02:00
unknown
f52a747268 mobile 2021-09-11 16:01:56 +02:00
unknown
c37bdc7aff kreten 2021-09-11 16:01:52 +02:00
unknown
9015ff2d6b mobile 2021-09-11 15:53:47 +02:00
unknown
a801503838 trim 2021-09-11 15:53:37 +02:00
55nknown
b0565ddcd9 mobile 2021-09-06 09:54:22 +02:00
55nknown
d8b6ba9a64 ios 2021-09-06 09:39:45 +02:00
unknown
549570a48c version bump 2021-09-05 19:54:30 +02:00
unknown
930e8d86b8 mobile 2021-09-05 19:36:14 +02:00
unknown
4aff7df96f kreten 2021-09-05 19:36:10 +02:00
unknown
c839ac178a android build fix 2021-09-05 19:35:08 +02:00
unknown
2c7efc0a18 kreten 2021-09-05 18:49:59 +02:00
unknown
5252813721 mobile 2021-09-05 18:48:23 +02:00
unknown
15d3daefed kreten 2021-09-05 18:48:18 +02:00
unknown
0729c13362 mobile 2021-09-05 16:58:33 +02:00
unknown
4bb978ba63 mobile 2021-09-05 16:55:43 +02:00
unknown
d9c071b5ae update gradle version 2021-09-05 16:53:13 +02:00
unknown
6ffe4b6c33 gitignore 2021-09-04 20:29:46 +02:00
unknown
7bd5d8bd5a version bump 2021-09-04 20:24:03 +02:00
unknown
c0ffa5d726 commit 2021-09-04 20:05:48 +02:00
unknown
befb107183 mobile 2021-09-04 12:11:15 +02:00
unknown
e56488094e mobile 2021-09-02 20:15:02 +02:00
unknown
74831c3e56 beta 5 2021-09-02 20:03:00 +02:00
unknown
9d3347d680 mobile 2021-09-02 20:01:13 +02:00
unknown
25100ab7d9 add test school 2021-09-02 18:08:31 +02:00
unknown
b509adcbc9 kreten 2021-09-02 17:00:03 +02:00
unknown
d421ae9031 capitalize fix 2021-09-02 16:59:57 +02:00
unknown
c3b79fcb3f today, yesterday fix 2021-09-02 01:34:32 +02:00
unknown
3cf57ac6d4 version bump 2021-09-02 01:28:06 +02:00
unknown
d72bf84a36 supporters 2021-09-02 01:27:59 +02:00
unknown
638b8c9413 limit text scaling 2021-09-02 01:27:29 +02:00
unknown
d5bdca698b commit 2021-09-02 00:18:58 +02:00
unknown
ea6b2ec73d commit 2021-09-02 00:18:41 +02:00
unknown
7ffb58c9ac art icon appears for geography 2021-09-01 14:11:30 +02:00
unknown
eaf2e2a6c4 vibration 2021-08-31 22:05:59 +02:00
unknown
8cf642fb72 kreten 2021-08-31 21:14:34 +02:00
unknown
47245b4551 bn 2021-08-31 21:14:11 +02:00
unknown
2b25abaf4d fix font scaling 2021-08-31 21:07:26 +02:00
unknown
adef77b5ed Migrating from Manifest defined custom splash screens 2021-08-31 21:05:34 +02:00
Unknown
8cc3107faf Merge pull request #2 from filc/ios
ios
2021-08-31 19:29:55 +02:00
Unknown
3284c5ba5a Create CONTRIBUTING.md 2021-08-31 18:51:54 +02:00
unknown
942a92f1f4 bn 2021-08-31 18:36:35 +02:00
unknown
ae3272e6da App name 2021-08-31 18:11:18 +02:00
unknown
67768b9de9 readme 2021-08-31 17:51:30 +02:00
unknown
aba24c0c2a commti 2021-08-31 17:40:20 +02:00
unknown
c55a5b9fe7 commit 2021-08-31 16:58:59 +02:00
unknown
fee63a2205 ios icons, launch screen 2021-08-31 16:58:41 +02:00
unknown
9bcf9eb391 bn 2021-08-31 16:58:21 +02:00
DarK-rtfm
fa9a61657b pubspec?? 2021-08-31 15:38:00 +02:00
unknown
33e4595e09 bn 2021-08-31 15:27:58 +02:00
unknown
91582c3b37 fix appstore issues 2021-08-31 15:21:21 +02:00
DarK-rtfm
61de95970e pubspec.ignore 2021-08-31 15:17:21 +02:00
unknown
e36347510f remove modules (deprecated) 2021-08-31 14:39:19 +02:00
unknown
e1429dedae ios version 2021-08-31 14:34:16 +02:00
83 changed files with 846 additions and 877 deletions

39
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,39 @@
# Contributing Guide
Köszönjük, ha programozással segíted a munkánkat!
A folytatáshoz szükséged lesz egy Linuxot vagy Windowst futtató számítógépre, minimális programozási tapasztalatra és egy kis angoltudásra.
Segít, ha nem csak kicsit tudsz programozni, és ha ismered a Gitet és a GitHubot ;)
## Miben segítsek?
Kérünk, **olyan dologgal járulj hozzá** a Filchez, ami valószínűleg **sok embernek hasznos lesz** majd. Szeretnénk egy minél teljeskörűbb iskolai asszisztenst létrehozni, de az iskolaspecifikus, vagy külön neked hasznos funkciók helye inkább legyen a saját forkod.
Fontos, hogy **mielőtt egy nagy volumenű projektbe belekezdesz, futtasd meg ötletedet a [Discord szerverünkön](https://filcnaplo.hu/discord),** ahol még azelőtt tudunk tanácsot adni, mielőtt sok-sok órát beleöltél volna egy esetleg felesleges dologba.
A legjobban annak örülünk, ha az [Issues](https://github.com/filcnaplo/filcnaplo/issues) oldalról szemezgetsz, **ha lehet, a [priority taggel megjelöltekkel kezdd](https://github.com/filcnaplo/filcnaplo/issues?q=is%3Aissue+is%3Aopen+label%3Apriority),** vagy ha új vagy a Flutterhez, ajánljuk figyelmedbe [ezeket a viszonylag könnyen javítható hibákat](https://github.com/filcnaplo/filcnaplo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) (ha épp van ilyen).
## Hogyan segítsek?
Nem ígérhetünk itt sem programozás-, sem git-kurzust, de a projektspecifikus dolgokat leírjuk, és segítünk a Flutter feltelepítésében.
A Filc a Google által pár éve létrehozott **[Fluttert](https://flutter.dev/)** használja, aminek nyelve a **[Dart](https://dart.dev/)**. Ha ismered a C#-ot, Javát, C++t, vagy egyéb hasonló nyelvet, **nem fog gondot okozni a használata.** A felhasználói felület létrehozásában az is segíthet, ha foglalkoztál már korábban weboldalakkal.
Ha még nem használtál Fluttert, mindenképp böngészd át a [YouTube csatornájukat](https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw).
Könnyen tudsz kódot, vagy akár UI-t is tesztelni a [DartPad](https://dartpad.dev/) oldalon.
#### [Segítség a Flutter telepítéséhez és a forráskód futtatásához](/.github/SETUP.md)
Fontos: **Legyél a flutter beta verzióján!** Írd be: `flutter channel beta`
Ha nem értesz a Githez, ajánljuk figyelmedbe [ezt a cikket](https://medium.com/envienta-magyarorsz%C3%A1g/git-%C3%A9s-github-gyorstalpal%C3%B3-f2d78a732deb). Viszont arra kérünk, a Git használatát ne a Filcen próbáld ki először, hozz létre előbb egy saját Repót, és abba tesztelgess. Ha már nagyjából kitapasztaltad, várjuk hozzájárulásodat.
Készíts egy forkot a saját fiókod alá.
A Filc legfrissebb, épp fejlesztés alatt álló verzióját a [dev brancen](https://github.com/filcnaplo/filcnaplo/tree/dev) találod, kérjük ide commitolj, és ide célozd a forkodból a Pull Requested. Írd le benne, mit változtattál, és ha lehet, csatolj képernyőképet is.
Minél gyakrabban készíts minél részletesebben elnevezett commitokat, hogy el tudjunk tájékozódni az általad beküldött kódon.
---
Az általad fejlesztett funkciók mellé a changelogban odakerül GitHub felhasználóneved.
Ha jelentős és rendszeres hozzájáruló vagy, Discordon megkapod a `DEV` rangot.
Ha bárhol elakadtál, keress minket Discordon.
Jó fejlesztést kívánunk!

View File

@@ -5,8 +5,7 @@
#### Nem hivatalos e-napló alkalmazás az eKRÉTA rendszerhez #### Nem hivatalos e-napló alkalmazás az eKRÉTA rendszerhez
[![discord](https://img.shields.io/discord/712698455193157643?label=Discord)](http://filcnaplo.hu/discord)   [![Codemagic build status](https://api.codemagic.io/apps/612cc79b35b443d1b2c638ec/612cc79b35b443d1b2c638eb/status_badge.svg)](https://codemagic.io/apps/612cc79b35b443d1b2c638ec/612cc79b35b443d1b2c638eb/latest_build) [![Downloads](https://img.shields.io/github/downloads-pre/filc/naplo/latest/total?color=%23&label=Downloads&logo=github&sort=semver)](https://github.com/filc/naplo/releases)   [![discord](https://img.shields.io/discord/712698455193157643?label=Discord)](http://filcnaplo.hu/discord)   [![Codemagic build status](https://api.codemagic.io/apps/612cc79b35b443d1b2c638ec/612cc79b35b443d1b2c638eb/status_badge.svg)](https://codemagic.io/apps/612cc79b35b443d1b2c638ec/612cc79b35b443d1b2c638eb/latest_build)
## Setup ## Setup

4
changelog.md Normal file
View File

@@ -0,0 +1,4 @@
- Hibajavítások
- Hibajavítások
- Hibajavítások
- Hibajavítások

View File

@@ -9,3 +9,4 @@ GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore. # Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties key.properties
.project

View File

@@ -52,6 +52,7 @@ android {
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
} }
signingConfigs { signingConfigs {
@@ -77,6 +78,7 @@ flutter {
} }
dependencies { dependencies {
implementation 'com.android.support:multidex:2.0.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

View File

@@ -2,7 +2,6 @@
<application android:label="Filc Napló" android:icon="@mipmap/ic_launcher" android:requestLegacyExternalStorage="true"> <application android:label="Filc Napló" android:icon="@mipmap/ic_launcher" android:requestLegacyExternalStorage="true">
<activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
<meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" />
<meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/launch_background" />
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
@@ -10,7 +9,7 @@
</activity> </activity>
<meta-data android:name="flutterEmbedding" android:value="2" /> <meta-data android:name="flutterEmbedding" android:value="2" />
</application> </application>
<!-- Permissions --> <!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />

View File

@@ -13,7 +13,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.6.3' classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -21,6 +21,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>8.0</string> <string>9.0</string>
</dict> </dict>
</plist> </plist>

View File

@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"

View File

@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"

41
filcnaplo/ios/Podfile Normal file
View File

@@ -0,0 +1,41 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

123
filcnaplo/ios/Podfile.lock Normal file
View File

@@ -0,0 +1,123 @@
PODS:
- DKImagePickerController/Core (4.3.2):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.2)
- DKImagePickerController/PhotoGallery (4.3.2):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.2)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0)
- flutter_custom_tabs (0.0.1):
- Flutter
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- open_file (0.0.1):
- Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider (0.0.1):
- Flutter
- "permission_handler (5.1.0+2)":
- Flutter
- SDWebImage (5.11.1):
- SDWebImage/Core (= 5.11.1)
- SDWebImage/Core (5.11.1)
- share_plus (0.0.1):
- Flutter
- sqflite (0.0.2):
- Flutter
- FMDB (>= 2.7.5)
- SwiftyGif (5.4.0)
- url_launcher (0.0.1):
- Flutter
DEPENDENCIES:
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- flutter_custom_tabs (from `.symlinks/plugins/flutter_custom_tabs/ios`)
- open_file (from `.symlinks/plugins/open_file/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- FMDB
- SDWebImage
- SwiftyGif
EXTERNAL SOURCES:
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
flutter_custom_tabs:
:path: ".symlinks/plugins/flutter_custom_tabs/ios"
open_file:
:path: ".symlinks/plugins/open_file/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
permission_handler:
:path: ".symlinks/plugins/permission_handler/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
url_launcher:
:path: ".symlinks/plugins/url_launcher/ios"
SPEC CHECKSUMS:
DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_custom_tabs: 7a10a08686955cb748e5d26e0ae586d30689bf89
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
open_file: 02eb5cb6b21264bd3a696876f5afbfb7ca4f4b7d
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
SwiftyGif: 5d4af95df24caf1c570dbbcb32a3b8a0763bc6d7
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
COCOAPODS: 1.11.0

View File

@@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
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 */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
@@ -31,10 +32,13 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
1F0ADD56276103500A3016C8 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; 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>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
80777CF254888CE770D5F909 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -42,6 +46,7 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
98578F0EBCC6D3FF8391AAEB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -49,12 +54,32 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
373A6ECB5FC71FE9D8AF2EDB /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
6640A963014A9D4F31026053 /* Frameworks */ = {
isa = PBXGroup;
children = (
1F0ADD56276103500A3016C8 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
91FEB6212755D596FFFFEC73 /* Pods */ = {
isa = PBXGroup;
children = (
80777CF254888CE770D5F909 /* Pods-Runner.debug.xcconfig */,
98578F0EBCC6D3FF8391AAEB /* Pods-Runner.release.xcconfig */,
707F8089D970F81C480F73C4 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = { 9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -72,6 +97,8 @@
9740EEB11CF90186004384FC /* Flutter */, 9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
91FEB6212755D596FFFFEC73 /* Pods */,
6640A963014A9D4F31026053 /* Frameworks */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -105,12 +132,14 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
779338C8D92BCBC36F75F791 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */, 9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */, 97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
71459C0EB905E05018E3D78F /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
@@ -183,6 +212,45 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
}; };
71459C0EB905E05018E3D78F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
779338C8D92BCBC36F75F791 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@@ -468,4 +536,4 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
}; };
rootObject = 97C146E61CF9000F007C117D /* Project object */; rootObject = 97C146E61CF9000F007C117D /* Project object */;
} }

View File

@@ -4,4 +4,7 @@
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace> </Workspace>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -1,122 +1,208 @@
{ {
"images" : [ "images": [
{ {
"size" : "20x20", "size": "60x60",
"idiom" : "iphone", "expected-size": "180",
"filename" : "Icon-App-20x20@2x.png", "filename": "180.png",
"scale" : "2x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "iphone",
"scale": "3x"
}, },
{ {
"size" : "20x20", "size": "40x40",
"idiom" : "iphone", "expected-size": "80",
"filename" : "Icon-App-20x20@3x.png", "filename": "80.png",
"scale" : "3x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "iphone",
"scale": "2x"
}, },
{ {
"size" : "29x29", "size": "40x40",
"idiom" : "iphone", "expected-size": "120",
"filename" : "Icon-App-29x29@1x.png", "filename": "120.png",
"scale" : "1x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "iphone",
"scale": "3x"
}, },
{ {
"size" : "29x29", "size": "60x60",
"idiom" : "iphone", "expected-size": "120",
"filename" : "Icon-App-29x29@2x.png", "filename": "120.png",
"scale" : "2x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "iphone",
"scale": "2x"
}, },
{ {
"size" : "29x29", "size": "57x57",
"idiom" : "iphone", "expected-size": "57",
"filename" : "Icon-App-29x29@3x.png", "filename": "57.png",
"scale" : "3x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "iphone",
"scale": "1x"
}, },
{ {
"size" : "40x40", "size": "29x29",
"idiom" : "iphone", "expected-size": "58",
"filename" : "Icon-App-40x40@2x.png", "filename": "58.png",
"scale" : "2x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "iphone",
"scale": "2x"
}, },
{ {
"size" : "40x40", "size": "29x29",
"idiom" : "iphone", "expected-size": "29",
"filename" : "Icon-App-40x40@3x.png", "filename": "29.png",
"scale" : "3x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "iphone",
"scale": "1x"
}, },
{ {
"size" : "60x60", "size": "29x29",
"idiom" : "iphone", "expected-size": "87",
"filename" : "Icon-App-60x60@2x.png", "filename": "87.png",
"scale" : "2x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "iphone",
"scale": "3x"
}, },
{ {
"size" : "60x60", "size": "57x57",
"idiom" : "iphone", "expected-size": "114",
"filename" : "Icon-App-60x60@3x.png", "filename": "114.png",
"scale" : "3x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "iphone",
"scale": "2x"
}, },
{ {
"size" : "20x20", "size": "20x20",
"idiom" : "ipad", "expected-size": "40",
"filename" : "Icon-App-20x20@1x.png", "filename": "40.png",
"scale" : "1x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "iphone",
"scale": "2x"
}, },
{ {
"size" : "20x20", "size": "20x20",
"idiom" : "ipad", "expected-size": "60",
"filename" : "Icon-App-20x20@2x.png", "filename": "60.png",
"scale" : "2x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "iphone",
"scale": "3x"
}, },
{ {
"size" : "29x29", "size": "1024x1024",
"idiom" : "ipad", "filename": "1024.png",
"filename" : "Icon-App-29x29@1x.png", "expected-size": "1024",
"scale" : "1x" "idiom": "ios-marketing",
"folder": "Assets.xcassets/AppIcon.appiconset/",
"scale": "1x"
}, },
{ {
"size" : "29x29", "size": "40x40",
"idiom" : "ipad", "expected-size": "80",
"filename" : "Icon-App-29x29@2x.png", "filename": "80.png",
"scale" : "2x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "2x"
}, },
{ {
"size" : "40x40", "size": "72x72",
"idiom" : "ipad", "expected-size": "72",
"filename" : "Icon-App-40x40@1x.png", "filename": "72.png",
"scale" : "1x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "1x"
}, },
{ {
"size" : "40x40", "size": "76x76",
"idiom" : "ipad", "expected-size": "152",
"filename" : "Icon-App-40x40@2x.png", "filename": "152.png",
"scale" : "2x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "2x"
}, },
{ {
"size" : "76x76", "size": "50x50",
"idiom" : "ipad", "expected-size": "100",
"filename" : "Icon-App-76x76@1x.png", "filename": "100.png",
"scale" : "1x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "2x"
}, },
{ {
"size" : "76x76", "size": "29x29",
"idiom" : "ipad", "expected-size": "58",
"filename" : "Icon-App-76x76@2x.png", "filename": "58.png",
"scale" : "2x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "2x"
}, },
{ {
"size" : "83.5x83.5", "size": "76x76",
"idiom" : "ipad", "expected-size": "76",
"filename" : "Icon-App-83.5x83.5@2x.png", "filename": "76.png",
"scale" : "2x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "1x"
}, },
{ {
"size" : "1024x1024", "size": "29x29",
"idiom" : "ios-marketing", "expected-size": "29",
"filename" : "Icon-App-1024x1024@1x.png", "filename": "29.png",
"scale" : "1x" "folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "1x"
},
{
"size": "50x50",
"expected-size": "50",
"filename": "50.png",
"folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "1x"
},
{
"size": "72x72",
"expected-size": "144",
"filename": "144.png",
"folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "2x"
},
{
"size": "40x40",
"expected-size": "40",
"filename": "40.png",
"folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "1x"
},
{
"size": "83.5x83.5",
"expected-size": "167",
"filename": "167.png",
"folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "2x"
},
{
"size": "20x20",
"expected-size": "20",
"filename": "20.png",
"folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "1x"
},
{
"size": "20x20",
"expected-size": "40",
"filename": "40.png",
"folder": "Assets.xcassets/AppIcon.appiconset/",
"idiom": "ipad",
"scale": "2x"
} }
], ],
"info" : { "info": {
"version" : 1, "version": 1,
"author" : "xcode" "author": "xcode"
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 852 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 B

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -39,6 +39,6 @@
</scenes> </scenes>
<resources> <resources>
<image name="LaunchImage" width="512" height="512"/> <image name="LaunchImage" width="512" height="512"/>
<image name="LaunchBackground" width="1" height="1"/> <image name="LaunchBackground" width="1080" height="1920"/>
</resources> </resources>
</document> </document>

View File

@@ -1,52 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>filcnaplo</string> <string>Filc Napló</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string> <string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>
<string>Main</string> <string>Main</string>
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UISupportedInterfaceOrientations~ipad</key> <key>UISupportedInterfaceOrientations~ipad</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string> <string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>UIStatusBarHidden</key> <key>UIStatusBarHidden</key>
<false/> <false/>
<key>LSApplicationQueriesSchemes</key> <key>LSApplicationQueriesSchemes</key>
<array> <array>
<string>https</string> <string>https</string>
<string>http</string> <string>http</string>
</array> </array>
</dict> <key>NSPhotoLibraryUsageDescription</key>
<string>The app requires the photo library to set a custom profile picture.</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
</dict>
</plist> </plist>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>production</string>
</dict>
</plist>

View File

@@ -3,22 +3,40 @@ import 'dart:convert';
import 'package:filcnaplo/models/config.dart'; import 'package:filcnaplo/models/config.dart';
import 'package:filcnaplo/models/news.dart'; import 'package:filcnaplo/models/news.dart';
import 'package:filcnaplo/models/release.dart'; import 'package:filcnaplo/models/release.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/models/supporter.dart';
import 'package:filcnaplo_kreta_api/models/school.dart'; import 'package:filcnaplo_kreta_api/models/school.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:connectivity_plus/connectivity_plus.dart';
class FilcAPI { class FilcAPI {
// Public API
static const SCHOOL_LIST = "https://filcnaplo.hu/v2/school_list.json"; static const SCHOOL_LIST = "https://filcnaplo.hu/v2/school_list.json";
static const CONFIG = "https://filcnaplo.hu/v2/config.json";
static const NEWS = "https://filcnaplo.hu/v2/news.json"; static const NEWS = "https://filcnaplo.hu/v2/news.json";
static const SUPPORTERS = "https://filcnaplo.hu/v2/supporters.json";
// Private API
static const CONFIG = "https://api.filcnaplo.hu/config";
static const REPORT = "https://api.filcnaplo.hu/report";
// Updates
static const REPO = "filc/naplo"; static const REPO = "filc/naplo";
static const RELEASES = "https://api.github.com/repos/$REPO/releases"; static const RELEASES = "https://api.github.com/repos/$REPO/releases";
static Future<bool> checkConnectivity() async => (await Connectivity().checkConnectivity()) != ConnectivityResult.none;
static Future<List<School>?> getSchools() async { static Future<List<School>?> getSchools() async {
try { try {
http.Response res = await http.get(Uri.parse(SCHOOL_LIST)); http.Response res = await http.get(Uri.parse(SCHOOL_LIST));
if (res.statusCode == 200) { if (res.statusCode == 200) {
return (jsonDecode(res.body) as List).cast<Map>().map((json) => School.fromJson(json)).toList(); List<School> schools = (jsonDecode(res.body) as List).cast<Map>().map((json) => School.fromJson(json)).toList();
schools.add(School(
city: "Tiszabura",
instituteCode: "supporttest-reni-tiszabura-teszt01",
name: "FILC Éles Reni tiszabura-teszt",
));
return schools;
} else { } else {
throw "HTTP ${res.statusCode}: ${res.body}"; throw "HTTP ${res.statusCode}: ${res.body}";
} }
@@ -27,15 +45,22 @@ class FilcAPI {
} }
} }
static Future<Config?> getConfig() async { static Future<Config?> getConfig(SettingsProvider settings) async {
Map<String, String> headers = {
"x-filc-id": settings.xFilcId,
"user-agent": SettingsProvider.defaultSettings().config.userAgent,
};
try { try {
http.Response res = await http.get(Uri.parse(CONFIG)); http.Response res = await http.get(Uri.parse(CONFIG), headers: headers);
if (res.statusCode == 200) { if (res.statusCode == 200) {
return Config.fromJson(jsonDecode(res.body)); return Config.fromJson(jsonDecode(res.body));
} else { } else if (res.statusCode == 429) {
throw "HTTP ${res.statusCode}: ${res.body}"; res = await http.get(Uri.parse(CONFIG));
if (res.statusCode == 200) return Config.fromJson(jsonDecode(res.body));
} }
throw "HTTP ${res.statusCode}: ${res.body}";
} catch (error) { } catch (error) {
print("ERROR: FilcAPI.getConfig: $error"); print("ERROR: FilcAPI.getConfig: $error");
} }
@@ -55,6 +80,20 @@ class FilcAPI {
} }
} }
static Future<Supporters?> getSupporters() async {
try {
http.Response res = await http.get(Uri.parse(SUPPORTERS));
if (res.statusCode == 200) {
return Supporters.fromJson(jsonDecode(res.body));
} else {
throw "HTTP ${res.statusCode}: ${res.body}";
}
} catch (error) {
print("ERROR: FilcAPI.getSupporters: $error");
}
}
static Future<List<Release>?> getReleases() async { static Future<List<Release>?> getReleases() async {
try { try {
http.Response res = await http.get(Uri.parse(RELEASES)); http.Response res = await http.get(Uri.parse(RELEASES));
@@ -82,4 +121,35 @@ class FilcAPI {
return Future.value(null); return Future.value(null);
} }
static Future<void> sendReport(ErrorReport report) async {
try {
http.Response res = await http.post(Uri.parse(REPORT), body: {
"os": report.os,
"version": report.version,
"error": report.error,
"stack_trace": report.stack,
});
if (res.statusCode != 200) {
throw "HTTP ${res.statusCode}: ${res.body}";
}
} catch (error) {
print("ERROR: FilcAPI.sendReport: $error");
}
}
}
class ErrorReport {
String stack;
String os;
String version;
String error;
ErrorReport({
required this.stack,
required this.os,
required this.version,
required this.error,
});
} }

View File

@@ -1,3 +1,4 @@
import 'package:filcnaplo/utils/jwt.dart';
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart'; import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
import 'package:filcnaplo_kreta_api/providers/event_provider.dart'; import 'package:filcnaplo_kreta_api/providers/event_provider.dart';
import 'package:filcnaplo_kreta_api/providers/exam_provider.dart'; import 'package:filcnaplo_kreta_api/providers/exam_provider.dart';
@@ -10,10 +11,8 @@ import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/models/user.dart'; import 'package:filcnaplo/models/user.dart';
import 'package:filcnaplo/utils/jwt.dart';
import 'package:filcnaplo_kreta_api/client/api.dart'; import 'package:filcnaplo_kreta_api/client/api.dart';
import 'package:filcnaplo_kreta_api/client/client.dart'; import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/models/message.dart';
import 'package:filcnaplo_kreta_api/models/student.dart'; import 'package:filcnaplo_kreta_api/models/student.dart';
import 'package:filcnaplo_kreta_api/models/week.dart'; import 'package:filcnaplo_kreta_api/models/week.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -65,12 +64,14 @@ Future loginApi({
try { try {
Provider.of<KretaClient>(context, listen: false).accessToken = res["access_token"]; Provider.of<KretaClient>(context, listen: false).accessToken = res["access_token"];
Map? studentJson = await Provider.of<KretaClient>(context, listen: false).getAPI(KretaAPI.student(instituteCode)); Map? studentJson = await Provider.of<KretaClient>(context, listen: false).getAPI(KretaAPI.student(instituteCode));
Student student = Student.fromJson(studentJson!);
var user = User( var user = User(
username: username, username: username,
password: password, password: password,
instituteCode: instituteCode, instituteCode: instituteCode,
name: JwtUtils.getNameFromJWT(res["access_token"]) ?? "?", name: student.name,
student: Student.fromJson(studentJson!), student: student,
role: JwtUtils.getRoleFromJWT(res["access_token"])!,
); );
if (onLogin != null) onLogin(user); if (onLogin != null) onLogin(user);
@@ -82,14 +83,16 @@ Future loginApi({
// Get user data // Get user data
try { try {
await Provider.of<GradeProvider>(context, listen: false).fetch(); await Future.wait([
await Provider.of<TimetableProvider>(context, listen: false).fetch(week: Week.current()); Provider.of<GradeProvider>(context, listen: false).fetch(),
await Provider.of<ExamProvider>(context, listen: false).fetch(); Provider.of<TimetableProvider>(context, listen: false).fetch(week: Week.current()),
await Provider.of<HomeworkProvider>(context, listen: false).fetch(); Provider.of<ExamProvider>(context, listen: false).fetch(),
await Provider.of<MessageProvider>(context, listen: false).fetch(type: MessageType.inbox); Provider.of<HomeworkProvider>(context, listen: false).fetch(),
await Provider.of<NoteProvider>(context, listen: false).fetch(); Provider.of<MessageProvider>(context, listen: false).fetchAll(),
await Provider.of<EventProvider>(context, listen: false).fetch(); Provider.of<NoteProvider>(context, listen: false).fetch(),
await Provider.of<AbsenceProvider>(context, listen: false).fetch(); Provider.of<EventProvider>(context, listen: false).fetch(),
Provider.of<AbsenceProvider>(context, listen: false).fetch(),
]);
} catch (error) { } catch (error) {
print("WARNING: failed to fetch user data: $error"); print("WARNING: failed to fetch user data: $error");
} }

View File

@@ -31,8 +31,8 @@ class UpdateProvider extends ChangeNotifier {
// Check for new releases // Check for new releases
if (_releases.length > 0) { if (_releases.length > 0) {
print("INFO: New update: ${releases.first.version}");
_available = _packageInfo != null && _releases.first.version.compareTo(Version.fromString(_packageInfo?.version ?? "")) == 1; _available = _packageInfo != null && _releases.first.version.compareTo(Version.fromString(_packageInfo?.version ?? "")) == 1;
if (_available) print("INFO: New update: ${releases.first.version}");
notifyListeners(); notifyListeners();
} }
} }

View File

@@ -13,6 +13,7 @@ class UserProvider with ChangeNotifier {
String? get name => user?.name; String? get name => user?.name;
String? get username => user?.username; String? get username => user?.username;
String? get password => user?.password; String? get password => user?.password;
Role? get role => user?.role;
Student? get student => user?.student; Student? get student => user?.student;
void setUser(String userId) { void setUser(String userId) {

View File

@@ -1,3 +1,6 @@
import 'dart:io';
import 'dart:math';
import 'package:filcnaplo/api/client.dart'; import 'package:filcnaplo/api/client.dart';
import 'package:filcnaplo/api/providers/news_provider.dart'; import 'package:filcnaplo/api/providers/news_provider.dart';
import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart';
@@ -29,6 +32,7 @@ import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
import 'package:filcnaplo/api/providers/user_provider.dart'; import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/api/providers/update_provider.dart'; import 'package:filcnaplo/api/providers/update_provider.dart';
import 'package:filcnaplo_mobile_ui/pages/grades/calculator/grade_calculator_provider.dart'; import 'package:filcnaplo_mobile_ui/pages/grades/calculator/grade_calculator_provider.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart';
class App extends StatelessWidget { class App extends StatelessWidget {
final SettingsProvider settings; final SettingsProvider settings;
@@ -43,14 +47,17 @@ class App extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
setSystemChrome(context); setSystemChrome(context);
// Set high refresh mode #28
if (Platform.isAndroid) FlutterDisplayMode.setHighRefreshRate();
WidgetsBinding.instance?.addPostFrameCallback((_) { WidgetsBinding.instance?.addPostFrameCallback((_) {
FilcAPI.getConfig().then((Config? config) { FilcAPI.getConfig(settings).then((Config? config) {
settings.update(context, database: database, config: config ?? Config.fromJson({})); if (config != null) settings.update(context, database: database, config: config);
}); });
}); });
return I18n( return I18n(
initialLocale: Locale(settings.language, settings.language), initialLocale: Locale(settings.language, settings.language.toUpperCase()),
child: MultiProvider( child: MultiProvider(
providers: [ providers: [
ChangeNotifierProvider<SettingsProvider>(create: (_) => settings), ChangeNotifierProvider<SettingsProvider>(create: (_) => settings),
@@ -74,24 +81,47 @@ class App extends StatelessWidget {
ChangeNotifierProvider<GradeCalculatorProvider>(create: (context) => GradeCalculatorProvider(context)), ChangeNotifierProvider<GradeCalculatorProvider>(create: (context) => GradeCalculatorProvider(context)),
], ],
child: Consumer<ThemeModeObserver>( child: Consumer<ThemeModeObserver>(
builder: (context, themeMode, child) => MaterialApp( builder: (context, themeMode, child) {
title: "Filc Napló", return MaterialApp(
debugShowCheckedModeBanner: false, builder: (context, child) {
theme: AppTheme.lightTheme(context), // Limit font size scaling to 1.0
darkTheme: AppTheme.darkTheme(context), double textScaleFactor = min(MediaQuery.of(context).textScaleFactor, 1.0);
themeMode: themeMode.themeMode,
localizationsDelegates: [ return MediaQuery(
GlobalMaterialLocalizations.delegate, data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor),
GlobalWidgetsLocalizations.delegate, child: child ?? Container(),
GlobalCupertinoLocalizations.delegate, );
], },
supportedLocales: [ title: "Filc Napló",
const Locale('en'), debugShowCheckedModeBanner: false,
const Locale('hu'), theme: AppTheme.lightTheme(context),
const Locale('de'), darkTheme: AppTheme.darkTheme(context),
], themeMode: themeMode.themeMode,
onGenerateRoute: (settings) => rootNavigator(settings), localizationsDelegates: [
initialRoute: user.getUsers().length > 0 ? "navigation" : "login"), GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'EN'),
const Locale('hu', 'HU'),
const Locale('de', 'DE'),
],
localeListResolutionCallback: (locales, supported) {
Locale locale = Locale('hu', 'HU');
for (var loc in locales ?? []) {
if (supported.contains(loc)) {
locale = loc;
break;
}
}
return locale;
},
onGenerateRoute: (settings) => rootNavigator(settings),
initialRoute: user.getUsers().length > 0 ? "navigation" : "login");
},
), ),
), ),
); );

View File

@@ -9,7 +9,7 @@ Future<Database> initDB() async {
var settingsDB = await createSettingsTable(db); var settingsDB = await createSettingsTable(db);
// Create table Users // Create table Users
await db.execute("CREATE TABLE IF NOT EXISTS users (id TEXT NOT NULL, name TEXT, username TEXT, password TEXT, institute_code TEXT, student TEXT)"); var usersDB = await createUsersTable(db);
await db.execute("CREATE TABLE IF NOT EXISTS user_data (" await db.execute("CREATE TABLE IF NOT EXISTS user_data ("
"id TEXT NOT NULL, grades TEXT, timetable TEXT, exams TEXT, homework TEXT, messages TEXT, notes TEXT, events TEXT, absences TEXT)"); "id TEXT NOT NULL, grades TEXT, timetable TEXT, exams TEXT, homework TEXT, messages TEXT, notes TEXT, events TEXT, absences TEXT)");
@@ -18,7 +18,9 @@ Future<Database> initDB() async {
await db.insert("settings", SettingsProvider.defaultSettings().toMap()); await db.insert("settings", SettingsProvider.defaultSettings().toMap());
} }
await migrateDB(db, settingsDB.struct.keys); // Migrate Databases
await migrateDB(db, "settings", settingsDB.struct.keys, SettingsProvider.defaultSettings().toMap(), createSettingsTable);
await migrateDB(db, "users", usersDB.struct.keys, {"role": 0}, createUsersTable);
return db; return db;
} }
@@ -28,8 +30,9 @@ Future<DatabaseStruct> createSettingsTable(Database db) async {
"language": String, "start_page": int, "rounding": int, "theme": int, "accent_color": int, "news": int, "news_state": int, "developer_mode": int, "language": String, "start_page": int, "rounding": int, "theme": int, "accent_color": int, "news": int, "news_state": int, "developer_mode": int,
"update_channel": int, "config": String, // general "update_channel": int, "config": String, // general
"grade_color1": int, "grade_color2": int, "grade_color3": int, "grade_color4": int, "grade_color5": int, // grade colors "grade_color1": int, "grade_color2": int, "grade_color3": int, "grade_color4": int, "grade_color5": int, // grade colors
"vibrate": int, "vibration_strength": int, "ab_weeks": int, "swap_ab_weeks": int, "vibration_strength": int, "ab_weeks": int, "swap_ab_weeks": int,
"notifications": int, "notifications_bitfield": int, "notification_poll_interval": int, // notifications "notifications": int, "notifications_bitfield": int, "notification_poll_interval": int, // notifications
"x_filc_id": String,
}); });
// Create table Settings // Create table Settings
@@ -38,35 +41,67 @@ Future<DatabaseStruct> createSettingsTable(Database db) async {
return settingsDB; return settingsDB;
} }
Future<void> migrateDB(Database db, Iterable<String> keys) async { Future<DatabaseStruct> createUsersTable(Database db) async {
var settings = (await db.query("settings"))[0]; var usersDB = DatabaseStruct(
{"id": String, "name": String, "username": String, "password": String, "institute_code": String, "student": String, "role": int});
bool migrationRequired = keys.any((key) => !settings.containsKey(key) || settings[key] == null); // Create table Users
await db.execute("CREATE TABLE IF NOT EXISTS users ($usersDB)");
if (migrationRequired) { return usersDB;
var defaultSettings = SettingsProvider.defaultSettings(); }
var settingsCopy = Map<String, dynamic>.from(settings);
// Delete settings Future<void> migrateDB(
await db.execute("drop table settings"); Database db,
String table,
Iterable<String> keys,
Map<String, Object?> defaultValues,
Future<DatabaseStruct> Function(Database) create,
) async {
var originalRows = await db.query(table);
// Fill missing columns if (originalRows.length == 0) {
keys.forEach((key) { await db.execute("drop table $table");
if (!keys.contains(key)) { await create(db);
print("debug: dropping $key"); return;
settingsCopy.remove(key); }
}
if (!settings.containsKey(key) || settings[key] == null) { List<Map<String, dynamic>> migrated = [];
print("DEBUG: migrating $key");
settingsCopy[key] = defaultSettings.toMap()[key]; await Future.forEach<Map<String, Object?>>(originalRows, (original) async {
} bool migrationRequired = keys.any((key) => !original.containsKey(key) || original[key] == null);
if (migrationRequired) {
print("INFO: Migrating $table");
var copy = Map<String, dynamic>.from(original);
// Fill missing columns
keys.forEach((key) {
if (!keys.contains(key)) {
print("DEBUG: dropping $key");
copy.remove(key);
}
if (!original.containsKey(key) || original[key] == null) {
print("DEBUG: migrating $key");
copy[key] = defaultValues[key];
}
});
migrated.add(copy);
}
});
if (migrated.length > 0) {
// Delete table
await db.execute("drop table $table");
// Recreate table
await create(db);
await Future.forEach(migrated, (Map<String, dynamic> copy) async {
await db.insert(table, copy);
}); });
// Recreate settings
await createSettingsTable(db);
await db.insert("settings", settingsCopy);
print("INFO: Database migrated"); print("INFO: Database migrated");
} }
} }

View File

@@ -15,7 +15,7 @@ class DatabaseStruct {
break; break;
} }
return "${name} ${typeName.toUpperCase()}"; return "${name} ${typeName.toUpperCase()} ${name == 'id' ? 'NOT NULL' : ''}";
} }
@override @override

View File

@@ -7,16 +7,16 @@ class SubjectIcon {
static IconData? lookup({Subject? subject, String? subjectName}) { static IconData? lookup({Subject? subject, String? subjectName}) {
assert(!(subject == null && subjectName == null)); assert(!(subject == null && subjectName == null));
String name = subject?.name.toLowerCase().specialChars() ?? subjectName ?? ""; String name = subject?.name.toLowerCase().specialChars().trim() ?? subjectName ?? "";
String category = subject?.category.description.toLowerCase().specialChars() ?? ""; String category = subject?.category.description.toLowerCase().specialChars() ?? "";
// todo: check for categories // todo: check for categories
if (RegExp("mate(k|matika)").hasMatch(name) || category == "matematika") return Icons.calculate_outlined; if (RegExp("mate(k|matika)").hasMatch(name) || category == "matematika") return Icons.calculate_outlined;
if (RegExp("magyar nyelv|nyelvtan").hasMatch(name)) return Icons.spellcheck_outlined; if (RegExp("magyar nyelv|nyelvtan").hasMatch(name)) return Icons.spellcheck_outlined;
if (RegExp("irodalom").hasMatch(name)) return Icons.menu_book_outlined; if (RegExp("irodalom").hasMatch(name)) return Icons.menu_book_outlined;
if (RegExp("rajz|muvtori|muveszet|kultura").hasMatch(name)) return Icons.palette_outlined;
if (RegExp("tor(i|tenelem)").hasMatch(name)) return Icons.hourglass_empty_outlined; if (RegExp("tor(i|tenelem)").hasMatch(name)) return Icons.hourglass_empty_outlined;
if (RegExp("foldrajz").hasMatch(name)) return Icons.public_outlined; if (RegExp("foldrajz").hasMatch(name)) return Icons.public_outlined;
if (RegExp("rajz|muvtori|muveszet|kultura").hasMatch(name)) return Icons.palette_outlined;
if (RegExp("fizika").hasMatch(name)) return Icons.emoji_objects_outlined; if (RegExp("fizika").hasMatch(name)) return Icons.emoji_objects_outlined;
if (RegExp("^enek|zene|szolfezs|zongora|korus").hasMatch(name)) return Icons.music_note_outlined; if (RegExp("^enek|zene|szolfezs|zongora|korus").hasMatch(name)) return Icons.music_note_outlined;
if (RegExp("^tes(i|tneveles)|sport").hasMatch(name)) return Icons.sports_soccer_outlined; if (RegExp("^tes(i|tneveles)|sport").hasMatch(name)) return Icons.sports_soccer_outlined;

View File

@@ -10,6 +10,8 @@ import 'package:open_file/open_file.dart';
enum UpdateState { prepare, downloading, installing } enum UpdateState { prepare, downloading, installing }
typedef UpdateCallback = Function(double progress, UpdateState state); typedef UpdateCallback = Function(double progress, UpdateState state);
// TODO: cleanup old apk files
extension UpdateHelper on Release { extension UpdateHelper on Release {
Future<void> install({UpdateCallback? updateCallback}) async { Future<void> install({UpdateCallback? updateCallback}) async {
String downloads = await StorageHelper.downloadsPath(); String downloads = await StorageHelper.downloadsPath();

View File

@@ -2,10 +2,12 @@ import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/database/init.dart'; import 'package:filcnaplo/database/init.dart';
import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/models/settings.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:filcnaplo/app.dart'; import 'package:filcnaplo/app.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:filcnaplo_mobile_ui/screens/error_screen.dart'; import 'package:filcnaplo_mobile_ui/screens/error_screen.dart';
import 'package:filcnaplo_mobile_ui/screens/error_report_screen.dart';
void main() async { void main() async {
// Initalize // Initalize
@@ -39,12 +41,24 @@ class Startup {
} }
} }
bool errorShown = false;
String lastException = '';
Widget errorBuilder(FlutterErrorDetails details) { Widget errorBuilder(FlutterErrorDetails details) {
return Builder(builder: (context) { return Builder(builder: (context) {
if (Navigator.of(context).canPop()) Navigator.pop(context); if (Navigator.of(context).canPop()) Navigator.pop(context);
WidgetsBinding.instance?.addPostFrameCallback((_) { WidgetsBinding.instance?.addPostFrameCallback((_) {
Navigator.of(context, rootNavigator: true).push(MaterialPageRoute(builder: (ctx) => ErrorScreen(details))); if (!errorShown && details.exceptionAsString() != lastException) {
errorShown = true;
lastException = details.exceptionAsString();
Navigator.of(context, rootNavigator: true).push(MaterialPageRoute(builder: (context) {
if (kReleaseMode)
return ErrorReportScreen(details);
else
return ErrorScreen(details);
})).then((_) => errorShown = false);
}
}); });
return Container(); return Container();

View File

@@ -6,10 +6,11 @@ import 'package:filcnaplo/theme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
enum Pages { home, grades, timetable, messages, absences } enum Pages { home, grades, timetable, messages, absences }
enum UpdateChannel { stable, beta, dev } enum UpdateChannel { stable, beta, dev }
enum VibrationStrength { light, medium, strong } enum VibrationStrength { off, light, medium, strong }
class SettingsProvider extends ChangeNotifier { class SettingsProvider extends ChangeNotifier {
PackageInfo? _packageInfo; PackageInfo? _packageInfo;
@@ -42,12 +43,12 @@ class SettingsProvider extends ChangeNotifier {
// minutes: times 15 // minutes: times 15
int _notificationPollInterval; int _notificationPollInterval;
bool _developerMode; bool _developerMode;
bool _vibrate; VibrationStrength _vibrate;
VibrationStrength _vibrationStrength;
bool _ABweeks; bool _ABweeks;
bool _swapABweeks; bool _swapABweeks;
UpdateChannel _updateChannel; UpdateChannel _updateChannel;
Config _config; Config _config;
String _xFilcId;
SettingsProvider({ SettingsProvider({
required String language, required String language,
@@ -62,12 +63,12 @@ class SettingsProvider extends ChangeNotifier {
required int notificationsBitfield, required int notificationsBitfield,
required bool developerMode, required bool developerMode,
required int notificationPollInterval, required int notificationPollInterval,
required bool vibrate, required VibrationStrength vibrate,
required VibrationStrength vibrationStrength,
required bool ABweeks, required bool ABweeks,
required bool swapABweeks, required bool swapABweeks,
required UpdateChannel updateChannel, required UpdateChannel updateChannel,
required Config config, required Config config,
required String xFilcId,
}) : _language = language, }) : _language = language,
_startPage = startPage, _startPage = startPage,
_rounding = rounding, _rounding = rounding,
@@ -81,11 +82,11 @@ class SettingsProvider extends ChangeNotifier {
_developerMode = developerMode, _developerMode = developerMode,
_notificationPollInterval = notificationPollInterval, _notificationPollInterval = notificationPollInterval,
_vibrate = vibrate, _vibrate = vibrate,
_vibrationStrength = vibrationStrength,
_ABweeks = ABweeks, _ABweeks = ABweeks,
_swapABweeks = swapABweeks, _swapABweeks = swapABweeks,
_updateChannel = updateChannel, _updateChannel = updateChannel,
_config = config { _config = config,
_xFilcId = xFilcId {
PackageInfo.fromPlatform().then((PackageInfo packageInfo) { PackageInfo.fromPlatform().then((PackageInfo packageInfo) {
_packageInfo = packageInfo; _packageInfo = packageInfo;
}); });
@@ -111,12 +112,12 @@ class SettingsProvider extends ChangeNotifier {
notificationsBitfield: map["notifications_bitfield"], notificationsBitfield: map["notifications_bitfield"],
notificationPollInterval: map["notification_poll_interval"], notificationPollInterval: map["notification_poll_interval"],
developerMode: map["developer_mode"] == 1 ? true : false, developerMode: map["developer_mode"] == 1 ? true : false,
vibrate: map["vibrate"] == 1 ? true : false, vibrate: VibrationStrength.values[map["vibration_strength"]],
vibrationStrength: VibrationStrength.values[map["vibration_strength"]],
ABweeks: map["ab_weeks"] == 1 ? true : false, ABweeks: map["ab_weeks"] == 1 ? true : false,
swapABweeks: map["swap_ab_weeks"] == 1 ? true : false, swapABweeks: map["swap_ab_weeks"] == 1 ? true : false,
updateChannel: UpdateChannel.values[map["update_channel"]], updateChannel: UpdateChannel.values[map["update_channel"]],
config: Config.fromJson(jsonDecode(map["config"] ?? "{}")), config: Config.fromJson(jsonDecode(map["config"] ?? "{}")),
xFilcId: map["x_filc_id"],
); );
} }
@@ -138,12 +139,12 @@ class SettingsProvider extends ChangeNotifier {
"grade_color4": _gradeColors[3].value, "grade_color4": _gradeColors[3].value,
"grade_color5": _gradeColors[4].value, "grade_color5": _gradeColors[4].value,
"update_channel": _updateChannel.index, "update_channel": _updateChannel.index,
"vibrate": _vibrate ? 1 : 0, "vibration_strength": _vibrate.index,
"vibration_strength": _vibrationStrength.index,
"ab_weeks": _ABweeks ? 1 : 0, "ab_weeks": _ABweeks ? 1 : 0,
"swap_ab_weeks": _swapABweeks ? 1 : 0, "swap_ab_weeks": _swapABweeks ? 1 : 0,
"notification_poll_interval": _notificationPollInterval, "notification_poll_interval": _notificationPollInterval,
"config": jsonEncode(config.json), "config": jsonEncode(config.json),
"x_filc_id": _xFilcId,
}; };
} }
@@ -167,12 +168,12 @@ class SettingsProvider extends ChangeNotifier {
notificationsBitfield: 255, notificationsBitfield: 255,
developerMode: false, developerMode: false,
notificationPollInterval: 1, notificationPollInterval: 1,
vibrate: true, vibrate: VibrationStrength.medium,
vibrationStrength: VibrationStrength.medium,
ABweeks: false, ABweeks: false,
swapABweeks: false, swapABweeks: false,
updateChannel: UpdateChannel.stable, updateChannel: UpdateChannel.stable,
config: Config.fromJson({}), config: Config.fromJson({}),
xFilcId: Uuid().v4(),
); );
} }
@@ -189,13 +190,13 @@ class SettingsProvider extends ChangeNotifier {
int get notificationsBitfield => _notificationsBitfield; int get notificationsBitfield => _notificationsBitfield;
bool get developerMode => _developerMode; bool get developerMode => _developerMode;
int get notificationPollInterval => _notificationPollInterval; int get notificationPollInterval => _notificationPollInterval;
bool get vibrate => _vibrate; VibrationStrength get vibrate => _vibrate;
VibrationStrength get vibrationStrength => _vibrationStrength;
bool get ABweeks => _ABweeks; bool get ABweeks => _ABweeks;
bool get swapABweeks => _swapABweeks; bool get swapABweeks => _swapABweeks;
UpdateChannel get updateChannel => _updateChannel; UpdateChannel get updateChannel => _updateChannel;
PackageInfo? get packageInfo => _packageInfo; PackageInfo? get packageInfo => _packageInfo;
Config get config => _config; Config get config => _config;
String get xFilcId => _xFilcId;
Future<void> update( Future<void> update(
BuildContext context, { BuildContext context, {
@@ -212,12 +213,12 @@ class SettingsProvider extends ChangeNotifier {
int? notificationsBitfield, int? notificationsBitfield,
bool? developerMode, bool? developerMode,
int? notificationPollInterval, int? notificationPollInterval,
bool? vibrate, VibrationStrength? vibrate,
VibrationStrength? vibrationStrength,
bool? ABweeks, bool? ABweeks,
bool? swapABweeks, bool? swapABweeks,
UpdateChannel? updateChannel, UpdateChannel? updateChannel,
Config? config, Config? config,
String? xFilcId,
}) async { }) async {
if (language != null && language != _language) _language = language; if (language != null && language != _language) _language = language;
if (startPage != null && startPage != _startPage) _startPage = startPage; if (startPage != null && startPage != _startPage) _startPage = startPage;
@@ -233,11 +234,11 @@ class SettingsProvider extends ChangeNotifier {
if (notificationPollInterval != null && notificationPollInterval != _notificationPollInterval) if (notificationPollInterval != null && notificationPollInterval != _notificationPollInterval)
_notificationPollInterval = notificationPollInterval; _notificationPollInterval = notificationPollInterval;
if (vibrate != null && vibrate != _vibrate) _vibrate = vibrate; if (vibrate != null && vibrate != _vibrate) _vibrate = vibrate;
if (vibrationStrength != null && vibrationStrength != _vibrationStrength) _vibrationStrength = vibrationStrength;
if (ABweeks != null && ABweeks != _ABweeks) _ABweeks = ABweeks; if (ABweeks != null && ABweeks != _ABweeks) _ABweeks = ABweeks;
if (swapABweeks != null && swapABweeks != _swapABweeks) _swapABweeks = swapABweeks; if (swapABweeks != null && swapABweeks != _swapABweeks) _swapABweeks = swapABweeks;
if (updateChannel != null && updateChannel != _updateChannel) _updateChannel = updateChannel; if (updateChannel != null && updateChannel != _updateChannel) _updateChannel = updateChannel;
if (config != null && config != _config) _config = config; if (config != null && config != _config) _config = config;
if (xFilcId != null && xFilcId != _xFilcId) _xFilcId = xFilcId;
if (database == null) database = Provider.of<DatabaseProvider>(context, listen: false); if (database == null) database = Provider.of<DatabaseProvider>(context, listen: false);
await database.store.storeSettings(this); await database.store.storeSettings(this);

View File

@@ -0,0 +1,38 @@
class Supporter {
String name;
String amount;
String platform;
Supporter(this.name, this.amount, this.platform);
factory Supporter.fromJson(Map json) {
return Supporter(
(json["name"] ?? "").trim(),
json["amount"] ?? "",
json["platform"] ?? "",
);
}
}
class Supporters {
List<Supporter> top;
List<Supporter> all;
int progress;
int max;
Supporters({
required this.top,
required this.all,
required this.progress,
required this.max,
});
factory Supporters.fromJson(Map json) {
return Supporters(
max: (json["progress"] ?? {})["max"] ?? 1,
progress: (json["progress"] ?? {})["value"] ?? 0,
all: ((json["all"] ?? []) as List).cast<Map>().map((e) => Supporter.fromJson(e)).toList(),
top: ((json["top"] ?? []) as List).cast<Map>().map((e) => Supporter.fromJson(e)).toList(),
);
}
}

View File

@@ -3,6 +3,8 @@ import 'package:filcnaplo_kreta_api/client/api.dart';
import 'package:filcnaplo_kreta_api/models/student.dart'; import 'package:filcnaplo_kreta_api/models/student.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
enum Role { student, parent }
class User { class User {
late String id; late String id;
String username; String username;
@@ -10,6 +12,7 @@ class User {
String instituteCode; String instituteCode;
String name; String name;
Student student; Student student;
Role role;
User({ User({
String? id, String? id,
@@ -18,6 +21,7 @@ class User {
required this.password, required this.password,
required this.instituteCode, required this.instituteCode,
required this.student, required this.student,
required this.role,
}) { }) {
if (id != null) { if (id != null) {
this.id = id; this.id = id;
@@ -32,8 +36,9 @@ class User {
instituteCode: map["institute_code"], instituteCode: map["institute_code"],
username: map["username"], username: map["username"],
password: map["password"], password: map["password"],
name: map["name"], name: map["name"].trim(),
student: Student.fromJson(jsonDecode(map["student"])), student: Student.fromJson(jsonDecode(map["student"])),
role: Role.values[map["role"] ?? 0],
); );
} }
@@ -45,9 +50,13 @@ class User {
"institute_code": instituteCode, "institute_code": instituteCode,
"name": name, "name": name,
"student": jsonEncode(student.json), "student": jsonEncode(student.json),
"role": role.index,
}; };
} }
@override
String toString() => jsonEncode(toMap());
static Map<String, Object?> loginBody({ static Map<String, Object?> loginBody({
required String username, required String username,
required String password, required String password,

View File

@@ -1,376 +0,0 @@
// import 'dart:io';
// import 'dart:typed_data';
// import 'package:feather_icons_flutter/feather_icons_flutter.dart';
// import 'package:filcnaplo/data/context/app.dart';
// import 'package:filcnaplo/ui/common/bottom_card.dart';
// import 'package:filcnaplo/utils/colors.dart';
// import 'package:flutter/cupertino.dart';
// import 'package:flutter/material.dart';
// import 'package:filcnaplo/generated/i18n.dart';
// import 'package:flutter_markdown/flutter_markdown.dart';
// import 'package:http/http.dart' as http;
// import 'package:path_provider/path_provider.dart';
// import 'package:open_file/open_file.dart';
// import 'package:filcnaplo/data/context/theme.dart';
// import '../../ui/common/custom_snackbar.dart';
// enum InstallState { update, downloading, saving, installing }
// class AutoUpdater extends StatefulWidget {
// @override
// _AutoUpdaterState createState() => _AutoUpdaterState();
// }
// class _AutoUpdaterState extends State<AutoUpdater> {
// bool buttonPressed = false;
// double progress;
// bool displayProgress = false;
// InstallState installState;
// void downloadCallback(
// double progress, bool displayProgress, InstallState installState) {
// if (mounted) {
// setState(() {
// this.progress = progress;
// this.displayProgress = displayProgress;
// this.installState = installState;
// });
// }
// }
// @override
// Widget build(BuildContext context) {
// if (!buttonPressed) installState = InstallState.update;
// String buttonText;
// switch (installState) {
// case InstallState.update:
// buttonText = I18n.of(context).update;
// break;
// case InstallState.downloading:
// buttonText = I18n.of(context).updateDownloading;
// break;
// case InstallState.saving:
// buttonText = I18n.of(context).updateSaving;
// break;
// case InstallState.installing:
// buttonText = I18n.of(context).updateInstalling;
// break;
// default:
// buttonText = I18n.of(context).error;
// }
// return BottomCard(
// child: Padding(
// padding: EdgeInsets.only(top: 13),
// child: Column(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Row(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Expanded(
// child: ListTile(
// contentPadding: EdgeInsets.only(left: 8.0),
// title: Text(
// I18n.of(context).updateNewVersion,
// style: TextStyle(
// fontSize: 23,
// fontWeight: FontWeight.bold,
// ),
// ),
// subtitle: Text(
// app.user.sync.release.latestRelease.version,
// style: TextStyle(
// fontWeight: FontWeight.bold,
// fontSize: 18,
// ),
// ),
// ),
// ),
// ClipRRect(
// borderRadius: BorderRadius.circular(12.0),
// child: Image.asset(
// "assets/logo.png",
// width: 60,
// ),
// ),
// ],
// ),
// Padding(
// padding: EdgeInsets.all(8),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(
// I18n.of(context).updateChanges + ":",
// style: TextStyle(fontSize: 18),
// ),
// Text(
// I18n.of(context).updateCurrentVersion +
// ": " +
// app.currentAppVersion,
// style:
// TextStyle(color: Colors.white.withAlpha(180)),
// ),
// ],
// ),
// ),
// Expanded(
// child: Padding(
// padding: EdgeInsets.all(8.0),
// child: Builder(builder: (context) {
// try {
// return Markdown(
// shrinkWrap: true,
// data: app.user.sync.release.latestRelease.notes,
// padding: EdgeInsets.all(0),
// physics: BouncingScrollPhysics(),
// styleSheet: MarkdownStyleSheet(
// p: TextStyle(
// fontSize: 15,
// color: app.settings.theme.textTheme
// .bodyText1.color,
// ),
// ),
// );
// } catch (e) {
// print(
// "ERROR: autoUpdater.dart failed to show markdown release notes: " +
// e.toString());
// return Text(
// app.user.sync.release.latestRelease.notes);
// }
// })),
// )
// ],
// ),
// ),
// Stack(
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment: MainAxisAlignment.end,
// crossAxisAlignment: CrossAxisAlignment.center,
// children: [
// IconButton(
// icon: Icon(FeatherIcons.helpCircle),
// onPressed: () {
// showDialog(
// context: context,
// builder: (context) => HelpDialog());
// })
// ],
// ),
// Center(
// child: MaterialButton(
// color: ThemeContext.filcGreen,
// elevation: 0,
// highlightElevation: 0,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(45.0)),
// child: Padding(
// padding: EdgeInsets.symmetric(vertical: 9),
// child: Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// if (displayProgress)
// Container(
// margin: EdgeInsets.only(right: 10),
// height: 19,
// width: 19,
// child: CircularProgressIndicator(
// value: progress,
// valueColor: AlwaysStoppedAnimation<Color>(
// Colors.white),
// strokeWidth: 3.2,
// ),
// ),
// Text(
// buttonText.toUpperCase(),
// style: TextStyle(
// fontSize: 17,
// fontWeight: FontWeight.bold,
// color: Colors.white),
// )
// ],
// ),
// ),
// onPressed: () {
// if (!buttonPressed)
// installUpdate(context, downloadCallback);
// buttonPressed = true;
// },
// ),
// ),
// ],
// ),
// ]),
// ),
// );
// }
// Future installUpdate(BuildContext context, Function updateDisplay) async {
// updateDisplay(null, true, InstallState.downloading);
// String dir = (await getApplicationDocumentsDirectory()).path;
// String latestVersion = app.user.sync.release.latestRelease.version;
// String filename = "filcnaplo-$latestVersion.apk";
// File apk = File("$dir/$filename");
// var httpClient = http.Client();
// var request = new http.Request(
// 'GET', Uri.parse(app.user.sync.release.latestRelease.url));
// var response = httpClient.send(request);
// List<List<int>> chunks = [];
// int downloaded = 0;
// response.asStream().listen((http.StreamedResponse r) {
// r.stream.listen((List<int> chunk) {
// // Display percentage of completion
// updateDisplay(
// downloaded / r.contentLength, true, InstallState.downloading);
// chunks.add(chunk);
// downloaded += chunk.length;
// }, onDone: () async {
// // Display percentage of completion
// updateDisplay(null, true, InstallState.saving);
// // Save the file
// final Uint8List bytes = Uint8List(r.contentLength);
// int offset = 0;
// for (List<int> chunk in chunks) {
// bytes.setRange(offset, offset + chunk.length, chunk);
// offset += chunk.length;
// }
// await apk.writeAsBytes(bytes);
// updateDisplay(null, true, InstallState.installing);
// if (mounted) {
// OpenFile.open(apk.path).then((result) {
// if (result.type != ResultType.done) {
// print("ERROR: installUpdate.openFile: " + result.message);
// ScaffoldMessenger.of(context).showSnackBar(CustomSnackBar(
// message: I18n.of(context).error,
// color: Colors.red,
// ));
// }
// Navigator.pop(context);
// });
// }
// });
// });
// }
// }
// class HelpDialog extends StatelessWidget {
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// backgroundColor: Colors.transparent,
// body: Container(
// decoration: BoxDecoration(
// color: app.settings.theme.backgroundColor,
// borderRadius: BorderRadius.circular(4.0),
// ),
// padding: EdgeInsets.symmetric(vertical: 15, horizontal: 10),
// margin: EdgeInsets.all(32.0),
// child: Column(children: [
// Padding(
// padding: EdgeInsets.all(8.0),
// child: Center(
// child: Icon(FeatherIcons.helpCircle),
// ),
// ),
// Expanded(
// child: Markdown(
// shrinkWrap: true,
// data: helpText,
// padding: EdgeInsets.all(0),
// physics: BouncingScrollPhysics(),
// styleSheet: MarkdownStyleSheet(
// p: TextStyle(
// fontSize: 15,
// color: Colors.white,
// ),
// ),
// ),
// ),
// MaterialButton(
// child: Text(I18n.of(context).dialogDone),
// onPressed: () {
// Navigator.of(context).pop();
// })
// ])));
// }
// }
// const String helpText =
// """A **FRISSÍTÉS** gombot megnyomva az app automatikusan letölti a GitHubról a legfrissebb Filc telepítőt.\\
// Ez kb. 50 MB adatforgalommal jár.\\
// A letöltött telepítőt ezután megnyitja az app.
// Telefonmárkától és Android verziótól függően nagyon különböző a telepítés folyamata, de ezekre figyelj:
// - Ha kérdezi a telefon, **engedélyezd a Filctől származó appok telepítését**, majd nyomd meg a vissza gombot.\\
// _(Újabb Android verziók)_
// - Ha szól a telefon hogy a külső appok telepítése biztonsági okokból tiltott, a megjelenő gombbal **ugorj a beállításokba és kapcsold be az Ismeretlen források lehetőséget.**\\
// _(Régi Android verziók)_
// A telepítés után újra megnyílik az app, immár a legfrissebb verzióval. Az indítás során törli a telepítéshez használt .apk fájlokat, így a tárhelyed miatt nem kell aggódnod.
// """;
// class AutoUpdateButton extends StatelessWidget {
// @override
// Widget build(BuildContext context) {
// return Padding(
// padding: EdgeInsets.only(bottom: 5.0),
// child: Container(
// margin: EdgeInsets.symmetric(horizontal: 14.0),
// child: MaterialButton(
// color: textColor(Theme.of(context).backgroundColor).withAlpha(25),
// elevation: 0,
// highlightElevation: 0,
// shape:
// RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
// child: ListTile(
// contentPadding: EdgeInsets.zero,
// leading: Icon(FeatherIcons.download, color: app.settings.appColor),
// title: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Flexible(
// child: Text(
// I18n.of(context).updateAvailable,
// softWrap: false,
// overflow: TextOverflow.fade,
// )),
// Text(
// app.user.sync.release.latestRelease.version,
// style: TextStyle(
// color: app.settings.appColor,
// fontWeight: FontWeight.bold),
// )
// ],
// ),
// ),
// onPressed: () {
// showModalBottomSheet(
// context: context,
// backgroundColor: Colors.transparent,
// builder: (BuildContext context) => AutoUpdater(),
// );
// },
// ),
// ),
// );
// }
// }

View File

@@ -1,106 +0,0 @@
// import 'dart:io';
// import 'package:filcnaplo/data/context/app.dart';
// class ReleaseSync {
// Release latestRelease;
// bool isNew = false;
// Future sync() async {
// if (!Platform.isAndroid) return;
// var releasesJson = await app.user.kreta.getReleases();
// if (!app.settings.preUpdates) {
// for (Map r in releasesJson) {
// if (!r["prerelease"]) {
// latestRelease = Release.fromJson(r);
// break;
// }
// }
// } else {
// // List<Map> releases = [];
// latestRelease = Release.fromJson(releasesJson.first);
// }
// isNew = compareVersions(latestRelease.version, app.currentAppVersion);
// }
// bool compareVersions(String gitHub, String existing) {
// try {
// bool stableGitHub = false;
// List<String> gitHubPartsStrings = gitHub.split(RegExp(r"[.-]"));
// List<int> gitHubParts = [];
// for (String s in gitHubPartsStrings) {
// if (s.startsWith("beta")) {
// s = s.replaceAll("beta", "");
// } else if (s.startsWith("pre")) {
// //! pre versions have lower priority than beta
// s = s.replaceAll("pre", "");
// gitHubParts.add(0);
// } else {
// stableGitHub = true;
// }
// try {
// gitHubParts.add(int.parse(s));
// } catch (e) {
// print("ERROR: ReleaseSync.compareVersions: " + e.toString());
// }
// }
// if (stableGitHub) gitHubParts.add(1000);
// bool stableExisting = false;
// List<String> existingPartsStrings = existing.split(RegExp(r"[.-]"));
// List<int> existingParts = [];
// for (String s in existingPartsStrings) {
// if (s.startsWith("beta")) {
// s = s.replaceAll("beta", "");
// } else if (s.startsWith("pre")) {
// //! pre versions have lower priority than beta
// s = s.replaceAll("pre", "");
// existingParts.add(0);
// } else {
// stableExisting = true;
// }
// try {
// existingParts.add(int.parse(s));
// } catch (e) {
// print("ERROR: ReleaseSync.compareVersions: " + e.toString());
// }
// }
// // what even
// if (stableExisting) existingParts.add(1000);
// int i = 0;
// for (var gitHubPart in gitHubParts) {
// if (gitHubPart > existingParts[i])
// return true;
// else if (existingParts[i] > gitHubPart) return false;
// i++;
// }
// return false;
// } catch (e) {
// print("ERROR: ReleaseSync.compareVersions: " + e.toString());
// return false;
// }
// }
// }
// class Release {
// String version;
// String notes;
// String url;
// bool isExperimental;
// Release(this.version, this.notes, this.url, this.isExperimental);
// factory Release.fromJson(Map json) {
// List<Map> assets = [];
// json["assets"].forEach((json) {
// assets.add(json);
// });
// String url = assets[0]["browser_download_url"];
// return Release(json["tag_name"], json["body"], url, json["prerelease"]);
// }
// }

View File

@@ -1,148 +0,0 @@
// import 'package:filcnaplo/data/context/app.dart';
// import 'package:filcnaplo/data/models/lesson.dart';
// import 'package:filcnaplo/generated/i18n.dart';
// import 'package:filcnaplo/ui/common/custom_snackbar.dart';
// import 'package:filcnaplo/ui/pages/planner/timetable/day.dart';
// import 'package:filcnaplo/utils/format.dart';
// import 'package:filcnaplo/modules/printing/printerDebugScreen.dart';
// import 'package:flutter/material.dart';
// import 'package:flutter/services.dart' show rootBundle;
// import 'package:pdf/pdf.dart';
// import 'package:pdf/widgets.dart' as pw;
// import 'package:printing/printing.dart';
// import 'package:filcnaplo/ui/pages/planner/timetable/builder.dart';
// import 'package:flutter/foundation.dart';
// /*
// Author: daaniiieel
// Name: Timetable Printer (Experimental)
// Description: This module prints out the timetable for the selected user on the
// current week.
// */
// class TimetablePrinter {
// pw.Document build(
// BuildContext context, pw.Document pdf, List<Day> days, int min, int max) {
// List rows = <pw.TableRow>[];
// // build header row
// List<pw.Widget> headerChildren = <pw.Widget>[pw.Container()];
// days.forEach((day) => headerChildren.add(pw.Padding(
// padding: pw.EdgeInsets.all(5),
// child:
// pw.Center(child: pw.Text(weekdayStringShort(context, day.date.weekday))))));
// pw.TableRow headerRow = pw.TableRow(
// children: headerChildren,
// verticalAlignment: pw.TableCellVerticalAlignment.middle);
// rows.add(headerRow);
// // for each row
// for (int i = min; i < max; i++) {
// var children = <pw.Widget>[];
// var row = pw.TableRow(children: children);
// children.add(pw.Padding(
// padding: pw.EdgeInsets.all(5),
// child: pw.Center(child: pw.Text('$i. '))));
// days.forEach((Day day) {
// var lesson = day.lessons.firstWhere(
// (element) => element.lessonIndex != '+'
// ? int.parse(element.lessonIndex) == i
// : false,
// orElse: () => null);
// children.add(lesson != null
// ? pw.Padding(
// padding: pw.EdgeInsets.fromLTRB(5, 10, 5, 5),
// child: pw.Column(children: [
// pw.Text(lesson.name ?? lesson.subject.name),
// pw.Footer(
// leading: pw.Text(lesson.room),
// trailing: pw.Text(monogram(lesson.teacher))),
// ]))
// : pw.Padding(padding: pw.EdgeInsets.all(5)));
// });
// rows.add(row);
// }
// // add timetable to pdf
// pw.Table table = pw.Table(
// children: rows,
// border: pw.TableBorder.all(),
// defaultVerticalAlignment: pw.TableCellVerticalAlignment.middle,
// );
// // header and footer
// pw.Footer footer = pw.Footer(
// trailing: pw.Text('filcnaplo.hu'),
// margin: pw.EdgeInsets.only(top: 12.0),
// );
// String className = app.user.sync.student.student.className;
// pw.Footer header = pw.Footer(
// margin: pw.EdgeInsets.all(5),
// title: pw.Text(className, style: pw.TextStyle(fontSize: 30)),
// );
// pdf.addPage(pw.Page(
// pageFormat: PdfPageFormat.a4
// .landscape, // so the page looks normal both in portrait and landscape
// orientation: pw.PageOrientation.landscape,
// build: (pw.Context context) =>
// pw.Column(children: <pw.Widget>[header, table, footer])));
// return pdf;
// }
// void printPDF(final _scaffoldKey, BuildContext context) {
// // pdf theme (for unicode support)
// rootBundle.load("assets/Roboto-Regular.ttf").then((font) {
// pw.ThemeData myTheme = pw.ThemeData.withFont(base: pw.Font.ttf(font));
// pw.Document pdf = pw.Document(theme: myTheme);
// // sync indicator
// ScaffoldMessenger.of(context).showSnackBar(CustomSnackBar(
// message: I18n.of(context).syncTimetable,
// ));
// // get a builder and build current week
// final timetableBuilder = TimetableBuilder();
// timetableBuilder.build(timetableBuilder.getCurrentWeek());
// int minLessonIndex = 1;
// int maxLessonIndex = 1;
// List<Day> weekDays = timetableBuilder.week.days;
// for (Day day in weekDays) {
// for (Lesson lesson in day.lessons) {
// if (lesson.lessonIndex == '+') {
// continue;
// }
// if (int.parse(lesson.lessonIndex) < minLessonIndex) {
// minLessonIndex = int.parse(lesson.lessonIndex);
// }
// if (int.parse(lesson.lessonIndex) > maxLessonIndex) {
// maxLessonIndex = int.parse(lesson.lessonIndex);
// }
// }
// }
// pdf = build(context, pdf, weekDays, minLessonIndex, maxLessonIndex);
// // print pdf
// if (kReleaseMode) {
// Printing.layoutPdf(onLayout: (format) => pdf.save()).then((success) {
// if (success)
// ScaffoldMessenger.of(context).showSnackBar(CustomSnackBar(
// message: I18n.of(context).settingsExportExportTimetableSuccess,
// ));
// });
// } else {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (c) =>
// PrintingDebugScreen((format) => Future.value(pdf.save()))));
// }
// });
// }
// }

View File

@@ -1,17 +0,0 @@
// import 'dart:typed_data';
// import 'package:flutter/material.dart';
// import 'package:printing/printing.dart';
// import 'package:pdf/pdf.dart';
// class PrintingDebugScreen extends StatelessWidget {
// final Future<Uint8List> Function(PdfPageFormat) builder;
// PrintingDebugScreen(
// this.builder,
// );
// @override
// Widget build(BuildContext context) {
// return Scaffold(body: Center(child: PdfPreview(build: this.builder)));
// }
// }

View File

@@ -18,7 +18,7 @@ extension StringFormatUtils on String {
String capital() => this.length > 0 ? this[0].toUpperCase() + this.substring(1) : ""; String capital() => this.length > 0 ? this[0].toUpperCase() + this.substring(1) : "";
String capitalize() => this.split(" ").map((w) => this.capital()).join(" "); String capitalize() => this.split(" ").map((w) => w.capital()).join(" ");
String escapeHtml() { String escapeHtml() {
String htmlString = this; String htmlString = this;
@@ -37,11 +37,11 @@ extension DateFormatUtils on DateTime {
if (timeOnly) return DateFormat("HH:mm").format(this); if (timeOnly) return DateFormat("HH:mm").format(this);
DateTime now = DateTime.now(); DateTime now = DateTime.now();
if (this.difference(now).inDays == 0) { if (now.year == this.year && now.month == this.month && now.day == this.day) {
if (this.hour == 0 && this.minute == 0 && this.second == 0) return "Today".i18n; if (this.hour == 0 && this.minute == 0 && this.second == 0) return "Today".i18n;
return DateFormat("HH:mm").format(this); return DateFormat("HH:mm").format(this);
} }
if (this.difference(now).inDays == 1) return "Yesterday".i18n; if (now.year == this.year && now.month == this.month && now.subtract(Duration(days: 1)).day == this.day) return "Yesterday".i18n;
String formatString; String formatString;
if (this.year == now.year) if (this.year == now.year)

View File

@@ -1,7 +1,9 @@
import 'dart:convert'; import 'dart:convert';
import 'package:filcnaplo/models/user.dart';
class JwtUtils { class JwtUtils {
static String? getNameFromJWT(String jwt) { static Map? decodeJwt(String jwt) {
var parts = jwt.split("."); var parts = jwt.split(".");
if (parts.length != 3) return null; if (parts.length != 3) return null;
@@ -11,8 +13,27 @@ class JwtUtils {
parts[1] += "="; parts[1] += "=";
} }
var payload = utf8.decode(base64Url.decode(parts[1])); try {
var jwtData = jsonDecode(payload); var payload = utf8.decode(base64Url.decode(parts[1]));
return jwtData["name"]; return jsonDecode(payload);
} catch (error) {
print("ERROR: JwtUtils.decodeJwt: $error");
}
}
static String? getNameFromJWT(String jwt) {
var jwtData = decodeJwt(jwt);
return jwtData?["name"];
}
static Role? getRoleFromJWT(String jwt) {
var jwtData = decodeJwt(jwt);
switch (jwtData?["role"]) {
case "Tanulo":
return Role.student;
case "Gondviselo":
return Role.parent;
}
} }
} }

View File

@@ -3,7 +3,7 @@ description: "Nem hivatalos e-napló alkalmazás az e-Kréta rendszerhez"
homepage: https://filcnaplo.hu homepage: https://filcnaplo.hu
publish_to: "none" publish_to: "none"
version: 3.0.0-beta.2+121 version: 3.0.6+136
environment: environment:
sdk: ">=2.12.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
@@ -35,6 +35,8 @@ dependencies:
permission_handler: ^8.1.4+2 permission_handler: ^8.1.4+2
share_plus: ^2.1.4 share_plus: ^2.1.4
package_info_plus: ^1.0.6 package_info_plus: ^1.0.6
connectivity_plus: ^1.1.0
flutter_displaymode: ^0.3.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@@ -101,6 +103,17 @@ flutter:
weight: 100 weight: 100
style: italic style: italic
- family: SpaceMono
fonts:
- asset: assets/fonts/SpaceMono/SpaceMono-Regular.ttf
- asset: assets/fonts/SpaceMono/SpaceMono-Bold.ttf
weight: 700
- asset: assets/fonts/SpaceMono/SpaceMono-Italic.ttf
style: italic
- asset: assets/fonts/SpaceMono/SpaceMono-BoldItalic.ttf
weight: 700
style: italic
flutter_icons: flutter_icons:
image_path: "assets/icons/ic_launcher.png" image_path: "assets/icons/ic_launcher.png"
adaptive_icon_background: "#1F5B50" adaptive_icon_background: "#1F5B50"