Merge branch 'master' of github.com:refilc/naplo

This commit is contained in:
Zypherift 2024-06-14 14:09:28 +02:00
commit 0586da3742
72 changed files with 2854 additions and 609 deletions

56
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,56 @@
pipeline {
agent any
environment {
ANDROID_SDK = '/home/jenkins/flutter_things/android-sdk'
ANDROID_PATH="$ANDROID_SDK/tools:$ANDROID_SDK/platform-tools"
FLUTTER = '/home/jenkins/flutter_things/flutter/bin'
PATH = "$PATH:$ANDROID_PATH:$FLUTTER"
//TODO: need to fix flutter
}
stages {
stage('Copy Key Properties') {
steps {
// Copy the key.properties file
sh 'cp /home/jenkins/key.properties refilc/android/key.properties'
}
}
stage('Flutter Doctor') {
steps {
// Ensure Flutter is set up correctly
sh 'flutter doctor'
}
}
stage('Dependencies') {
steps {
// Get Flutter dependencies
sh 'cd refilc && flutter pub get'
}
}
stage('Build') {
steps {
// Build the Flutter project
sh 'cd refilc && flutter build apk --release'
}
}
stage('Archive') {
steps {
// Archive the APK
archiveArtifacts artifacts: 'build/app/outputs/flutter-apk/app-release.apk', fingerprint: true
}
}
}
post {
always {
// Clean up workspace after build
cleanWs()
}
}
}

View File

@ -20,7 +20,7 @@
android:gravity="center" android:gravity="center"
android:text="1." android:text="1."
android:textColor="@color/filc" android:textColor="@color/filc"
android:textColorLink="#ff3D7BF4" android:textColorLink="#ff052460"
android:textSize="30sp" android:textSize="30sp"
android:textStyle="bold" android:textStyle="bold"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
@ -110,4 +110,4 @@
android:textColor="@color/white" android:textColor="@color/white"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
</RelativeLayout> </RelativeLayout>

View File

@ -27,7 +27,7 @@
<color name="yellow_light">#ffFFCC00</color> <color name="yellow_light">#ffFFCC00</color>
<color name="light_yellow_light">#40FFD60A</color> <color name="light_yellow_light">#40FFD60A</color>
<color name="green_light">#ff34C759</color> <color name="green_light">#ff34C759</color>
<color name="filc_light">#ff3D7BF4</color> <color name="filc_light">#ff052460</color>
<color name="teal_light">#ff5AC8FA</color> <color name="teal_light">#ff5AC8FA</color>
<color name="blue_light">#ff007AFF</color> <color name="blue_light">#ff007AFF</color>
<color name="indigo_light">#ff5856D6</color> <color name="indigo_light">#ff5856D6</color>
@ -49,8 +49,8 @@
<color name="yellow">#ffFFD60A</color> <color name="yellow">#ffFFD60A</color>
<color name="light_yellow">#40FFD60A</color> <color name="light_yellow">#40FFD60A</color>
<color name="green">#ff32D74B</color> <color name="green">#ff32D74B</color>
<color name="filc">#ff3D7BF4</color> <color name="filc">#ff052460</color>
<color name="filc_gradient">#ff3D93F5</color> <color name="filc_gradient">#ff06348f</color>
<color name="teal">#ff64D2FF</color> <color name="teal">#ff64D2FF</color>
<color name="blue">#ff0A84FF</color> <color name="blue">#ff0A84FF</color>
<color name="indigo">#ff5E5CE6</color> <color name="indigo">#ff5E5CE6</color>
@ -66,4 +66,4 @@
<color name="pink_shade300">#FFF06292</color> <color name="pink_shade300">#FFF06292</color>
<color name="purple_shade300">#FFBA68C8</color> <color name="purple_shade300">#FFBA68C8</color>
<color name="teal_shade300">#FF22AC9B</color> <color name="teal_shade300">#FF22AC9B</color>
</resources> </resources>

View File

@ -0,0 +1,43 @@
<svg width="375" height="174" viewBox="0 0 375 174" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1575_5258)">
<g style="mix-blend-mode:color-burn">
<rect x="187.881" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="238.186" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="187.881" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="238.186" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="288.49" y="36.8047" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="337.652" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="288.49" y="-13.5" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="337.652" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="187.881" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="238.186" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="187.881" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
<rect x="238.186" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
<rect x="288.49" y="136.271" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="337.652" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="288.49" y="87.1099" width="49.3049" height="49.3049" stroke="#858585"/>
<rect x="337.652" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
<rect x="-12.1953" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="-12.1953" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="38.1094" y="36.8047" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="87.2705" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="38.1094" y="-13.5" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="87.2705" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="-12.1953" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="-12.1953" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
<rect x="38.1094" y="136.271" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="87.2705" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="38.1094" y="87.1099" width="49.3049" height="49.3049" stroke="#858585"/>
<rect x="87.2705" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
<rect x="137.576" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="137.576" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="137.576" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="137.576" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
</g>
</g>
<defs>
<clipPath id="clip0_1575_5258">
<rect width="375" height="173.78" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,27 @@
<svg width="375" height="175" viewBox="0 0 375 175" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1575_5259)">
<g style="mix-blend-mode:color-burn">
<mask id="path-1-inside-1_1575_5259" fill="white">
<path d="M0 37H375V89H0V37Z"/>
</mask>
<path d="M0 38H375V36H0V38Z" fill="#858585" mask="url(#path-1-inside-1_1575_5259)"/>
<mask id="path-3-inside-2_1575_5259" fill="white">
<path d="M0 -13H375V38H0V-13Z"/>
</mask>
<path d="M0 -12H375V-14H0V-12Z" fill="#858585" mask="url(#path-3-inside-2_1575_5259)"/>
<mask id="path-5-inside-3_1575_5259" fill="white">
<path d="M0 137H375V188H0V137Z"/>
</mask>
<path d="M0 138H375V136H0V138Z" fill="#858585" mask="url(#path-5-inside-3_1575_5259)"/>
<mask id="path-7-inside-4_1575_5259" fill="white">
<path d="M0 87H375V138H0V87Z"/>
</mask>
<path d="M0 88H375V86H0V88Z" fill="#858585" mask="url(#path-7-inside-4_1575_5259)"/>
</g>
</g>
<defs>
<clipPath id="clip0_1575_5259">
<rect width="375" height="173.78" fill="white" transform="translate(0 0.780518)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,47 @@
<svg width="375" height="175" viewBox="0 0 375 175" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1575_5260)">
<g style="mix-blend-mode:color-burn">
<circle cx="17" cy="19.561" r="1" fill="#858585"/>
<circle cx="59" cy="19.561" r="1" fill="#858585"/>
<circle cx="101" cy="19.561" r="1" fill="#858585"/>
<circle cx="143" cy="19.561" r="1" fill="#858585"/>
<circle cx="185" cy="19.561" r="1" fill="#858585"/>
<circle cx="227" cy="19.561" r="1" fill="#858585"/>
<circle cx="269" cy="19.561" r="1" fill="#858585"/>
<circle cx="311" cy="19.561" r="1" fill="#858585"/>
<circle cx="353" cy="19.561" r="1" fill="#858585"/>
<circle cx="17" cy="61.561" r="1" fill="#858585"/>
<circle cx="59" cy="61.561" r="1" fill="#858585"/>
<circle cx="101" cy="61.561" r="1" fill="#858585"/>
<circle cx="143" cy="61.561" r="1" fill="#858585"/>
<circle cx="185" cy="61.561" r="1" fill="#858585"/>
<circle cx="227" cy="61.561" r="1" fill="#858585"/>
<circle cx="269" cy="61.561" r="1" fill="#858585"/>
<circle cx="311" cy="61.561" r="1" fill="#858585"/>
<circle cx="353" cy="61.561" r="1" fill="#858585"/>
<circle cx="17" cy="103.561" r="1" fill="#858585"/>
<circle cx="59" cy="103.561" r="1" fill="#858585"/>
<circle cx="101" cy="103.561" r="1" fill="#858585"/>
<circle cx="143" cy="103.561" r="1" fill="#858585"/>
<circle cx="185" cy="103.561" r="1" fill="#858585"/>
<circle cx="227" cy="103.561" r="1" fill="#858585"/>
<circle cx="269" cy="103.561" r="1" fill="#858585"/>
<circle cx="311" cy="103.561" r="1" fill="#858585"/>
<circle cx="353" cy="103.561" r="1" fill="#858585"/>
<circle cx="17" cy="145.561" r="1" fill="#858585"/>
<circle cx="59" cy="145.561" r="1" fill="#858585"/>
<circle cx="101" cy="145.561" r="1" fill="#858585"/>
<circle cx="143" cy="145.561" r="1" fill="#858585"/>
<circle cx="185" cy="145.561" r="1" fill="#858585"/>
<circle cx="227" cy="145.561" r="1" fill="#858585"/>
<circle cx="269" cy="145.561" r="1" fill="#858585"/>
<circle cx="311" cy="145.561" r="1" fill="#858585"/>
<circle cx="353" cy="145.561" r="1" fill="#858585"/>
</g>
</g>
<defs>
<clipPath id="clip0_1575_5260">
<rect width="375" height="173.78" fill="white" transform="translate(0 0.561035)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,28 @@
<svg width="375" height="175" viewBox="0 0 375 175" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1575_5261)">
<g style="mix-blend-mode:color-burn">
<path d="M0 63.0001H375" stroke="#858585"/>
<path d="M0 75.0001H375" stroke="#858585"/>
<path d="M0 87.0001H375" stroke="#858585"/>
<path d="M0 99.0001H375" stroke="#858585"/>
<path d="M0 111H375" stroke="#858585"/>
</g>
<g style="mix-blend-mode:color-burn">
<path d="M0 135H375" stroke="#858585"/>
<path d="M0 147H375" stroke="#858585"/>
<path d="M0 159H375" stroke="#858585"/>
<path d="M0 171H375" stroke="#858585"/>
</g>
<g style="mix-blend-mode:color-burn">
<path d="M0 3.00012H375" stroke="#858585"/>
<path d="M0 15.0001H375" stroke="#858585"/>
<path d="M0 27.0001H375" stroke="#858585"/>
<path d="M0 39.0001H375" stroke="#858585"/>
</g>
</g>
<defs>
<clipPath id="clip0_1575_5261">
<rect width="375" height="173.78" fill="white" transform="translate(0 0.341431)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 973 B

View File

@ -1,43 +0,0 @@
<svg width="375" height="174" viewBox="0 0 375 174" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_581_2504)">
<g style="mix-blend-mode:color-burn">
<rect x="138.881" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="189.186" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="138.881" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="189.186" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="239.49" y="36.8047" width="49.3049" height="50.4482" stroke="black"/>
<rect x="288.652" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="239.49" y="-13.5" width="49.3049" height="50.4482" stroke="black"/>
<rect x="288.652" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="138.881" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="189.186" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="138.881" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
<rect x="189.186" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
<rect x="239.49" y="136.271" width="49.3049" height="50.4482" stroke="black"/>
<rect x="288.652" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="239.49" y="87.1099" width="49.3049" height="49.3049" stroke="black"/>
<rect x="288.652" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
<rect x="338.957" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="338.957" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="338.957" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="338.957" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
<rect x="-10.8906" y="36.8047" width="49.3049" height="50.4482" stroke="black"/>
<rect x="38.2705" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="-10.8906" y="-13.5" width="49.3049" height="50.4482" stroke="black"/>
<rect x="38.2705" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="-10.8906" y="136.271" width="49.3049" height="50.4482" stroke="black"/>
<rect x="38.2705" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="-10.8906" y="87.1099" width="49.3049" height="49.3049" stroke="black"/>
<rect x="38.2705" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
<rect x="88.5762" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="88.5762" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="88.5762" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="88.5762" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
</g>
</g>
<defs>
<clipPath id="clip0_581_2504">
<rect width="375" height="173.78" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -52,14 +52,31 @@ struct LockScreenLiveActivityView: View {
VStack(alignment: .center) { VStack(alignment: .center) {
// Jelenlegi óra // Jelenlegi óra
VStack { VStack {
Text(context.state.index + " " + context.state.title) if(context.state.title.contains("Az első órádig")) {
.font(.body) Text(context.state.title)
.bold() .font(.system(size: 15))
.multilineTextAlignment(.center) .bold()
.multilineTextAlignment(.center)
} else if(context.state.title == "Szünet") {
Text(context.state.title)
.font(.body)
.bold()
.padding(.trailing, 90)
Text("Terem: \(context.state.subtitle)") } else {
.italic() MultilineTextView(text: "\(context.state.index) \(context.state.title)", limit: 25)
.font(.caption) .font(.body)
.bold()
.multilineTextAlignment(.center)
}
//Terem
if (!context.state.subtitle.isEmpty) {
Text(context.state.subtitle)
.italic()
.bold()
.font(.system(size: 13))
}
} }
// Leírás // Leírás
@ -69,6 +86,7 @@ struct LockScreenLiveActivityView: View {
} }
// Következő óra // Következő óra
if(context.state.nextSubject != "" && context.state.nextRoom != "") {
HStack { HStack {
Image(systemName: "arrow.right") Image(systemName: "arrow.right")
.resizable() .resizable()
@ -80,18 +98,24 @@ struct LockScreenLiveActivityView: View {
.font(.caption2) .font(.caption2)
} }
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} else {
Spacer(minLength: 5)
Text("Ez az utolsó óra! Kitartást!")
.font(.system(size: 15))
}
} }
.padding(15) .padding(15)
Spacer() Spacer()
// Visszaszámláló // Visszaszámláló
Text(timerInterval: context.state.date, countsDown: true) Text(timerInterval: context.state.date, countsDown: true)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.frame(width: 85) .frame(width: 85)
.font(.title2) .font(.title2)
.monospacedDigit() .monospacedDigit()
.padding(.trailing, CGFloat(24)) .padding(.trailing)
} }
.activityBackgroundTint( .activityBackgroundTint(
context.state.color != "#676767" context.state.color != "#676767"
@ -109,7 +133,7 @@ struct LiveCardWidget: Widget {
LockScreenLiveActivityView(context: context) LockScreenLiveActivityView(context: context)
/// Dynamic Island /// Dynamic Island
} dynamicIsland: { context in } dynamicIsland: { context in
/// Expanded /// Expanded
return DynamicIsland { return DynamicIsland {
DynamicIslandExpandedRegion(.leading) { DynamicIslandExpandedRegion(.leading) {
@ -133,39 +157,95 @@ struct LiveCardWidget: Widget {
).progressViewStyle(.circular) ).progressViewStyle(.circular)
} }
} }
DynamicIslandExpandedRegion(.center) { DynamicIslandExpandedRegion(.center) {
VStack(alignment: .center) { VStack(alignment: .center) {
Text(context.state.index + context.state.title) // Első óra előtti expanded DynamicIsland
.lineLimit(1) if(context.state.title.contains("Az első órádig")) {
.font(.body) Text("Az első órád:")
.bold() .font(.body)
.bold()
Text(context.state.subtitle) .padding(.trailing, -15)
.lineLimit(1) MultilineTextView(text: "\(context.state.nextSubject)", limit: 25)
.font(.subheadline) .font(.body)
Spacer() .padding(.trailing, -25)
Text(context.state.description) Text("Ebben a teremben:")
.lineLimit(2) .font(.body)
.font(.caption) .bold()
}.padding(EdgeInsets(top: 0.0, leading: 5.0, bottom: 0.0, trailing: 0.0)) .padding(.leading, 15)
} Text(context.state.nextRoom)
.font(.body)
.padding(.leading, 15)
} else if(context.state.title == "Szünet") {
// Amikor szünet van, expanded DynamicIsland
Text(context.state.title)
.lineLimit(1)
.font(.body)
.bold()
.padding(.leading, 15)
Spacer(minLength: 5)
Text("Következő óra és terem:")
.font(.system(size: 13))
.padding(.leading, 25)
Text(context.state.nextSubject)
.font(.caption)
.padding(.leading, 15)
Text(context.state.nextRoom)
.font(.caption2)
.padding(.leading, 15)
} else {
// Amikor óra van, expanded DynamicIsland
MultilineTextView(text: "\(context.state.index) \(context.state.title)", limit: 25)
.lineLimit(1)
.font(.body)
.bold()
.padding(.trailing, -35)
Text(context.state.subtitle)
.lineLimit(1)
.italic()
.bold()
.font(.system(size: 13))
.padding(.trailing, -50)
Spacer(minLength: 5)
if(context.state.nextRoom != "" && context.state.nextSubject != "") {
Text("Következő óra és terem:")
.font(.system(size: 14))
.padding(.trailing, -35)
Spacer(minLength: 2)
Text(context.state.nextSubject)
.modifier(DynamicFontSizeModifier(text: context.state.nextSubject))
.padding(.trailing, -35)
Text(context.state.nextRoom)
// ignore: based on nextSubject characters, I check that the font size of the room is the same as the next subject.
.modifier(DynamicFontSizeModifier(text: context.state.nextSubject))
.padding(.trailing, -35)
} else {
Text("Ez az utolsó óra! Kitartást!")
.font(.system(size: 14))
.padding(.trailing, -30)
}
}
}.padding(EdgeInsets(top: 0.0, leading: 5.0, bottom: 0.0, trailing: 0.0))
}
/// Compact /// Compact
} compactLeading: { } compactLeading: {
Label { Image(systemName: context.state.icon)
Text(context.state.title)
} icon: {
Image(systemName: context.state.icon)
}
.font(.caption2)
} }
compactTrailing: { compactTrailing: {
Text(timerInterval: context.state.date, countsDown: true) Text(timerInterval: context.state.date, countsDown: true)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.frame(width: 40) .frame(width: 40)
.font(.caption2) .font(.caption2)
/// Collapsed /// Collapsed
} minimal: { } minimal: {
VStack(alignment: .center, content: { VStack(alignment: .center, content: {
@ -191,7 +271,59 @@ struct LiveCardWidget: Widget {
context.state.color != "#676767" context.state.color != "#676767"
? Color(hex: context.state.color) ? Color(hex: context.state.color)
: Color.clear : Color.clear
) )
}
}
}
struct MultilineTextView: View {
var text: String
var limit: Int = 20 // default is 20 character
var body: some View {
let words = text.split(separator: " ")
var currentLine = ""
var lines: [String] = []
for word in words {
if (currentLine.count + word.count + 1) > limit {
lines.append(currentLine)
currentLine = ""
}
if !currentLine.isEmpty {
currentLine += " "
}
currentLine += word
}
if !currentLine.isEmpty {
lines.append(currentLine)
}
return VStack(alignment: .center) {
ForEach(lines, id: \.self) { line in
Text(line)
}
Spacer(minLength: 1)
}
}
}
struct DynamicFontSizeModifier: ViewModifier {
var text: String
func body(content: Content) -> some View {
content
.font(.system(size: fontSize(for: text)))
}
private func fontSize(for text: String) -> CGFloat {
let length = text.count
if length < 10 {
return 12
} else if length < 20 {
return 12
} else {
return 11
} }
} }
} }

View File

@ -336,6 +336,8 @@ class FilcAPI {
if (res.statusCode == 200) { if (res.statusCode == 200) {
return (jsonDecode(res.body) as Map); return (jsonDecode(res.body) as Map);
} else if (res.statusCode == 404) {
return {"public_id": ""};
} else { } else {
throw "HTTP ${res.statusCode}: ${res.body}"; throw "HTTP ${res.statusCode}: ${res.body}";
} }

View File

@ -88,24 +88,24 @@ class LiveCardProvider extends ChangeNotifier {
case LiveCardState.morning: case LiveCardState.morning:
return { return {
"color": "color":
'#${_settings.liveActivityColor.toString().substring(10, 16)}', '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": nextLesson != null "icon": nextLesson != null
? SubjectIcon.resolveName(subject: nextLesson?.subject) ? SubjectIcon.resolveName(subject: nextLesson?.subject)
: "book", : "book",
"title": "Első órádig:", "title": "Jó reggelt! Az első órádig:",
"subtitle": "", "subtitle": "",
"description": "", "description": "",
"startDate": storeFirstRunDate != null "startDate": storeFirstRunDate != null
? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) -
(_delay.inMilliseconds)) (_delay.inMilliseconds))
.toString() .toString()
: "", : "",
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": nextLesson != null "nextSubject": nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: nextLesson?.subject).capital() ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "", : "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
@ -113,24 +113,24 @@ class LiveCardProvider extends ChangeNotifier {
case LiveCardState.afternoon: case LiveCardState.afternoon:
return { return {
"color": "color":
'#${_settings.liveActivityColor.toString().substring(10, 16)}', '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": nextLesson != null "icon": nextLesson != null
? SubjectIcon.resolveName(subject: nextLesson?.subject) ? SubjectIcon.resolveName(subject: nextLesson?.subject)
: "book", : "book",
"title": "Első órádig:", "title": "Jó napot! Az első órádig:",
"subtitle": "", "subtitle": "",
"description": "", "description": "",
"startDate": storeFirstRunDate != null "startDate": storeFirstRunDate != null
? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) -
(_delay.inMilliseconds)) (_delay.inMilliseconds))
.toString() .toString()
: "", : "",
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": nextLesson != null "nextSubject": nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: nextLesson?.subject).capital() ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "", : "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
@ -138,24 +138,24 @@ class LiveCardProvider extends ChangeNotifier {
case LiveCardState.night: case LiveCardState.night:
return { return {
"color": "color":
'#${_settings.liveActivityColor.toString().substring(10, 16)}', '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": nextLesson != null "icon": nextLesson != null
? SubjectIcon.resolveName(subject: nextLesson?.subject) ? SubjectIcon.resolveName(subject: nextLesson?.subject)
: "book", : "book",
"title": "Első órádig:", "title": "Jó estét! Az első órádig:",
"subtitle": "", "subtitle": "",
"description": "", "description": "",
"startDate": storeFirstRunDate != null "startDate": storeFirstRunDate != null
? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) -
(_delay.inMilliseconds)) (_delay.inMilliseconds))
.toString() .toString()
: "", : "",
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": nextLesson != null "nextSubject": nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: nextLesson?.subject).capital() ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "", : "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
@ -163,28 +163,28 @@ class LiveCardProvider extends ChangeNotifier {
case LiveCardState.duringLesson: case LiveCardState.duringLesson:
return { return {
"color": "color":
'#${_settings.liveActivityColor.toString().substring(10, 16)}', '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": currentLesson != null "icon": currentLesson != null
? SubjectIcon.resolveName(subject: currentLesson?.subject) ? SubjectIcon.resolveName(subject: currentLesson?.subject)
: "book", : "book",
"index": "index":
currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "", currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
"title": currentLesson != null "title": currentLesson != null
? currentLesson?.subject.renamedTo ?? ? currentLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: currentLesson?.subject) ShortSubject.resolve(subject: currentLesson?.subject)
.capital() .capital()
: "", : "",
"subtitle": currentLesson?.room.replaceAll("_", " ") ?? "", "subtitle": "Terem: ${currentLesson?.room.replaceAll("_", " ") ?? ""}",
"description": currentLesson?.description ?? "", "description": currentLesson?.description ?? "",
"startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) - "startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) - "endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": nextLesson != null "nextSubject": nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: nextLesson?.subject).capital() ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "", : "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
@ -200,23 +200,23 @@ class LiveCardProvider extends ChangeNotifier {
return { return {
"color": "color":
'#${_settings.liveActivityColor.toString().substring(10, 16)}', '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": iconFloorMap[diff] ?? "cup.and.saucer", "icon": iconFloorMap[diff] ?? "cup.and.saucer",
"title": "Szünet", "title": "Szünet",
"description": "go $diff".i18n.fill([ "description": "go $diff".i18n.fill([
diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room
]), ]),
"startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) - "startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": (nextLesson != null "nextSubject": (nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: nextLesson?.subject) ShortSubject.resolve(subject: nextLesson?.subject)
.capital() .capital()
: "") : "")
.capital(), .capital(),
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
"index": "", "index": "",
@ -243,8 +243,8 @@ class LiveCardProvider extends ChangeNotifier {
DateTime now = _now().add(_delay); DateTime now = _now().add(_delay);
if ((currentState == LiveCardState.morning || if ((currentState == LiveCardState.morning ||
currentState == LiveCardState.afternoon || currentState == LiveCardState.afternoon ||
currentState == LiveCardState.night) && currentState == LiveCardState.night) &&
storeFirstRunDate == null) { storeFirstRunDate == null) {
storeFirstRunDate = now; storeFirstRunDate = now;
} }
@ -253,9 +253,9 @@ class LiveCardProvider extends ChangeNotifier {
// Filter label lessons #128 // Filter label lessons #128
today = today today = today
.where((lesson) => .where((lesson) =>
lesson.status?.name != "Elmaradt" && lesson.status?.name != "Elmaradt" &&
lesson.subject.id != '' && lesson.subject.id != '' &&
!lesson.isEmpty) !lesson.isEmpty)
.toList(); .toList();
if (today.isNotEmpty) { if (today.isNotEmpty) {
@ -263,7 +263,7 @@ class LiveCardProvider extends ChangeNotifier {
today.sort((a, b) => a.start.compareTo(b.start)); today.sort((a, b) => a.start.compareTo(b.start));
final _lesson = today.firstWhere( final _lesson = today.firstWhere(
(l) => l.start.isBefore(now) && l.end.isAfter(now), (l) => l.start.isBefore(now) && l.end.isAfter(now),
orElse: () => Lesson.fromJson({})); orElse: () => Lesson.fromJson({}));
if (_lesson.start.year != 0) { if (_lesson.start.year != 0) {
@ -328,7 +328,7 @@ class LiveCardProvider extends ChangeNotifier {
hasActivityStarted = true; hasActivityStarted = true;
} else if (!hasActivityStarted && } else if (!hasActivityStarted &&
((currentState == LiveCardState.duringLesson && ((currentState == LiveCardState.duringLesson &&
currentLesson != null) || currentLesson != null) ||
currentState == LiveCardState.duringBreak)) { currentState == LiveCardState.duringBreak)) {
debugPrint("Óra van, vagy szünet, de nincs LiveActivity. létrehozás..."); debugPrint("Óra van, vagy szünet, de nincs LiveActivity. létrehozás...");
PlatformChannel.createLiveActivity(toMap()); PlatformChannel.createLiveActivity(toMap());
@ -362,7 +362,12 @@ class LiveCardProvider extends ChangeNotifier {
} }
//END //END
if (hasActivityStarted && if ((currentState == LiveCardState.afternoon || currentState == LiveCardState.morning || currentState == LiveCardState.night) && hasActivityStarted && nextLesson != null &&
nextLesson!.start.difference(now).inMinutes > 60) {
debugPrint("Több, mint 1 óra van az első óráig. Befejezés...");
PlatformChannel.endLiveActivity();
hasActivityStarted = false;
} else if (hasActivityStarted &&
!hasDayEnd && !hasDayEnd &&
nextLesson == null && nextLesson == null &&
now.isAfter(prevLesson!.end)) { now.isAfter(prevLesson!.end)) {
@ -384,4 +389,4 @@ class LiveCardProvider extends ChangeNotifier {
List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? []) List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? [])
.where((l) => _sameDate(l.date, _now())) .where((l) => _sameDate(l.date, _now()))
.toList(); .toList();
} }

View File

@ -7,17 +7,23 @@ import 'package:provider/provider.dart';
class SelfNoteProvider with ChangeNotifier { class SelfNoteProvider with ChangeNotifier {
late List<SelfNote> _notes; late List<SelfNote> _notes;
late List<TodoItem> _todoItems;
late BuildContext _context; late BuildContext _context;
List<SelfNote> get notes => _notes; List<SelfNote> get notes => _notes;
List<TodoItem> get todos => _todoItems;
SelfNoteProvider({ SelfNoteProvider({
List<SelfNote> initialNotes = const [], List<SelfNote> initialNotes = const [],
List<TodoItem> initialTodoItems = const [],
required BuildContext context, required BuildContext context,
}) { }) {
_notes = List.castFrom(initialNotes); _notes = List.castFrom(initialNotes);
_todoItems = List.castFrom(initialTodoItems);
_context = context; _context = context;
if (_notes.isEmpty) restore(); if (_notes.isEmpty) restore();
if (_todoItems.isEmpty) restoreTodo();
} }
// restore self notes from db // restore self notes from db
@ -38,6 +44,24 @@ class SelfNoteProvider with ChangeNotifier {
} }
} }
// restore todo items from db
Future<void> restoreTodo() async {
String? userId = Provider.of<UserProvider>(_context, listen: false).id;
// await Provider.of<DatabaseProvider>(_context, listen: false)
// .userStore
// .storeSelfNotes([], userId: userId!);
// load self notes from db
if (userId != null) {
var dbTodo = await Provider.of<DatabaseProvider>(_context, listen: false)
.userQuery
.getTodoItems(userId: userId);
_todoItems = dbTodo;
notifyListeners();
}
}
// fetches fresh data from api (not needed, cuz no api for that) // fetches fresh data from api (not needed, cuz no api for that)
// Future<void> fetch() async { // Future<void> fetch() async {
// } // }
@ -54,4 +78,17 @@ class SelfNoteProvider with ChangeNotifier {
_notes = notes; _notes = notes;
notifyListeners(); notifyListeners();
} }
// store todo items in db
Future<void> storeTodo(List<TodoItem> todos) async {
User? user = Provider.of<UserProvider>(_context, listen: false).user;
if (user == null) throw "Cannot store Self Notes for User null";
String userId = user.id;
await Provider.of<DatabaseProvider>(_context, listen: false)
.userStore
.storeSelfTodoItems(todos, userId: userId);
_todoItems = todos;
notifyListeners();
}
} }

View File

@ -23,6 +23,7 @@ class UserProvider with ChangeNotifier {
String? get nickname => user?.nickname; String? get nickname => user?.nickname;
String get picture => user?.picture ?? ""; String get picture => user?.picture ?? "";
String? get displayName => user?.displayName; String? get displayName => user?.displayName;
int? get gradeStreak => user?.gradeStreak;
final SettingsProvider _settings; final SettingsProvider _settings;

View File

@ -45,6 +45,7 @@ const settingsDB = DatabaseStruct("settings", {
// more // more
"show_breaks": int, "show_breaks": int,
"font_family": String, "font_family": String,
"title_only_font": int,
"plus_session_id": String, "plus_session_id": String,
"cal_sync_room_location": String, "cal_sync_show_exams": int, "cal_sync_room_location": String, "cal_sync_show_exams": int,
"cal_sync_show_teacher": int, "cal_sync_renamed": int, "cal_sync_show_teacher": int, "cal_sync_renamed": int,
@ -52,6 +53,7 @@ const settingsDB = DatabaseStruct("settings", {
"nav_shadow": int, "nav_shadow": int,
"new_colors": int, "new_colors": int,
"uwu_mode": int, "uwu_mode": int,
"new_popups": int,
// quick settings // quick settings
"q_timetable_lesson_num": int, "q_timetable_sub_tiles": int, "q_timetable_lesson_num": int, "q_timetable_sub_tiles": int,
"q_subjects_sub_tiles": int, "q_subjects_sub_tiles": int,
@ -61,7 +63,8 @@ const settingsDB = DatabaseStruct("settings", {
const usersDB = DatabaseStruct("users", { const usersDB = DatabaseStruct("users", {
"id": String, "name": String, "username": String, "password": String, "id": String, "name": String, "username": String, "password": String,
"institute_code": String, "student": String, "role": int, "institute_code": String, "student": String, "role": int,
"nickname": String, "picture": String // premium only "nickname": String, "picture": String, // premium only (it's now plus btw)
"grade_streak": int,
}); });
const userDataDB = DatabaseStruct("user_data", { const userDataDB = DatabaseStruct("user_data", {
"id": String, "grades": String, "timetable": String, "exams": String, "id": String, "grades": String, "timetable": String, "exams": String,
@ -84,12 +87,13 @@ const userDataDB = DatabaseStruct("user_data", {
"goal_befores": String, "goal_befores": String,
"goal_pin_dates": String, "goal_pin_dates": String,
// todo and notes // todo and notes
"todo_items": String, "self_notes": String, "todo_items": String, "self_notes": String, "self_todo": String,
// v5 shit // v5 shit
"roundings": String, "roundings": String,
"grade_rarities": String, "grade_rarities": String,
"linked_accounts": String, "linked_accounts": String,
"custom_lesson_desc": String, "custom_lesson_desc": String,
"watch_data": String,
}); });
Future<void> createTable(Database db, DatabaseStruct struct) => Future<void> createTable(Database db, DatabaseStruct struct) =>
@ -129,7 +133,12 @@ Future<Database> initDB(DatabaseProvider database) async {
await migrateDB( await migrateDB(
db, db,
struct: usersDB, struct: usersDB,
defaultValues: {"role": 0, "nickname": "", "picture": ""}, defaultValues: {
"role": 0,
"nickname": "",
"picture": "",
"grade_streak": 0
},
); );
await migrateDB(db, struct: userDataDB, defaultValues: { await migrateDB(db, struct: userDataDB, defaultValues: {
"grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]", "grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]",
@ -152,12 +161,13 @@ Future<Database> initDB(DatabaseProvider database) async {
"goal_befores": "{}", "goal_befores": "{}",
"goal_pin_dates": "{}", "goal_pin_dates": "{}",
// todo and notes // todo and notes
"todo_items": "{}", "self_notes": "[]", "todo_items": "{}", "self_notes": "[]", "self_todo": "[]",
// v5 shit // v5 shit
"roundings": "{}", "roundings": "{}",
"grade_rarities": "{}", "grade_rarities": "{}",
"linked_accounts": "[]", "linked_accounts": "[]",
"custom_lesson_desc": "{}", "custom_lesson_desc": "{}",
"watch_data": "{}",
}); });
} catch (error) { } catch (error) {
print("ERROR: migrateDB: $error"); print("ERROR: migrateDB: $error");

View File

@ -317,6 +317,18 @@ class UserDatabaseQuery {
return selfNotes; return selfNotes;
} }
Future<List<TodoItem>> getTodoItems({required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return [];
String? todoItemsJson = userData.elementAt(0)["self_todo"] as String?;
if (todoItemsJson == null) return [];
List<TodoItem> todoItems = (jsonDecode(todoItemsJson) as List)
.map((e) => TodoItem.fromJson(e))
.toList();
return todoItems;
}
// v5 // v5
Future<Map<String, String>> getRoundings({required String userId}) async { Future<Map<String, String>> getRoundings({required String userId}) async {
List<Map> userData = List<Map> userData =

View File

@ -196,6 +196,13 @@ class UserDatabaseStore {
where: "id = ?", whereArgs: [userId]); where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeSelfTodoItems(List<TodoItem> todoItems,
{required String userId}) async {
String todoItemsJson = jsonEncode(todoItems.map((e) => e.json).toList());
await db.update("user_data", {"self_todo": todoItemsJson},
where: "id = ?", whereArgs: [userId]);
}
// v5 // v5
Future<void> storeRoundings(Map<String, String> roundings, Future<void> storeRoundings(Map<String, String> roundings,
{required String userId}) async { {required String userId}) async {

View File

@ -212,7 +212,7 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
), ),
notificationDetails, notificationDetails,
payload: "grades"); payload: "grades");
} else if (settingsProvider.gradeOpeningFun) { } else if (settingsProvider.gradeOpeningFun) {
// if surprise grades are enabled, show a notification without the grade // if surprise grades are enabled, show a notification without the grade
await flutterLocalNotificationsPlugin.show( await flutterLocalNotificationsPlugin.show(
grade.id.hashCode, grade.id.hashCode,
@ -485,9 +485,10 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
lesson.lessonIndex, lesson.lessonIndex,
lesson.name, lesson.name,
dayTitle(lesson.date), dayTitle(lesson.date),
lesson.substituteTeacher!.isRenamed ((lesson.substituteTeacher?.isRenamed ?? false)
? lesson.substituteTeacher!.renamedTo! ? lesson.substituteTeacher?.renamedTo!
: lesson.substituteTeacher!.name : lesson.substituteTeacher?.name) ??
'',
], ],
), ),
notificationDetails, notificationDetails,
@ -505,9 +506,10 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
dayTitle(lesson.date), dayTitle(lesson.date),
lesson.lessonIndex, lesson.lessonIndex,
lesson.name, lesson.name,
lesson.substituteTeacher!.isRenamed ((lesson.substituteTeacher?.isRenamed ?? false)
? lesson.substituteTeacher!.renamedTo! ? lesson.substituteTeacher?.renamedTo!
: lesson.substituteTeacher!.name : lesson.substituteTeacher?.name) ??
'',
], ],
), ),
notificationDetails, notificationDetails,
@ -525,9 +527,10 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
lesson.lessonIndex, lesson.lessonIndex,
lesson.name, lesson.name,
dayTitle(lesson.date), dayTitle(lesson.date),
lesson.substituteTeacher!.isRenamed ((lesson.substituteTeacher?.isRenamed ?? false)
? lesson.substituteTeacher!.renamedTo! ? lesson.substituteTeacher?.renamedTo!
: lesson.substituteTeacher!.name : lesson.substituteTeacher?.name) ??
'',
], ],
), ),
notificationDetails, notificationDetails,
@ -608,9 +611,10 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
lesson.lessonIndex, lesson.lessonIndex,
lesson.name, lesson.name,
dayTitle(lesson.date), dayTitle(lesson.date),
lesson.substituteTeacher!.isRenamed ((lesson.substituteTeacher?.isRenamed ?? false)
? lesson.substituteTeacher!.renamedTo! ? lesson.substituteTeacher?.renamedTo!
: lesson.substituteTeacher!.name : lesson.substituteTeacher?.name) ??
'',
], ],
), ),
notificationDetails, notificationDetails,
@ -629,9 +633,10 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
dayTitle(lesson.date), dayTitle(lesson.date),
lesson.lessonIndex, lesson.lessonIndex,
lesson.name, lesson.name,
lesson.substituteTeacher!.isRenamed ((lesson.substituteTeacher?.isRenamed ?? false)
? lesson.substituteTeacher!.renamedTo! ? lesson.substituteTeacher?.renamedTo!
: lesson.substituteTeacher!.name : lesson.substituteTeacher?.name) ??
'',
], ],
), ),
notificationDetails, notificationDetails,

View File

@ -292,3 +292,105 @@ class ShortSubject {
return subject?.name.capital() ?? subjectName?.capital() ?? "?"; return subject?.name.capital() ?? subjectName?.capital() ?? "?";
} }
} }
// new v5 thingie
class SubjectBooklet {
// static String resolveName({GradeSubject? subject, String? subjectName}) =>
// _resolve(subject: subject, subjectName: subjectName).name;
static String resolveVariant(
{GradeSubject? subject,
String? subjectName,
required BuildContext context}) =>
_resolve(subject: subject, subjectName: subjectName);
static String _resolve({GradeSubject? subject, String? subjectName}) {
assert(!(subject == null && subjectName == null));
String name = (subject?.name ?? subjectName ?? "")
.toLowerCase()
.specialChars()
.trim();
String category =
subject?.category.description.toLowerCase().specialChars() ?? "";
String basePath = "assets/svg/cover_arts";
// todo: check for categories
if (RegExp("mate(k|matika)").hasMatch(name) || category == "matematika") {
return "$basePath/grid.svg";
} else if (RegExp("magyar nyelv|nyelvtan").hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("irodalom").hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("tor(i|tenelem)").hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("foldrajz").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("rajz|muvtori|muveszet|vizualis").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("fizika").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("^enek|zene|szolfezs|zongora|korus").hasMatch(name)) {
return "$basePath/vocal.svg";
} else if (RegExp("^tes(i|tneveles)|sport|edzeselmelet").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("kemia").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("biologia").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp(
"kornyezet|termeszet ?(tudomany|ismeret)|hon( es nep)?ismeret")
.hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("(hit|erkolcs)tan|vallas|etika|bibliaismeret")
.hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("penzugy").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("informatika|szoftver|iroda|digitalis").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("prog").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("halozat").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("szinhaz").hasMatch(name)) {
return "$basePath/vocal.svg";
} else if (RegExp("film|media").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("elektro(tech)?nika").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("gepesz|mernok|ipar").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("technika").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("tanc").hasMatch(name)) {
return "$basePath/vocal.svg";
} else if (RegExp("filozofia").hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("osztaly(fonoki|kozosseg)|kozossegi|neveles")
.hasMatch(name) ||
name == "ofo") {
return "$basePath/plain.svg";
} else if (RegExp("gazdasag").hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("szorgalom").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("magatartas").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp(
"angol|nemet|francia|olasz|orosz|spanyol|latin|kinai|nyelv")
.hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("linux").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("adatbazis").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("asztali alkalmazasok").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("projekt").hasMatch(name)) {
return "$basePath/plain.svg";
}
return "$basePath/plain.svg";
}
}

View File

@ -33,3 +33,37 @@ class SelfNote {
'note_type': noteType == NoteType.image ? 'image' : 'text', 'note_type': noteType == NoteType.image ? 'image' : 'text',
}; };
} }
class TodoItem {
String id;
String title;
String content;
bool done;
Map? json;
TodoItem({
required this.id,
required this.title,
required this.content,
required this.done,
this.json,
});
factory TodoItem.fromJson(Map json) {
return TodoItem(
id: json['id'],
title: json['title'],
content: json['content'],
done: json['done'],
json: json,
);
}
get toJson => {
'id': id,
'title': title,
'content': content,
'done': done,
};
}

View File

@ -96,6 +96,7 @@ class SettingsProvider extends ChangeNotifier {
// more // more
bool _showBreaks; bool _showBreaks;
String _fontFamily; String _fontFamily;
bool _titleOnlyFont;
String _plusSessionId; String _plusSessionId;
String _calSyncRoomLocation; String _calSyncRoomLocation;
bool _calSyncShowExams; bool _calSyncShowExams;
@ -105,6 +106,7 @@ class SettingsProvider extends ChangeNotifier {
bool _navShadow; bool _navShadow;
bool _newColors; bool _newColors;
bool _uwuMode; bool _uwuMode;
bool _newPopups;
// quick settings // quick settings
bool _qTimetableLessonNum; bool _qTimetableLessonNum;
bool _qTimetableSubTiles; bool _qTimetableSubTiles;
@ -167,6 +169,7 @@ class SettingsProvider extends ChangeNotifier {
required String pinSetNotify, required String pinSetNotify,
required String pinSetExtras, required String pinSetExtras,
required String fontFamily, required String fontFamily,
required bool titleOnlyFont,
required String plusSessionId, required String plusSessionId,
required String calSyncRoomLocation, required String calSyncRoomLocation,
required bool calSyncShowExams, required bool calSyncShowExams,
@ -176,6 +179,7 @@ class SettingsProvider extends ChangeNotifier {
required bool navShadow, required bool navShadow,
required bool newColors, required bool newColors,
required bool uwuMode, required bool uwuMode,
required bool newPopups,
required bool qTimetableLessonNum, required bool qTimetableLessonNum,
required bool qTimetableSubTiles, required bool qTimetableSubTiles,
required bool qSubjectsSubTiles, required bool qSubjectsSubTiles,
@ -235,6 +239,7 @@ class SettingsProvider extends ChangeNotifier {
_pinSetNotify = pinSetNotify, _pinSetNotify = pinSetNotify,
_pinSetExtras = pinSetExtras, _pinSetExtras = pinSetExtras,
_fontFamily = fontFamily, _fontFamily = fontFamily,
_titleOnlyFont = titleOnlyFont,
_plusSessionId = plusSessionId, _plusSessionId = plusSessionId,
_calSyncRoomLocation = calSyncRoomLocation, _calSyncRoomLocation = calSyncRoomLocation,
_calSyncShowExams = calSyncShowExams, _calSyncShowExams = calSyncShowExams,
@ -244,6 +249,7 @@ class SettingsProvider extends ChangeNotifier {
_navShadow = navShadow, _navShadow = navShadow,
_newColors = newColors, _newColors = newColors,
_uwuMode = uwuMode, _uwuMode = uwuMode,
_newPopups = newPopups,
_qTimetableLessonNum = qTimetableLessonNum, _qTimetableLessonNum = qTimetableLessonNum,
_qTimetableSubTiles = qTimetableSubTiles, _qTimetableSubTiles = qTimetableSubTiles,
_qSubjectsSubTiles = qSubjectsSubTiles; _qSubjectsSubTiles = qSubjectsSubTiles;
@ -322,6 +328,7 @@ class SettingsProvider extends ChangeNotifier {
pinSetNotify: map['notify_s_pin'], pinSetNotify: map['notify_s_pin'],
pinSetExtras: map['extras_s_pin'], pinSetExtras: map['extras_s_pin'],
fontFamily: map['font_family'], fontFamily: map['font_family'],
titleOnlyFont: map['title_only_font'] == 1,
plusSessionId: map['plus_session_id'], plusSessionId: map['plus_session_id'],
calSyncRoomLocation: map['cal_sync_room_location'], calSyncRoomLocation: map['cal_sync_room_location'],
calSyncShowExams: map['cal_sync_show_exams'] == 1, calSyncShowExams: map['cal_sync_show_exams'] == 1,
@ -331,6 +338,7 @@ class SettingsProvider extends ChangeNotifier {
navShadow: map['nav_shadow'] == 1, navShadow: map['nav_shadow'] == 1,
newColors: map['new_colors'] == 1, newColors: map['new_colors'] == 1,
uwuMode: map['uwu_mode'] == 1, uwuMode: map['uwu_mode'] == 1,
newPopups: map['new_popups'] == 1,
qTimetableLessonNum: map['q_timetable_lesson_num'] == 1, qTimetableLessonNum: map['q_timetable_lesson_num'] == 1,
qTimetableSubTiles: map['q_timetable_sub_tiles'] == 1, qTimetableSubTiles: map['q_timetable_sub_tiles'] == 1,
qSubjectsSubTiles: map['q_subjects_sub_tiles'] == 1, qSubjectsSubTiles: map['q_subjects_sub_tiles'] == 1,
@ -397,6 +405,7 @@ class SettingsProvider extends ChangeNotifier {
"notify_s_pin": _pinSetNotify, "notify_s_pin": _pinSetNotify,
"extras_s_pin": _pinSetExtras, "extras_s_pin": _pinSetExtras,
"font_family": _fontFamily, "font_family": _fontFamily,
"title_only_font": _titleOnlyFont ? 1 : 0,
"plus_session_id": _plusSessionId, "plus_session_id": _plusSessionId,
"cal_sync_room_location": _calSyncRoomLocation, "cal_sync_room_location": _calSyncRoomLocation,
"cal_sync_show_exams": _calSyncShowExams ? 1 : 0, "cal_sync_show_exams": _calSyncShowExams ? 1 : 0,
@ -406,6 +415,7 @@ class SettingsProvider extends ChangeNotifier {
"nav_shadow": _navShadow ? 1 : 0, "nav_shadow": _navShadow ? 1 : 0,
"new_colors": _newColors ? 1 : 0, "new_colors": _newColors ? 1 : 0,
"uwu_mode": _uwuMode ? 1 : 0, "uwu_mode": _uwuMode ? 1 : 0,
"new_popups": _newPopups ? 1 : 0,
"q_timetable_lesson_num": _qTimetableLessonNum ? 1 : 0, "q_timetable_lesson_num": _qTimetableLessonNum ? 1 : 0,
"q_timetable_sub_tiles": _qTimetableSubTiles ? 1 : 0, "q_timetable_sub_tiles": _qTimetableSubTiles ? 1 : 0,
"q_subjects_sub_tiles": _qSubjectsSubTiles ? 1 : 0, "q_subjects_sub_tiles": _qSubjectsSubTiles ? 1 : 0,
@ -476,6 +486,7 @@ class SettingsProvider extends ChangeNotifier {
pinSetNotify: '', pinSetNotify: '',
pinSetExtras: '', pinSetExtras: '',
fontFamily: '', fontFamily: '',
titleOnlyFont: false,
plusSessionId: '', plusSessionId: '',
calSyncRoomLocation: 'location', calSyncRoomLocation: 'location',
calSyncShowExams: true, calSyncShowExams: true,
@ -485,6 +496,7 @@ class SettingsProvider extends ChangeNotifier {
navShadow: true, navShadow: true,
newColors: true, newColors: true,
uwuMode: false, uwuMode: false,
newPopups: true,
qTimetableLessonNum: true, qTimetableLessonNum: true,
qTimetableSubTiles: true, qTimetableSubTiles: true,
qSubjectsSubTiles: true, qSubjectsSubTiles: true,
@ -546,6 +558,7 @@ class SettingsProvider extends ChangeNotifier {
String get currentThemeCreator => _currentThemeCreator; String get currentThemeCreator => _currentThemeCreator;
bool get showBreaks => _showBreaks; bool get showBreaks => _showBreaks;
String get fontFamily => _fontFamily; String get fontFamily => _fontFamily;
bool get titleOnlyFont => _titleOnlyFont;
String get plusSessionId => _plusSessionId; String get plusSessionId => _plusSessionId;
String get calSyncRoomLocation => _calSyncRoomLocation; String get calSyncRoomLocation => _calSyncRoomLocation;
bool get calSyncShowExams => _calSyncShowExams; bool get calSyncShowExams => _calSyncShowExams;
@ -555,6 +568,7 @@ class SettingsProvider extends ChangeNotifier {
bool get navShadow => _navShadow; bool get navShadow => _navShadow;
bool get newColors => _newColors; bool get newColors => _newColors;
bool get uwuMode => _uwuMode; bool get uwuMode => _uwuMode;
bool get newPopups => _newPopups;
bool get qTimetableLessonNum => _qTimetableLessonNum; bool get qTimetableLessonNum => _qTimetableLessonNum;
bool get qTimetableSubTiles => _qTimetableSubTiles; bool get qTimetableSubTiles => _qTimetableSubTiles;
bool get qSubjectsSubTiles => _qSubjectsSubTiles; bool get qSubjectsSubTiles => _qSubjectsSubTiles;
@ -612,6 +626,7 @@ class SettingsProvider extends ChangeNotifier {
String? currentThemeCreator, String? currentThemeCreator,
bool? showBreaks, bool? showBreaks,
String? fontFamily, String? fontFamily,
bool? titleOnlyFont,
String? plusSessionId, String? plusSessionId,
String? calSyncRoomLocation, String? calSyncRoomLocation,
bool? calSyncShowExams, bool? calSyncShowExams,
@ -621,6 +636,7 @@ class SettingsProvider extends ChangeNotifier {
bool? navShadow, bool? navShadow,
bool? newColors, bool? newColors,
bool? uwuMode, bool? uwuMode,
bool? newPopups,
bool? qTimetableLessonNum, bool? qTimetableLessonNum,
bool? qTimetableSubTiles, bool? qTimetableSubTiles,
bool? qSubjectsSubTiles, bool? qSubjectsSubTiles,
@ -777,6 +793,9 @@ class SettingsProvider extends ChangeNotifier {
if (fontFamily != null && fontFamily != _fontFamily) { if (fontFamily != null && fontFamily != _fontFamily) {
_fontFamily = fontFamily; _fontFamily = fontFamily;
} }
if (titleOnlyFont != null && titleOnlyFont != _titleOnlyFont) {
_titleOnlyFont = titleOnlyFont;
}
if (plusSessionId != null && plusSessionId != _plusSessionId) { if (plusSessionId != null && plusSessionId != _plusSessionId) {
_plusSessionId = plusSessionId; _plusSessionId = plusSessionId;
} }
@ -806,6 +825,9 @@ class SettingsProvider extends ChangeNotifier {
if (uwuMode != null && uwuMode != _uwuMode) { if (uwuMode != null && uwuMode != _uwuMode) {
_uwuMode = uwuMode; _uwuMode = uwuMode;
} }
if (newPopups != null && newPopups != _newPopups) {
_newPopups = newPopups;
}
if (qTimetableLessonNum != null && if (qTimetableLessonNum != null &&
qTimetableLessonNum != _qTimetableLessonNum) { qTimetableLessonNum != _qTimetableLessonNum) {
_qTimetableLessonNum = qTimetableLessonNum; _qTimetableLessonNum = qTimetableLessonNum;

View File

@ -16,8 +16,10 @@ class User {
Role role; Role role;
String nickname; String nickname;
String picture; String picture;
int gradeStreak;
String get displayName => nickname != '' ? nickname : name; String get displayName => nickname != '' ? nickname : name;
bool get hasStreak => gradeStreak > 0;
User({ User({
String? id, String? id,
@ -29,6 +31,7 @@ class User {
required this.role, required this.role,
this.nickname = "", this.nickname = "",
this.picture = "", this.picture = "",
this.gradeStreak = 0,
}) { }) {
if (id != null) { if (id != null) {
this.id = id; this.id = id;
@ -57,6 +60,7 @@ class User {
role: Role.values[map["role"] ?? 0], role: Role.values[map["role"] ?? 0],
nickname: map["nickname"] ?? "", nickname: map["nickname"] ?? "",
picture: map["picture"] ?? "", picture: map["picture"] ?? "",
gradeStreak: map["grade_streak"] ?? 0,
); );
} }

View File

@ -104,9 +104,10 @@ class AppTheme {
brightness: Brightness.light, brightness: Brightness.light,
useMaterial3: true, useMaterial3: true,
fontFamily: _defaultFontFamily, fontFamily: _defaultFontFamily,
textTheme: textTheme: !settings.titleOnlyFont
googleFontsMap[settings.fontFamily]?.apply(bodyColor: textColor) ?? ? (googleFontsMap[settings.fontFamily]?.apply(bodyColor: textColor) ??
const TextTheme().apply(bodyColor: textColor), const TextTheme().apply(bodyColor: textColor))
: null,
scaffoldBackgroundColor: backgroundColor, scaffoldBackgroundColor: backgroundColor,
primaryColor: lightColors.filc, primaryColor: lightColors.filc,
dividerColor: const Color(0x00000000), dividerColor: const Color(0x00000000),
@ -229,8 +230,9 @@ class AppTheme {
brightness: Brightness.dark, brightness: Brightness.dark,
useMaterial3: true, useMaterial3: true,
fontFamily: _defaultFontFamily, fontFamily: _defaultFontFamily,
textTheme: textTheme: !settings.titleOnlyFont
googleFontsMap[settings.fontFamily]?.apply(bodyColor: textColor), ? (googleFontsMap[settings.fontFamily]?.apply(bodyColor: textColor))
: null,
scaffoldBackgroundColor: backgroundColor, scaffoldBackgroundColor: backgroundColor,
primaryColor: darkColors.filc, primaryColor: darkColors.filc,
dividerColor: const Color(0x00000000), dividerColor: const Color(0x00000000),

View File

@ -192,6 +192,8 @@ class FilcColorPickerState extends State<FilcColorPicker> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
bool advOverride = widget.colorMode == CustomColorMode.grade ? true : false;
if (MediaQuery.of(context).orientation == Orientation.portrait || if (MediaQuery.of(context).orientation == Orientation.portrait ||
widget.portraitOnly) { widget.portraitOnly) {
return Column( return Column(
@ -218,7 +220,7 @@ class FilcColorPickerState extends State<FilcColorPicker> {
child: colorPickerSlider(TrackType.saturation), child: colorPickerSlider(TrackType.saturation),
), ),
), ),
if (isAdvancedView) if (isAdvancedView || advOverride)
Padding( Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12.0), padding: const EdgeInsets.only(left: 12.0, right: 12.0),
child: SizedBox( child: SizedBox(
@ -230,7 +232,7 @@ class FilcColorPickerState extends State<FilcColorPicker> {
], ],
), ),
), ),
if (isAdvancedView && if ((isAdvancedView || advOverride) &&
widget.colorMode != CustomColorMode.theme && widget.colorMode != CustomColorMode.theme &&
widget.colorMode != CustomColorMode.enterId) widget.colorMode != CustomColorMode.enterId)
Padding( Padding(
@ -295,7 +297,8 @@ class FilcColorPickerState extends State<FilcColorPicker> {
], ],
), ),
), ),
if (widget.colorMode != CustomColorMode.enterId) if (widget.colorMode != CustomColorMode.enterId &&
widget.colorMode != CustomColorMode.grade)
SizedBox( SizedBox(
height: 70 * (widget.colorMode == CustomColorMode.theme ? 2 : 1), height: 70 * (widget.colorMode == CustomColorMode.theme ? 2 : 1),
child: BlockPicker( child: BlockPicker(
@ -347,7 +350,8 @@ class FilcColorPickerState extends State<FilcColorPicker> {
), ),
), ),
if (widget.colorMode != CustomColorMode.theme && if (widget.colorMode != CustomColorMode.theme &&
widget.colorMode != CustomColorMode.enterId) widget.colorMode != CustomColorMode.enterId &&
!advOverride)
Material( Material(
color: Colors.transparent, color: Colors.transparent,
child: InkWell( child: InkWell(

View File

@ -1,3 +1,4 @@
import 'package:i18n_extension/i18n_extension.dart';
import 'package:refilc/models/settings.dart'; import 'package:refilc/models/settings.dart';
import 'package:refilc_kreta_api/providers/exam_provider.dart'; import 'package:refilc_kreta_api/providers/exam_provider.dart';
import 'package:refilc_kreta_api/providers/homework_provider.dart'; import 'package:refilc_kreta_api/providers/homework_provider.dart';
@ -8,7 +9,8 @@ import 'package:refilc_kreta_api/models/lesson.dart';
import 'package:refilc/utils/format.dart'; import 'package:refilc/utils/format.dart';
import 'package:refilc_mobile_ui/common/panel/panel.dart'; import 'package:refilc_mobile_ui/common/panel/panel.dart';
import 'package:refilc_mobile_ui/common/round_border_icon.dart'; import 'package:refilc_mobile_ui/common/round_border_icon.dart';
import 'package:refilc_mobile_ui/common/widgets/exam/exam_view.dart'; // import 'package:refilc_mobile_ui/common/widgets/exam/exam_view.dart';
import 'package:refilc_mobile_ui/common/widgets/exam/exam_viewable.dart';
import 'package:refilc_mobile_ui/common/widgets/homework/homework_view.dart'; import 'package:refilc_mobile_ui/common/widgets/homework/homework_view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
@ -109,7 +111,8 @@ class LessonTile extends StatelessWidget {
title: exam.description != "" title: exam.description != ""
? exam.description ? exam.description
: exam.mode?.description ?? "exam".i18n, : exam.mode?.description ?? "exam".i18n,
onPressed: () => ExamView.show(exam, context: context), // onPressed: () => ExamView.show(exam, context: context),
onPressed: () => ExamPopup.show(context: context, exam: exam),
)); ));
} }
} }
@ -190,7 +193,7 @@ class LessonTile extends StatelessWidget {
: Transform.translate( : Transform.translate(
offset: const Offset(0, -2.0), offset: const Offset(0, -2.0),
child: Text( child: Text(
"${DateFormat("H:mm").format(lesson.start)}-${DateFormat("H:mm").format(lesson.end)}", "${DateFormat("E, H:mm", I18n.of(context).locale.toString()).format(lesson.start)}-${DateFormat("H:mm").format(lesson.end)}",
textAlign: TextAlign.start, textAlign: TextAlign.start,
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,

View File

@ -3,7 +3,7 @@ description: "Egy nem hivatalos e-KRÉTA kliens, diákoktól diákoknak."
homepage: https://refilc.hu homepage: https://refilc.hu
publish_to: "none" publish_to: "none"
version: 5.0.0+257 version: 5.0.1+265
environment: environment:
sdk: ">=2.17.0 <=3.3.2" sdk: ">=2.17.0 <=3.3.2"
@ -104,6 +104,7 @@ flutter:
- assets/svg/menu_icons/ - assets/svg/menu_icons/
- assets/other/dirtywords.xml - assets/other/dirtywords.xml
- assets/svg/ - assets/svg/
- assets/svg/cover_arts/
fonts: fonts:
- family: FilcIcons - family: FilcIcons

View File

@ -268,7 +268,7 @@ class GradesPageState extends State<GradesPage> {
title: Padding( title: Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Text( child: Text(
"Grades".i18n, "page_title_grades".i18n,
style: TextStyle( style: TextStyle(
color: AppColors.of(context).text, color: AppColors.of(context).text,
fontSize: 32.0, fontSize: 32.0,

View File

@ -11,6 +11,7 @@ class Student {
String? address; String? address;
String? groupId; String? groupId;
List<String> parents; List<String> parents;
// List<String> parentsPhone;
String? className; String? className;
Student({ Student({
@ -21,6 +22,7 @@ class Student {
required this.yearId, required this.yearId,
this.address, this.address,
required this.parents, required this.parents,
// required this.parentsPhone,
this.json, this.json,
}); });

View File

@ -50,7 +50,8 @@ class GradeProvider with ChangeNotifier {
String? userId = _user.id; String? userId = _user.id;
if (userId != null) { if (userId != null) {
final userStore = _database.userStore; final userStore = _database.userStore;
userStore.storeLastSeen(DateTime.now(), userId: userId, category: LastSeenCategory.surprisegrade); userStore.storeLastSeen(DateTime.now(),
userId: userId, category: LastSeenCategory.surprisegrade);
_lastSeen = DateTime.now(); _lastSeen = DateTime.now();
} }
} }
@ -59,7 +60,8 @@ class GradeProvider with ChangeNotifier {
String? userId = _user.id; String? userId = _user.id;
if (userId != null) { if (userId != null) {
final userStore = _database.userStore; final userStore = _database.userStore;
userStore.storeLastSeen(DateTime(1969), userId: userId, category: LastSeenCategory.surprisegrade); userStore.storeLastSeen(DateTime(1969),
userId: userId, category: LastSeenCategory.surprisegrade);
_lastSeen = DateTime(1969); _lastSeen = DateTime(1969);
} }
} }
@ -73,9 +75,11 @@ class GradeProvider with ChangeNotifier {
_grades = await userQuery.getGrades(userId: userId); _grades = await userQuery.getGrades(userId: userId);
await convertBySettings(); await convertBySettings();
await getGradeStreak();
_groupAvg = await userQuery.getGroupAverages(userId: userId); _groupAvg = await userQuery.getGroupAverages(userId: userId);
notifyListeners(); notifyListeners();
DateTime lastSeenDB = await userQuery.lastSeen(userId: userId, category: LastSeenCategory.surprisegrade); DateTime lastSeenDB = await userQuery.lastSeen(
userId: userId, category: LastSeenCategory.surprisegrade);
if (lastSeenDB.millisecondsSinceEpoch == 0 || if (lastSeenDB.millisecondsSinceEpoch == 0 ||
lastSeenDB.year == 0 || lastSeenDB.year == 0 ||
!_settings.gradeOpeningFun) { !_settings.gradeOpeningFun) {
@ -133,6 +137,30 @@ class GradeProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
// get current grade streak and set it to the user
Future<void> getGradeStreak() async {
User? user = _user.user;
if (user == null) throw "Cannot get Grade Streak for User null";
// streak magic
int gradeStreak = 0;
List<Grade> grs = _grades;
grs.sort((a, b) => -a.date.compareTo(b.date));
for (Grade grade in grs) {
if (grade.value.value == 5) {
gradeStreak++;
} else {
break;
}
}
print(gradeStreak);
user.gradeStreak = gradeStreak;
notifyListeners();
}
// Fetches Grades from the Kreta API then stores them in the database // Fetches Grades from the Kreta API then stores them in the database
Future<void> fetch() async { Future<void> fetch() async {
// test cucc // test cucc
@ -173,6 +201,7 @@ class GradeProvider with ChangeNotifier {
await _database.userStore.storeGrades(grades, userId: userId); await _database.userStore.storeGrades(grades, userId: userId);
_grades = grades; _grades = grades;
await convertBySettings(); await convertBySettings();
await getGradeStreak();
} }
Future<void> storeGroupAvg(List<GroupAverage> groupAvgs) async { Future<void> storeGroupAvg(List<GroupAverage> groupAvgs) async {

View File

@ -19,11 +19,13 @@ class ShareProvider extends ChangeNotifier {
// } // }
// themes // themes
Future<SharedTheme> shareCurrentTheme(BuildContext context, Future<SharedTheme> shareCurrentTheme(
{bool isPublic = false, BuildContext context, {
bool shareNick = true, bool isPublic = false,
required SharedGradeColors gradeColors, bool shareNick = true,
String displayName = ''}) async { required SharedGradeColors gradeColors,
String displayName = '',
}) async {
final SettingsProvider settings = final SettingsProvider settings =
Provider.of<SettingsProvider>(context, listen: false); Provider.of<SettingsProvider>(context, listen: false);
@ -69,7 +71,25 @@ class ShareProvider extends ChangeNotifier {
if (gradeColorsJson != null) { if (gradeColorsJson != null) {
SharedTheme theme = SharedTheme.fromJson( SharedTheme theme = SharedTheme.fromJson(
themeJson, SharedGradeColors.fromJson(gradeColorsJson)); themeJson,
SharedGradeColors.fromJson(gradeColorsJson["public_id"] != ''
? gradeColorsJson
: {
"public_id": "0",
"is_public": false,
"nickname": "Anonymous",
"five_color":
SettingsProvider.defaultSettings().gradeColors[4].value,
"four_color":
SettingsProvider.defaultSettings().gradeColors[3].value,
"three_color":
SettingsProvider.defaultSettings().gradeColors[2].value,
"two_color":
SettingsProvider.defaultSettings().gradeColors[1].value,
"one_color":
SettingsProvider.defaultSettings().gradeColors[0].value,
}),
);
return theme; return theme;
} }
} }
@ -93,7 +113,25 @@ class ShareProvider extends ChangeNotifier {
if (gradeColorsJson != null) { if (gradeColorsJson != null) {
SharedTheme theme = SharedTheme.fromJson( SharedTheme theme = SharedTheme.fromJson(
t, SharedGradeColors.fromJson(gradeColorsJson)); t,
SharedGradeColors.fromJson(gradeColorsJson["public_id"] != ''
? gradeColorsJson
: {
"public_id": "0",
"is_public": false,
"nickname": "Anonymous",
"five_color":
SettingsProvider.defaultSettings().gradeColors[4].value,
"four_color":
SettingsProvider.defaultSettings().gradeColors[3].value,
"three_color":
SettingsProvider.defaultSettings().gradeColors[2].value,
"two_color":
SettingsProvider.defaultSettings().gradeColors[1].value,
"one_color":
SettingsProvider.defaultSettings().gradeColors[0].value,
}),
);
themes.add(theme); themes.add(theme);
} }
@ -134,8 +172,25 @@ class ShareProvider extends ChangeNotifier {
Map? gradeColorsJson = await FilcAPI.getSharedGradeColors(id); Map? gradeColorsJson = await FilcAPI.getSharedGradeColors(id);
if (gradeColorsJson != null) { if (gradeColorsJson != null) {
SharedGradeColors gradeColors = SharedGradeColors gradeColors = SharedGradeColors.fromJson(
SharedGradeColors.fromJson(gradeColorsJson); gradeColorsJson["public_id"] != ''
? gradeColorsJson
: {
"public_id": "0",
"is_public": false,
"nickname": "Anonymous",
"five_color":
SettingsProvider.defaultSettings().gradeColors[4].value,
"four_color":
SettingsProvider.defaultSettings().gradeColors[3].value,
"three_color":
SettingsProvider.defaultSettings().gradeColors[2].value,
"two_color":
SettingsProvider.defaultSettings().gradeColors[1].value,
"one_color":
SettingsProvider.defaultSettings().gradeColors[0].value,
},
);
return gradeColors; return gradeColors;
} }

View File

@ -1,13 +1,22 @@
import 'package:dotted_border/dotted_border.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/ui/widgets/grade/grade_tile.dart'; import 'package:refilc/ui/widgets/grade/grade_tile.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:i18n_extension/i18n_extension.dart'; import 'package:i18n_extension/i18n_extension.dart';
class AverageDisplay extends StatelessWidget { class AverageDisplay extends StatelessWidget {
const AverageDisplay({super.key, this.average = 0.0, this.border = false}); const AverageDisplay({
super.key,
this.average = 0.0,
this.border = false,
this.dashed = false,
this.scale = 1.0,
});
final double average; final double average;
final bool border; final bool border;
final bool dashed;
final double scale;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -20,25 +29,44 @@ class AverageDisplay extends StatelessWidget {
averageText = averageText.replaceAll(".", ","); averageText = averageText.replaceAll(".", ",");
} }
Widget txtWidget = Text(
average == 0.0 ? "-" : averageText,
textAlign: TextAlign.center,
style: TextStyle(
color: color, fontWeight: FontWeight.w600, fontSize: scale * 15.0),
maxLines: 1,
);
return Container( return Container(
width: border ? 57.0 : 54.0, width: (border ? 57.0 : 54.0) * scale,
padding: EdgeInsets.symmetric( padding: (border && dashed)
horizontal: 6.0 - (border ? 2 : 0), vertical: 5.0 - (border ? 2 : 0)), ? null
: EdgeInsets.symmetric(
horizontal: (6.0 - (border ? 2 : 0)) * scale,
vertical: (5.0 - (border ? 2 : 0))) *
scale,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(45.0), borderRadius:
border: border (border && dashed) ? null : BorderRadius.circular(45.0 * scale),
border: border && !dashed
? Border.fromBorderSide( ? Border.fromBorderSide(
BorderSide(color: color.withOpacity(.5), width: 1.0)) BorderSide(color: color.withOpacity(.5), width: 1.0 * scale))
: null, : null,
color: !border ? color.withOpacity(average == 0.0 ? .15 : .25) : null, color: !border ? color.withOpacity(average == 0.0 ? .15 : .25) : null,
), ),
child: Text( child: (border && dashed)
average == 0.0 ? "-" : averageText, ? DottedBorder(
textAlign: TextAlign.center, strokeWidth: 1.0 * scale,
style: TextStyle( padding: EdgeInsets.all(4.0 * scale),
color: color, fontWeight: FontWeight.w600, fontSize: 15.0), color: color.withOpacity(.5),
maxLines: 1, dashPattern: const [6, 6],
), radius: Radius.circular(45.0 * scale),
borderType: BorderType.RRect,
child: Center(
child: txtWidget,
),
)
: txtWidget,
); );
} }
} }

View File

@ -1,4 +1,5 @@
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:refilc/helpers/subject.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:refilc/theme/colors/utils.dart'; import 'package:refilc/theme/colors/utils.dart';
@ -113,7 +114,9 @@ class HeroScrollViewState extends State<HeroScrollView> {
Padding( Padding(
padding: const EdgeInsets.only(top: 26.0), padding: const EdgeInsets.only(top: 26.0),
child: SvgPicture.asset( child: SvgPicture.asset(
"assets/svg/mesh_bg.svg", // "assets/svg/mesh_bg.svg",
SubjectBooklet.resolveVariant(
context: context, subjectName: widget.title),
// ignore: deprecated_member_use // ignore: deprecated_member_use
color: ColorsUtils() color: ColorsUtils()
.darken( .darken(

View File

@ -49,6 +49,8 @@ extension Localization on String {
"d_npc": "d_npc":
"You're such a non-player character, we couldn't give you a personality.", "You're such a non-player character, we couldn't give you a personality.",
"s_npc": "In-game playtime (hours)", "s_npc": "In-game playtime (hours)",
// other
"year_index": "Lesson Number",
}, },
"hu_hu": { "hu_hu": {
// main // main
@ -96,6 +98,8 @@ extension Localization on String {
"d_npc": "d_npc":
"Egy akkora nagy non-player character vagy, hogy neked semmilyen személyiség nem jutott ezen kívül.", "Egy akkora nagy non-player character vagy, hogy neked semmilyen személyiség nem jutott ezen kívül.",
"s_npc": "In-game playtime (óra)", "s_npc": "In-game playtime (óra)",
// other
"year_index": "Éves óraszám",
}, },
"de_de": { "de_de": {
// main // main
@ -144,6 +148,8 @@ extension Localization on String {
"d_npc": "d_npc":
"Du bist einfach so sehr wie ein Computer, dass wir dir nicht einmal eine Persönlichkeit geben konnten.", "Du bist einfach so sehr wie ein Computer, dass wir dir nicht einmal eine Persönlichkeit geben konnten.",
"s_npc": "Spielzeit (Stunden)", "s_npc": "Spielzeit (Stunden)",
// other
"year_index": "Ordinalzahl",
} }
}; };

View File

@ -65,6 +65,7 @@ class ProfileButton extends StatelessWidget {
radius: child.radius, radius: child.radius,
badge: child.badge, badge: child.badge,
role: child.role, role: child.role,
gradeStreak: child.gradeStreak,
profilePictureString: child.profilePictureString, profilePictureString: child.profilePictureString,
onTap: () { onTap: () {
showSlidingBottomSheet( showSlidingBottomSheet(

View File

@ -21,6 +21,7 @@ class ProfileImage extends StatefulWidget {
this.censored = false, this.censored = false,
this.profilePictureString = "", this.profilePictureString = "",
this.isNotePfp = false, this.isNotePfp = false,
this.gradeStreak = false,
}); });
final void Function()? onTap; final void Function()? onTap;
@ -35,6 +36,7 @@ class ProfileImage extends StatefulWidget {
final bool censored; final bool censored;
final String profilePictureString; final String profilePictureString;
final bool isNotePfp; final bool isNotePfp;
final bool gradeStreak;
@override @override
State<ProfileImage> createState() => _ProfileImageState(); State<ProfileImage> createState() => _ProfileImageState();
@ -145,6 +147,20 @@ class _ProfileImageState extends State<ProfileImage> {
color: roleColor, size: widget.radius / 1.3), color: roleColor, size: widget.radius / 1.3),
), ),
), ),
// streak indicator
// if (widget.gradeStreak)
// SizedBox(
// height: widget.radius * 2,
// width: widget.radius * 2,
// child: Container(
// alignment: Alignment.topLeft,
// child: Text(
// '🔥',
// style: TextStyle(fontSize: widget.radius * 0.9),
// ),
// ),
// ),
], ],
); );
} }
@ -238,6 +254,29 @@ class _ProfileImageState extends State<ProfileImage> {
), ),
), ),
// streak indicator
if (widget.gradeStreak)
Hero(
tag: "${widget.heroTag!}streak_indicator",
child: FittedBox(
fit: BoxFit.fitHeight,
child: SizedBox(
height: widget.radius * 2,
width: widget.radius * 2,
child: Transform.translate(
offset: Offset(-widget.radius / 4, -widget.radius / 4),
child: Container(
alignment: Alignment.topLeft,
child: Text(
'🔥',
style: TextStyle(fontSize: widget.radius * 0.8),
),
),
),
),
),
),
Material( Material(
color: Colors.transparent, color: Colors.transparent,
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,

View File

@ -1,6 +1,7 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:i18n_extension/i18n_extension.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:refilc/helpers/subject.dart'; import 'package:refilc/helpers/subject.dart';
@ -13,8 +14,11 @@ import 'package:refilc_kreta_api/models/exam.dart';
import 'package:refilc_kreta_api/models/lesson.dart'; import 'package:refilc_kreta_api/models/lesson.dart';
import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart'; import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart';
import 'package:refilc_mobile_ui/common/round_border_icon.dart'; import 'package:refilc_mobile_ui/common/round_border_icon.dart';
import 'package:refilc_mobile_ui/common/viewable.dart';
import 'package:refilc_mobile_ui/common/widgets/card_handle.dart';
import 'package:refilc_mobile_ui/common/widgets/exam/exam_tile.dart'; import 'package:refilc_mobile_ui/common/widgets/exam/exam_tile.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:refilc_mobile_ui/common/widgets/exam/exam_view.dart';
class ExamViewable extends StatelessWidget { class ExamViewable extends StatelessWidget {
const ExamViewable(this.exam, const ExamViewable(this.exam,
@ -26,22 +30,25 @@ class ExamViewable extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( if (Provider.of<SettingsProvider>(context).newPopups) {
onTap: () => ExamPopup.show(context: context, exam: exam), return GestureDetector(
child: ExamTile( onTap: () => ExamPopup.show(context: context, exam: exam),
child: ExamTile(
exam,
showSubject: showSubject,
padding: tilePadding,
),
);
}
return Viewable(
tile: ExamTile(
exam, exam,
showSubject: showSubject, showSubject: showSubject,
padding: tilePadding, padding: tilePadding,
), ),
view: CardHandle(child: ExamView(exam)),
); );
// return Viewable(
// tile: ExamTile(
// exam,
// showSubject: showSubject,
// padding: tilePadding,
// ),
// view: CardHandle(child: ExamView(exam)),
// );
} }
} }
@ -98,7 +105,9 @@ class ExamPopup extends StatelessWidget {
Stack( Stack(
children: [ children: [
SvgPicture.asset( SvgPicture.asset(
"assets/svg/mesh_bg.svg", // "assets/svg/mesh_bg.svg",
SubjectBooklet.resolveVariant(
context: context, subject: exam.subject),
// ignore: deprecated_member_use // ignore: deprecated_member_use
color: ColorsUtils() color: ColorsUtils()
.fade(context, Theme.of(context).colorScheme.secondary, .fade(context, Theme.of(context).colorScheme.secondary,
@ -210,13 +219,19 @@ class ExamPopup extends StatelessWidget {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( SizedBox(
exam.description.capital(), width: MediaQuery.of(context).size.width * 0.7,
style: TextStyle( child: Text(
color: exam.description.capital(),
AppColors.of(context).text.withOpacity(0.9), style: TextStyle(
fontSize: 16.0, color: AppColors.of(context)
fontWeight: FontWeight.w600, .text
.withOpacity(0.9),
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
maxLines: 3,
overflow: TextOverflow.ellipsis,
), ),
), ),
Text( Text(
@ -288,7 +303,7 @@ class ExamPopup extends StatelessWidget {
], ],
), ),
Text( Text(
'${DateFormat('H:mm').format(lesson!.start)} - ${DateFormat('H:mm').format(lesson!.end)}', '${DateFormat('MMM d, H:mm', I18n.locale.countryCode).format(lesson!.start).capital()} - ${DateFormat('H:mm').format(lesson!.end)}',
style: TextStyle( style: TextStyle(
color: color:
AppColors.of(context).text.withOpacity(0.85), AppColors.of(context).text.withOpacity(0.85),

View File

@ -12,6 +12,7 @@ extension Localization on String {
"l_desc": "Description...", "l_desc": "Description...",
"done": "Done", "done": "Done",
"cancel": "Cancel", "cancel": "Cancel",
"year_index": "Lesson Number",
}, },
"hu_hu": { "hu_hu": {
"Room": "Terem", "Room": "Terem",
@ -22,6 +23,7 @@ extension Localization on String {
"l_desc": "Leírás...", "l_desc": "Leírás...",
"done": "Kész", "done": "Kész",
"cancel": "Mégse", "cancel": "Mégse",
"year_index": "Éves óraszám",
}, },
"de_de": { "de_de": {
"Room": "Raum", "Room": "Raum",
@ -32,6 +34,7 @@ extension Localization on String {
"l_desc": "Beschreibung...", "l_desc": "Beschreibung...",
"done": "Erledigt", "done": "Erledigt",
"cancel": "Abbrechen", "cancel": "Abbrechen",
"year_index": "Ordinalzahl",
} }
}; };

View File

@ -1,3 +1,4 @@
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -8,11 +9,21 @@ import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/theme/colors/utils.dart'; import 'package:refilc/theme/colors/utils.dart';
import 'package:refilc/utils/format.dart'; import 'package:refilc/utils/format.dart';
import 'package:refilc_kreta_api/models/exam.dart';
import 'package:refilc_kreta_api/models/lesson.dart'; import 'package:refilc_kreta_api/models/lesson.dart';
import 'package:refilc_kreta_api/providers/exam_provider.dart';
import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart'; import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart';
import 'package:refilc_mobile_ui/common/panel/panel_button.dart';
import 'package:refilc_mobile_ui/common/round_border_icon.dart'; import 'package:refilc_mobile_ui/common/round_border_icon.dart';
import 'package:refilc/ui/widgets/lesson/lesson_tile.dart'; import 'package:refilc/ui/widgets/lesson/lesson_tile.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:refilc_mobile_ui/common/viewable.dart';
import 'package:refilc_mobile_ui/common/widgets/card_handle.dart';
import 'package:refilc_mobile_ui/common/widgets/lesson/lesson_view.dart';
import 'package:refilc_plus/models/premium_scopes.dart';
import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
import 'lesson_view.i18n.dart';
class LessonViewable extends StatefulWidget { class LessonViewable extends StatefulWidget {
const LessonViewable( const LessonViewable(
@ -59,174 +70,169 @@ class LessonViewableState extends State<LessonViewable> {
if (lsn.subject.id == '' || tile.lesson.isEmpty) return tile; if (lsn.subject.id == '' || tile.lesson.isEmpty) return tile;
return GestureDetector( // check if new popup needed
onTap: () => TimetableLessonPopup.show( if (Provider.of<SettingsProvider>(context).newPopups) {
context: context, return GestureDetector(
lesson: lsn, onTap: () => TimetableLessonPopup.show(
), context: context,
child: LessonTile( lesson: lsn,
lsn, ),
swapDesc: widget.swapDesc, child: tile,
showSubTiles: widget.showSubTiles, );
// onTap: () => TimetableLessonPopup.show( }
// context: context,
// lesson: lsn, return Viewable(
// ), tile: tile,
), view: CardHandle(child: LessonView(lsn)),
actions: [
PanelButton(
background: true,
title: Text(
"edit_lesson".i18n,
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop();
if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.timetableNotes)) {
PlusLockedFeaturePopup.show(
context: context, feature: PremiumFeature.timetableNotes);
return;
}
showDialog(
context: context,
builder: (context) => StatefulBuilder(builder: (context, setS) {
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(14.0))),
title: Text("edit_lesson".i18n),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
// description
TextField(
controller: _descTxt,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: const BorderSide(
color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
contentPadding:
const EdgeInsets.symmetric(horizontal: 12.0),
hintText: 'l_desc'.i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
size: 18.0,
),
onPressed: () {
setState(() {
_descTxt.text = '';
});
},
),
),
),
// const SizedBox(
// height: 14.0,
// ),
// // class
// TextField(
// controller: _descTxt,
// onEditingComplete: () async {
// // SharedTheme? theme = await shareProvider.getThemeById(
// // context,
// // id: _paintId.text.replaceAll(' ', ''),
// // );
// // if (theme != null) {
// // // set theme variable
// // newThemeByID = theme;
// // _paintId.clear();
// // } else {
// // ScaffoldMessenger.of(context).showSnackBar(
// // CustomSnackBar(
// // content: Text("theme_not_found".i18n,
// // style: const TextStyle(color: Colors.white)),
// // backgroundColor: AppColors.of(context).red,
// // context: context,
// // ),
// // );
// // }
// },
// decoration: InputDecoration(
// border: OutlineInputBorder(
// borderSide: const BorderSide(
// color: Colors.grey, width: 1.5),
// borderRadius: BorderRadius.circular(12.0),
// ),
// focusedBorder: OutlineInputBorder(
// borderSide: const BorderSide(
// color: Colors.grey, width: 1.5),
// borderRadius: BorderRadius.circular(12.0),
// ),
// contentPadding:
// const EdgeInsets.symmetric(horizontal: 12.0),
// hintText: 'l_desc'.i18n,
// suffixIcon: IconButton(
// icon: const Icon(
// FeatherIcons.x,
// color: Colors.grey,
// size: 18.0,
// ),
// onPressed: () {
// setState(() {
// _descTxt.text = '';
// });
// },
// ),
// ),
// ),
],
),
actions: [
TextButton(
child: Text(
"cancel".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () {
Navigator.of(context).maybePop();
},
),
TextButton(
child: Text(
"done".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () async {
saveLesson();
Navigator.of(context).pop();
setState(() {});
},
),
],
);
}),
);
},
),
],
); );
// return Viewable(
// tile: tile,
// view: CardHandle(child: LessonView(lsn)),
// actions: [
// PanelButton(
// background: true,
// title: Text(
// "edit_lesson".i18n,
// textAlign: TextAlign.center,
// maxLines: 2,
// overflow: TextOverflow.ellipsis,
// ),
// onPressed: () {
// Navigator.of(context, rootNavigator: true).pop();
// if (!Provider.of<PlusProvider>(context, listen: false)
// .hasScope(PremiumScopes.timetableNotes)) {
// PlusLockedFeaturePopup.show(
// context: context, feature: PremiumFeature.timetableNotes);
// return;
// }
// showDialog(
// context: context,
// builder: (context) => StatefulBuilder(builder: (context, setS) {
// return AlertDialog(
// shape: const RoundedRectangleBorder(
// borderRadius: BorderRadius.all(Radius.circular(14.0))),
// title: Text("edit_lesson".i18n),
// content: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// // description
// TextField(
// controller: _descTxt,
// decoration: InputDecoration(
// border: OutlineInputBorder(
// borderSide: const BorderSide(
// color: Colors.grey, width: 1.5),
// borderRadius: BorderRadius.circular(12.0),
// ),
// focusedBorder: OutlineInputBorder(
// borderSide: const BorderSide(
// color: Colors.grey, width: 1.5),
// borderRadius: BorderRadius.circular(12.0),
// ),
// contentPadding:
// const EdgeInsets.symmetric(horizontal: 12.0),
// hintText: 'l_desc'.i18n,
// suffixIcon: IconButton(
// icon: const Icon(
// FeatherIcons.x,
// color: Colors.grey,
// size: 18.0,
// ),
// onPressed: () {
// setState(() {
// _descTxt.text = '';
// });
// },
// ),
// ),
// ),
// // const SizedBox(
// // height: 14.0,
// // ),
// // // class
// // TextField(
// // controller: _descTxt,
// // onEditingComplete: () async {
// // // SharedTheme? theme = await shareProvider.getThemeById(
// // // context,
// // // id: _paintId.text.replaceAll(' ', ''),
// // // );
// // // if (theme != null) {
// // // // set theme variable
// // // newThemeByID = theme;
// // // _paintId.clear();
// // // } else {
// // // ScaffoldMessenger.of(context).showSnackBar(
// // // CustomSnackBar(
// // // content: Text("theme_not_found".i18n,
// // // style: const TextStyle(color: Colors.white)),
// // // backgroundColor: AppColors.of(context).red,
// // // context: context,
// // // ),
// // // );
// // // }
// // },
// // decoration: InputDecoration(
// // border: OutlineInputBorder(
// // borderSide: const BorderSide(
// // color: Colors.grey, width: 1.5),
// // borderRadius: BorderRadius.circular(12.0),
// // ),
// // focusedBorder: OutlineInputBorder(
// // borderSide: const BorderSide(
// // color: Colors.grey, width: 1.5),
// // borderRadius: BorderRadius.circular(12.0),
// // ),
// // contentPadding:
// // const EdgeInsets.symmetric(horizontal: 12.0),
// // hintText: 'l_desc'.i18n,
// // suffixIcon: IconButton(
// // icon: const Icon(
// // FeatherIcons.x,
// // color: Colors.grey,
// // size: 18.0,
// // ),
// // onPressed: () {
// // setState(() {
// // _descTxt.text = '';
// // });
// // },
// // ),
// // ),
// // ),
// ],
// ),
// actions: [
// TextButton(
// child: Text(
// "cancel".i18n,
// style: const TextStyle(fontWeight: FontWeight.w500),
// ),
// onPressed: () {
// Navigator.of(context).maybePop();
// },
// ),
// TextButton(
// child: Text(
// "done".i18n,
// style: const TextStyle(fontWeight: FontWeight.w500),
// ),
// onPressed: () async {
// saveLesson();
// Navigator.of(context).pop();
// setState(() {});
// },
// ),
// ],
// );
// }),
// );
// },
// ),
// ],
// );
} }
void saveLesson() async { void saveLesson() async {
@ -283,6 +289,18 @@ class TimetableLessonPopup extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Exam? lessonExam;
if (lesson.exam != "") {
Exam exam = Provider.of<ExamProvider>(context, listen: false)
.exams
.firstWhere((t) => t.id == lesson.exam,
orElse: () => Exam.fromJson({}));
if (exam.id != "") {
lessonExam = exam;
}
}
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
@ -295,7 +313,9 @@ class TimetableLessonPopup extends StatelessWidget {
Stack( Stack(
children: [ children: [
SvgPicture.asset( SvgPicture.asset(
"assets/svg/mesh_bg.svg", // "assets/svg/mesh_bg.svg",
SubjectBooklet.resolveVariant(
context: context, subject: lesson.subject),
// ignore: deprecated_member_use // ignore: deprecated_member_use
color: ColorsUtils() color: ColorsUtils()
.fade(context, Theme.of(context).colorScheme.secondary, .fade(context, Theme.of(context).colorScheme.secondary,
@ -319,13 +339,13 @@ class TimetableLessonPopup extends StatelessWidget {
.withOpacity(0.1), .withOpacity(0.1),
Theme.of(context).scaffoldBackgroundColor, Theme.of(context).scaffoldBackgroundColor,
], ],
stops: const [0.1, 0.5, 0.7, 1.0], stops: const [0.0, 0.3, 0.6, 0.95],
begin: Alignment.topCenter, begin: Alignment.topCenter,
end: Alignment.bottomCenter, end: Alignment.bottomCenter,
), ),
), ),
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
height: 175.0, height: 200.0,
), ),
], ],
), ),
@ -340,16 +360,27 @@ class TimetableLessonPopup extends StatelessWidget {
width: 40, width: 40,
height: 4, height: 4,
decoration: BoxDecoration( decoration: BoxDecoration(
color: ColorsUtils() color: Theme.of(context).scaffoldBackgroundColor,
.fade(
context, Theme.of(context).colorScheme.secondary,
darkenAmount: 0.1, lightenAmount: 0.1)
.withOpacity(0.33),
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
2.0, 2.0,
), ),
), ),
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: ColorsUtils()
.fade(context,
Theme.of(context).colorScheme.secondary,
darkenAmount: 0.1, lightenAmount: 0.1)
.withOpacity(0.33),
borderRadius: BorderRadius.circular(
2.0,
),
),
),
), ),
const SizedBox( const SizedBox(
height: 38.0, height: 38.0,
), ),
@ -387,11 +418,9 @@ class TimetableLessonPopup extends StatelessWidget {
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.background,
borderRadius: BorderRadius.vertical( borderRadius: const BorderRadius.vertical(
top: const Radius.circular(12.0), top: Radius.circular(12.0),
bottom: (lesson.description.replaceAll(' ', '') != '') bottom: Radius.circular(6.0),
? const Radius.circular(6.0)
: const Radius.circular(12.0),
), ),
), ),
padding: const EdgeInsets.all(14.0), padding: const EdgeInsets.all(14.0),
@ -466,7 +495,15 @@ class TimetableLessonPopup extends StatelessWidget {
height: 8.0, height: 8.0,
), ),
Text( Text(
lesson.teacher.name, ((lesson.substituteTeacher == null ||
lesson.substituteTeacher!.name == "")
? (lesson.teacher.isRenamed
? lesson.teacher.renamedTo
: lesson.teacher.name)
: (lesson.substituteTeacher!.isRenamed
? lesson.substituteTeacher!.renamedTo
: lesson.substituteTeacher!.name)) ??
'',
style: TextStyle( style: TextStyle(
color: AppColors.of(context).text.withOpacity(0.9), color: AppColors.of(context).text.withOpacity(0.9),
fontSize: 14.0, fontSize: 14.0,
@ -487,7 +524,7 @@ class TimetableLessonPopup extends StatelessWidget {
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.background,
borderRadius: const BorderRadius.vertical( borderRadius: const BorderRadius.vertical(
top: Radius.circular(6.0), top: Radius.circular(6.0),
bottom: Radius.circular(12.0), bottom: Radius.circular(6.0),
), ),
), ),
padding: const EdgeInsets.all(14.0), padding: const EdgeInsets.all(14.0),
@ -506,6 +543,94 @@ class TimetableLessonPopup extends StatelessWidget {
], ],
), ),
), ),
const SizedBox(
height: 6.0,
),
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
borderRadius: BorderRadius.vertical(
top: const Radius.circular(6.0),
bottom: lesson.exam != ''
? const Radius.circular(6.0)
: const Radius.circular(12.0),
),
),
padding: const EdgeInsets.all(14.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${'year_index'.i18n}: ${lesson.lessonYearIndex ?? '?'}',
style: TextStyle(
color: AppColors.of(context).text.withOpacity(0.9),
fontSize: 14.0,
fontWeight: FontWeight.w600,
),
),
],
),
),
if (lesson.exam != '')
const SizedBox(
height: 6.0,
),
if (lesson.exam != '' && lessonExam != null)
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(6.0),
bottom: Radius.circular(12.0)),
),
padding: const EdgeInsets.all(14.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
const Icon(
FeatherIcons.file,
size: 20.0,
),
const SizedBox(
width: 10.0,
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
child: Text(
lessonExam.description.capital(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: AppColors.of(context)
.text
.withOpacity(0.9),
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
),
),
],
),
Flexible(
child: Text(
lessonExam.mode?.description ?? 'Dolgozat',
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: AppColors.of(context)
.text
.withOpacity(0.85),
fontSize: 14.0,
fontWeight: FontWeight.w500,
),
),
),
],
),
),
// const SizedBox( // const SizedBox(
// height: 24.0, // height: 24.0,
// ), // ),

View File

@ -4,7 +4,9 @@ import 'dart:math';
import 'package:animations/animations.dart'; import 'package:animations/animations.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:refilc/api/providers/update_provider.dart'; import 'package:refilc/api/providers/update_provider.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/utils.dart'; import 'package:refilc/theme/colors/utils.dart';
import 'package:refilc/ui/date_widget.dart'; import 'package:refilc/ui/date_widget.dart';
import 'package:refilc_kreta_api/models/absence.dart'; import 'package:refilc_kreta_api/models/absence.dart';
@ -169,6 +171,7 @@ class AbsencesPageState extends State<AbsencesPage>
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
), ),
), ),
), ),
@ -179,10 +182,22 @@ class AbsencesPageState extends State<AbsencesPage>
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Text( child: Text(
"Absences".i18n, "Absences".i18n,
style: TextStyle( style: Provider.of<SettingsProvider>(context).fontFamily !=
color: AppColors.of(context).text, '' &&
fontSize: 32.0, Provider.of<SettingsProvider>(context).titleOnlyFont
fontWeight: FontWeight.bold), ? GoogleFonts.getFont(
Provider.of<SettingsProvider>(context).fontFamily,
textStyle: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold,
),
)
: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold,
),
), ),
), ),
bottom: FilterBar( bottom: FilterBar(
@ -504,7 +519,9 @@ class AbsencesPageState extends State<AbsencesPage>
style: TextStyle( style: TextStyle(
fontSize: 18.0, fontSize: 18.0,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
color: AppColors.of(context).green, color: value1 > 0
? AppColors.of(context).green
: AppColors.of(context).text,
), ),
), ),
Text( Text(
@ -513,12 +530,14 @@ class AbsencesPageState extends State<AbsencesPage>
fontSize: 16.0, fontSize: 16.0,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
height: 1.1, height: 1.1,
color: ColorsUtils().fade( color: value1 > 0
context, ? ColorsUtils().fade(
AppColors.of(context).green, context,
darkenAmount: 0.5, AppColors.of(context).green,
lightenAmount: 0.4, darkenAmount: 0.5,
), lightenAmount: 0.4,
)
: AppColors.of(context).text,
), ),
), ),
], ],
@ -535,7 +554,9 @@ class AbsencesPageState extends State<AbsencesPage>
style: TextStyle( style: TextStyle(
fontSize: 18.0, fontSize: 18.0,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
color: AppColors.of(context).red, color: value2 > 0
? AppColors.of(context).red
: AppColors.of(context).text,
), ),
), ),
Text( Text(
@ -544,12 +565,14 @@ class AbsencesPageState extends State<AbsencesPage>
fontSize: 16.0, fontSize: 16.0,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
height: 1.1, height: 1.1,
color: ColorsUtils().fade( color: value2 > 0
context, ? ColorsUtils().fade(
AppColors.of(context).red, context,
darkenAmount: 0.4, AppColors.of(context).red,
lightenAmount: 0.2, darkenAmount: 0.4,
), lightenAmount: 0.2,
)
: AppColors.of(context).text,
), ),
), ),
], ],
@ -597,8 +620,9 @@ class AbsencesPageState extends State<AbsencesPage>
children: [ children: [
Row( Row(
children: [ children: [
const Icon( Icon(
Icons.av_timer_rounded, Icons.av_timer_rounded,
color: value3 > 0 ? Colors.orange : null,
), ),
const SizedBox( const SizedBox(
width: 10.0, width: 10.0,

View File

@ -34,7 +34,6 @@ import 'package:refilc_mobile_ui/pages/grades/calculator/grade_calculator_provid
import 'package:refilc_mobile_ui/pages/grades/grades_count.dart'; import 'package:refilc_mobile_ui/pages/grades/grades_count.dart';
import 'package:refilc_mobile_ui/pages/grades/graph.dart'; import 'package:refilc_mobile_ui/pages/grades/graph.dart';
import 'package:refilc_mobile_ui/pages/grades/subject_grades_container.dart'; import 'package:refilc_mobile_ui/pages/grades/subject_grades_container.dart';
import 'package:refilc_plus/ui/mobile/goal_planner/goal_planner_screen.dart';
// import 'package:refilc_plus/models/premium_scopes.dart'; // import 'package:refilc_plus/models/premium_scopes.dart';
// import 'package:refilc_plus/providers/plus_provider.dart'; // import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/goal_planner/goal_state_screen.dart'; import 'package:refilc_plus/ui/mobile/goal_planner/goal_state_screen.dart';
@ -44,6 +43,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:refilc_plus/ui/mobile/goal_planner/goal_track_popup.dart';
import 'grades_page.i18n.dart'; import 'grades_page.i18n.dart';
// import 'package:refilc_plus/ui/mobile/goal_planner/new_goal.dart'; // import 'package:refilc_plus/ui/mobile/goal_planner/new_goal.dart';
@ -425,9 +425,10 @@ class _GradeSubjectViewState extends State<GradeSubjectView>
// ScaffoldMessenger.of(context).showSnackBar( // ScaffoldMessenger.of(context).showSnackBar(
// const SnackBar(content: Text("Hamarosan..."))); // const SnackBar(content: Text("Hamarosan...")));
Navigator.of(context).push(CupertinoPageRoute( // Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => // builder: (context) =>
GoalPlannerScreen(subject: widget.subject))); // GoalPlannerScreen(subject: widget.subject)));
GoalTrackPopup.show(context, subject: widget.subject);
}, },
child: const Icon(FeatherIcons.flag, size: 20.0), child: const Icon(FeatherIcons.flag, size: 20.0),
), ),

View File

@ -4,6 +4,7 @@ import 'dart:math';
import 'package:auto_size_text/auto_size_text.dart'; import 'package:auto_size_text/auto_size_text.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:refilc/api/providers/update_provider.dart'; import 'package:refilc/api/providers/update_provider.dart';
import 'package:refilc/models/settings.dart'; import 'package:refilc/models/settings.dart';
import 'package:refilc/ui/widgets/grade/grade_tile.dart'; import 'package:refilc/ui/widgets/grade/grade_tile.dart';
@ -267,6 +268,12 @@ class GradesPageState extends State<GradesPage> {
), ),
), ),
), ),
if (hasHomework &&
nearestExam != null &&
Provider.of<SettingsProvider>(context).qSubjectsSubTiles)
const SizedBox(
height: 6.0,
),
if (nearestExam != null && if (nearestExam != null &&
Provider.of<SettingsProvider>(context).qSubjectsSubTiles) Provider.of<SettingsProvider>(context).qSubjectsSubTiles)
Container( Container(
@ -560,6 +567,7 @@ class GradesPageState extends State<GradesPage> {
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
), ),
), ),
), ),
@ -568,11 +576,21 @@ class GradesPageState extends State<GradesPage> {
title: Padding( title: Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Text( child: Text(
"Grades".i18n, "page_title_grades".i18n,
style: TextStyle( style: Provider.of<SettingsProvider>(context).fontFamily !=
color: AppColors.of(context).text, '' &&
fontSize: 32.0, Provider.of<SettingsProvider>(context).titleOnlyFont
fontWeight: FontWeight.bold), ? GoogleFonts.getFont(
Provider.of<SettingsProvider>(context).fontFamily,
textStyle: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold),
)
: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold),
), ),
), ),
shadowColor: Theme.of(context).shadowColor, shadowColor: Theme.of(context).shadowColor,
@ -667,6 +685,8 @@ class GradesPageState extends State<GradesPage> {
// SoonAlert.show(context: context); // SoonAlert.show(context: context);
gradeCalcTotal(context); gradeCalcTotal(context);
Navigator.of(context, rootNavigator: true).pop();
}, },
), ),
), ),

View File

@ -31,7 +31,8 @@ extension Localization on String {
"grade_calc": "Grade Calculator", "grade_calc": "Grade Calculator",
}, },
"hu_hu": { "hu_hu": {
"Grades": "Tantárgyak", "Grades": "Jegyek",
"page_title_grades": "Tantárgyak",
"Ghost Grades": "Szellem jegyek", "Ghost Grades": "Szellem jegyek",
"Subjects": "Tantárgyaid", "Subjects": "Tantárgyaid",
"Subjects_changes": "Tantárgyi változások", "Subjects_changes": "Tantárgyi változások",

View File

@ -248,11 +248,12 @@ class GradeGraphState extends State<GradeGraph> {
), ),
if (ghostData.isNotEmpty && ghostSpots.isNotEmpty) if (ghostData.isNotEmpty && ghostSpots.isNotEmpty)
LineChartBarData( LineChartBarData(
preventCurveOverShooting: true, preventCurveOverShooting: false,
spots: ghostSpots, spots: ghostSpots,
isCurved: true, isCurved: true,
colors: [AppColors.of(context).text], colors: [AppColors.of(context).text],
barWidth: 8, barWidth: 6,
curveSmoothness: 0.2,
isStrokeCapRound: true, isStrokeCapRound: true,
dotData: FlDotData(show: false), dotData: FlDotData(show: false),
belowBarData: BarAreaData( belowBarData: BarAreaData(

View File

@ -3,6 +3,7 @@ import 'dart:math';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:refilc/api/providers/live_card_provider.dart'; import 'package:refilc/api/providers/live_card_provider.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/ui/date_widget.dart'; import 'package:refilc/ui/date_widget.dart';
@ -244,14 +245,34 @@ class HomePageState extends State<HomePage> with TickerProviderStateMixin {
greeting, greeting,
overflow: TextOverflow.fade, overflow: TextOverflow.fade,
textAlign: TextAlign.start, textAlign: TextAlign.start,
style: TextStyle( style:
fontWeight: FontWeight.bold, Provider.of<SettingsProvider>(context)
fontSize: 18.0, .fontFamily !=
color: Theme.of(context) '' &&
.textTheme Provider.of<SettingsProvider>(
.bodyMedium context)
?.color, .titleOnlyFont
), ? GoogleFonts.getFont(
Provider.of<SettingsProvider>(
context)
.fontFamily,
textStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Theme.of(context)
.textTheme
.bodyMedium
?.color,
),
)
: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Theme.of(context)
.textTheme
.bodyMedium
?.color,
),
), ),
Text( Text(
DateFormat('EEEE, MMM d', DateFormat('EEEE, MMM d',
@ -317,6 +338,7 @@ class HomePageState extends State<HomePage> with TickerProviderStateMixin {
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
), ),
), ),
), ),
@ -355,7 +377,7 @@ class HomePageState extends State<HomePage> with TickerProviderStateMixin {
LiveCardState.duringLesson || LiveCardState.duringLesson ||
_liveCard.currentState == _liveCard.currentState ==
LiveCardState.duringBreak) LiveCardState.duringBreak)
? 55.0 ? 62.0
: 52.0), : 52.0),
), ),
child: Transform.scale( child: Transform.scale(

View File

@ -404,7 +404,7 @@ class LiveCardStateA extends State<LiveCard> {
swapRoom: true, swapRoom: true,
currentLessonIndicator: false, currentLessonIndicator: false,
padding: padding:
const EdgeInsets.only(top: 6.0, bottom: 4.0), const EdgeInsets.only(top: 2.0, bottom: 4.0),
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
showSubTiles: false, showSubTiles: false,
), ),
@ -911,6 +911,37 @@ class LiveCardStateA extends State<LiveCard> {
Row( Row(
children: liveCard.nextLesson != null children: liveCard.nextLesson != null
? [ ? [
Container(
width: (liveCard.nextLesson?.room
.length ??
0) >
20
? 111
: null,
padding: const EdgeInsets.symmetric(
horizontal: 5.5, vertical: 3.0),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.tertiary
.withOpacity(.15),
borderRadius:
BorderRadius.circular(10.0),
),
child: Text(
liveCard.nextLesson!.room,
overflow: TextOverflow.ellipsis,
style: TextStyle(
height: 1.1,
fontSize: 12.0,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.9),
),
),
),
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),

View File

@ -1,6 +1,8 @@
import 'dart:math'; import 'dart:math';
import 'package:google_fonts/google_fonts.dart';
import 'package:refilc/api/providers/update_provider.dart'; import 'package:refilc/api/providers/update_provider.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc/ui/date_widget.dart'; import 'package:refilc/ui/date_widget.dart';
import 'package:refilc_kreta_api/providers/message_provider.dart'; import 'package:refilc_kreta_api/providers/message_provider.dart';
import 'package:refilc/api/providers/user_provider.dart'; import 'package:refilc/api/providers/user_provider.dart';
@ -109,6 +111,7 @@ class MessagesPageState extends State<MessagesPage>
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
), ),
), ),
), ),
@ -128,10 +131,22 @@ class MessagesPageState extends State<MessagesPage>
), ),
Text( Text(
"Messages".i18n, "Messages".i18n,
style: TextStyle( style: Provider.of<SettingsProvider>(context)
color: AppColors.of(context).text, .fontFamily !=
fontSize: 32.0, '' &&
fontWeight: FontWeight.bold), Provider.of<SettingsProvider>(context)
.titleOnlyFont
? GoogleFonts.getFont(
Provider.of<SettingsProvider>(context).fontFamily,
textStyle: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold),
)
: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold),
), ),
], ],
), ),

View File

@ -5,6 +5,7 @@ import 'dart:math';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:refilc/api/providers/database_provider.dart'; import 'package:refilc/api/providers/database_provider.dart';
import 'package:refilc/api/providers/self_note_provider.dart'; import 'package:refilc/api/providers/self_note_provider.dart';
import 'package:refilc/api/providers/update_provider.dart'; import 'package:refilc/api/providers/update_provider.dart';
@ -35,6 +36,7 @@ import 'package:refilc_plus/models/premium_scopes.dart';
import 'package:refilc_plus/providers/plus_provider.dart'; import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/plus/premium_inline.dart'; import 'package:refilc_plus/ui/mobile/plus/premium_inline.dart';
import 'package:refilc_plus/ui/mobile/plus/upsell.dart'; import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
import 'package:uuid/uuid.dart';
import 'notes_page.i18n.dart'; import 'notes_page.i18n.dart';
enum AbsenceFilter { absences, delays, misses } enum AbsenceFilter { absences, delays, misses }
@ -65,9 +67,14 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
Map<String, bool> doneItems = {}; Map<String, bool> doneItems = {};
List<Widget> noteTiles = []; List<Widget> noteTiles = [];
List<TodoItem> todoItems = [];
final TextEditingController _taskName = TextEditingController();
final TextEditingController _taskContent = TextEditingController();
void generateTiles() async { void generateTiles() async {
doneItems = await databaseProvider.userQuery.toDoItems(userId: user.id!); doneItems = await databaseProvider.userQuery.toDoItems(userId: user.id!);
todoItems = await databaseProvider.userQuery.getTodoItems(userId: user.id!);
List<Widget> tiles = []; List<Widget> tiles = [];
@ -82,7 +89,7 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
List<Widget> toDoTiles = []; List<Widget> toDoTiles = [];
if (hw.isNotEmpty && if (hw.isNotEmpty &&
!Provider.of<PlusProvider>(context, listen: false) Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.unlimitedSelfNotes)) { .hasScope(PremiumScopes.unlimitedSelfNotes)) {
toDoTiles.addAll(hw.map((e) => TickTile( toDoTiles.addAll(hw.map((e) => TickTile(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
@ -102,6 +109,21 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
))); )));
} }
if (selfNoteProvider.todos.isNotEmpty) {
toDoTiles.addAll(selfNoteProvider.todos.map((e) => TickTile(
padding: EdgeInsets.zero,
title: e.title,
description: e.content,
isTicked: e.done,
onTap: (p0) async {
todoItems.firstWhere((element) => element.id == e.id).done = p0;
await databaseProvider.userStore
.storeSelfTodoItems(todoItems, userId: user.id!);
},
)));
}
if (toDoTiles.isNotEmpty) { if (toDoTiles.isNotEmpty) {
tiles.add(const SizedBox( tiles.add(const SizedBox(
height: 10.0, height: 10.0,
@ -128,26 +150,31 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
CupertinoPageRoute( CupertinoPageRoute(
builder: (context) => NoteViewScreen(note: e))), builder: (context) => NoteViewScreen(note: e))),
) )
: Container( : GestureDetector(
height: MediaQuery.of(context).size.width / 2.42, onTap: () => Navigator.of(context, rootNavigator: true).push(
width: MediaQuery.of(context).size.width / 2.42, CupertinoPageRoute(
decoration: BoxDecoration( builder: (context) => NoteViewScreen(note: e))),
boxShadow: [ child: Container(
if (Provider.of<SettingsProvider>(context, listen: false) height: MediaQuery.of(context).size.width / 2.42,
.shadowEffect) width: MediaQuery.of(context).size.width / 2.42,
BoxShadow( decoration: BoxDecoration(
offset: const Offset(0, 21), boxShadow: [
blurRadius: 23.0, if (Provider.of<SettingsProvider>(context, listen: false)
color: Theme.of(context).shadowColor, .shadowEffect)
), BoxShadow(
], offset: const Offset(0, 21),
), blurRadius: 23.0,
child: ClipRRect( color: Theme.of(context).shadowColor,
borderRadius: BorderRadius.circular(16.0), ),
child: Image.memory( ],
const Base64Decoder().convert(e.content), ),
fit: BoxFit.cover, child: ClipRRect(
gaplessPlayback: true, borderRadius: BorderRadius.circular(16.0),
child: Image.memory(
const Base64Decoder().convert(e.content),
fit: BoxFit.cover,
gaplessPlayback: true,
),
), ),
), ),
), ),
@ -289,6 +316,7 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
), ),
), ),
), ),
@ -299,10 +327,20 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Text( child: Text(
"notes".i18n, "notes".i18n,
style: TextStyle( style: Provider.of<SettingsProvider>(context).fontFamily !=
color: AppColors.of(context).text, '' &&
fontSize: 32.0, Provider.of<SettingsProvider>(context).titleOnlyFont
fontWeight: FontWeight.bold), ? GoogleFonts.getFont(
Provider.of<SettingsProvider>(context).fontFamily,
textStyle: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold),
)
: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold),
), ),
), ),
), ),
@ -313,6 +351,8 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
.fetch( .fetch(
from: DateTime.now().subtract(const Duration(days: 30))); from: DateTime.now().subtract(const Duration(days: 30)));
Provider.of<SelfNoteProvider>(context, listen: false).restore(); Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false)
.restoreTodo();
generateTiles(); generateTiles();
@ -410,7 +450,159 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
}, },
), ),
), ),
const SizedBox(
height: 10.0,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Theme.of(context).colorScheme.background),
child: ListTile(
title: Row(
children: [
const Icon(Icons.task_outlined),
const SizedBox(
width: 10.0,
),
Text('new_task'.i18n),
],
),
onTap: () {
if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.unlimitedSelfNotes)) {
PlusLockedFeaturePopup.show(
context: context, feature: PremiumFeature.selfNotes);
return;
}
showTaskCreation(context);
},
),
),
]), ]),
); );
} }
void showTaskCreation(context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(14.0))),
contentPadding: const EdgeInsets.only(top: 10.0),
title: Text("new_task".i18n),
content: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 10.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: _taskName,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
focusedBorder: OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
hintText: "task_name".i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
),
onPressed: () {
setState(() {
_taskName.text = "";
});
},
),
),
),
const SizedBox(
height: 10.0,
),
TextField(
controller: _taskContent,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
focusedBorder: OutlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
hintText: "task_content".i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
),
onPressed: () {
setState(() {
_taskContent.text = "";
});
},
),
),
),
],
),
),
actions: [
TextButton(
child: Text(
"cancel".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () {
Navigator.of(context).maybePop();
},
),
TextButton(
child: Text(
"next".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () async {
todoItems.add(TodoItem.fromJson({
'id': const Uuid().v4(),
'title': _taskName.text.replaceAll(' ', '') != ""
? _taskName.text
: 'no_title'.i18n,
'content': _taskContent.text,
'done': false,
}));
await databaseProvider.userStore
.storeSelfTodoItems(todoItems, userId: user.id!);
setState(() {
_taskName.text = "";
_taskContent.text = "";
});
Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false)
.restoreTodo();
generateTiles();
Navigator.of(context).pop(true);
},
),
],
),
);
}
} }

View File

@ -14,6 +14,10 @@ extension ScreensLocalization on String {
"hint_t": "Note title...", "hint_t": "Note title...",
"your_notes": "Your Notes", "your_notes": "Your Notes",
"new_image": "New Image", "new_image": "New Image",
"no_title": "No title",
"task_content": "Task content...",
"task_name": "Task title...",
"new_task": "New Task",
}, },
"hu_hu": { "hu_hu": {
"notes": "Füzet", "notes": "Füzet",
@ -26,6 +30,10 @@ extension ScreensLocalization on String {
"hint_t": "Jegyzet címe...", "hint_t": "Jegyzet címe...",
"your_notes": "Jegyzeteid", "your_notes": "Jegyzeteid",
"new_image": "Új kép", "new_image": "Új kép",
"no_title": "Nincs cím",
"task_content": "Feladat tartalma...",
"task_name": "Feladat címe...",
"new_task": "Új feladat",
}, },
"de_de": { "de_de": {
"notes": "Broschüre", "notes": "Broschüre",
@ -38,6 +46,10 @@ extension ScreensLocalization on String {
"hint_t": "Titel notieren...", "hint_t": "Titel notieren...",
"your_notes": "Deine Noten", "your_notes": "Deine Noten",
"new_image": "Neues Bild", "new_image": "Neues Bild",
"no_title": "Kein Titel",
"task_content": "Aufgabeninhalt...",
"task_name": "Aufgabentitel...",
"new_task": "Neue Aufgabe",
}, },
}; };

View File

@ -257,6 +257,8 @@ class AddNoteScreenState extends State<AddNoteScreen> {
style: const TextStyle(fontSize: 16.0), style: const TextStyle(fontSize: 16.0),
), ),
), ),
if (MediaQuery.of(context).viewInsets.bottom != 0)
const SizedBox(height: 60),
], ],
), ),
), ),

View File

@ -6,6 +6,7 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:image_crop/image_crop.dart'; import 'package:image_crop/image_crop.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -27,6 +28,8 @@ class ImageNoteEditor extends StatefulWidget {
} }
class _ImageNoteEditorState extends State<ImageNoteEditor> { class _ImageNoteEditorState extends State<ImageNoteEditor> {
final _title = TextEditingController();
final cropKey = GlobalKey<CropState>(); final cropKey = GlobalKey<CropState>();
File? _file; File? _file;
File? _sample; File? _sample;
@ -62,7 +65,7 @@ class _ImageNoteEditorState extends State<ImageNoteEditor> {
child: Crop.file( child: Crop.file(
_sample!, _sample!,
key: cropKey, key: cropKey,
aspectRatio: 1.0, // aspectRatio: 1.0,
), ),
); );
} }
@ -135,7 +138,8 @@ class _ImageNoteEditorState extends State<ImageNoteEditor> {
selfNotes.add(SelfNote.fromJson({ selfNotes.add(SelfNote.fromJson({
'id': const Uuid().v4(), 'id': const Uuid().v4(),
'content': base64Image, 'content': base64Image,
'note_type': 'image' 'note_type': 'image',
'title': _title.text,
})); }));
await Provider.of<DatabaseProvider>(context, listen: false) await Provider.of<DatabaseProvider>(context, listen: false)
@ -143,6 +147,7 @@ class _ImageNoteEditorState extends State<ImageNoteEditor> {
.storeSelfNotes(selfNotes, userId: widget.u.id); .storeSelfNotes(selfNotes, userId: widget.u.id);
Provider.of<SelfNoteProvider>(context, listen: false).restore(); Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false).restoreTodo();
debugPrint('$file'); debugPrint('$file');
} }
@ -170,6 +175,37 @@ class _ImageNoteEditorState extends State<ImageNoteEditor> {
const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
child: _sample == null ? openImageWidget() : cropImageWidget(), child: _sample == null ? openImageWidget() : cropImageWidget(),
), ),
Padding(
padding:
const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
child: TextField(
controller: _title,
onEditingComplete: () async {},
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
hintText: 'title'.i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
),
onPressed: () {
setState(() {
_title.text = '';
});
},
),
),
),
),
// if (widget.u.picture != "") // if (widget.u.picture != "")
// TextButton( // TextButton(
// child: Text( // child: Text(

View File

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:refilc/api/providers/self_note_provider.dart'; import 'package:refilc/api/providers/self_note_provider.dart';
import 'package:refilc/models/self_note.dart'; import 'package:refilc/models/self_note.dart';
@ -8,6 +10,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:markdown/markdown.dart' as md; import 'package:markdown/markdown.dart' as md;
import 'notes_screen.i18n.dart';
class NoteViewScreen extends StatefulWidget { class NoteViewScreen extends StatefulWidget {
const NoteViewScreen({super.key, required this.note}); const NoteViewScreen({super.key, required this.note});
@ -30,7 +33,9 @@ class NoteViewScreenState extends State<NoteViewScreen> {
surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, surfaceTintColor: Theme.of(context).scaffoldBackgroundColor,
leading: BackButton(color: AppColors.of(context).text), leading: BackButton(color: AppColors.of(context).text),
title: Text( title: Text(
widget.note.title ?? '${widget.note.content.split(' ')[0]}...', widget.note.noteType == NoteType.text
? (widget.note.title ?? '${widget.note.content.split(' ')[0]}...')
: 'image_note'.i18n,
style: TextStyle( style: TextStyle(
color: AppColors.of(context).text, color: AppColors.of(context).text,
fontSize: 26.0, fontSize: 26.0,
@ -38,52 +43,55 @@ class NoteViewScreenState extends State<NoteViewScreen> {
), ),
), ),
actions: [ actions: [
ClipRRect( if (widget.note.noteType == NoteType.text)
borderRadius: BorderRadius.circular(10.1), ClipRRect(
child: GestureDetector( borderRadius: BorderRadius.circular(10.1),
onTap: () { child: GestureDetector(
// handle tap onTap: () {
Navigator.of(context, rootNavigator: true).push( // handle tap
CupertinoPageRoute( Navigator.of(context, rootNavigator: true).push(
builder: (context) => CupertinoPageRoute(
AddNoteScreen(initialNote: widget.note))); builder: (context) =>
}, AddNoteScreen(initialNote: widget.note)));
child: Container( },
color: Theme.of(context).colorScheme.secondary.withOpacity(0.2), child: Container(
child: Padding( color:
padding: const EdgeInsets.all(8.0), Theme.of(context).colorScheme.secondary.withOpacity(0.2),
child: Stack( child: Padding(
children: [ padding: const EdgeInsets.all(8.0),
IconTheme( child: Stack(
data: IconThemeData( children: [
color: Theme.of(context).colorScheme.secondary, IconTheme(
data: IconThemeData(
color: Theme.of(context).colorScheme.secondary,
),
child: const Icon(
FeatherIcons.edit,
size: 20.0,
),
), ),
child: const Icon( IconTheme(
FeatherIcons.edit, data: IconThemeData(
size: 20.0, color:
Theme.of(context).brightness == Brightness.light
? Colors.black.withOpacity(.5)
: Colors.white.withOpacity(.3),
),
child: const Icon(
FeatherIcons.edit,
size: 20.0,
),
), ),
), ],
IconTheme( ),
data: IconThemeData(
color:
Theme.of(context).brightness == Brightness.light
? Colors.black.withOpacity(.5)
: Colors.white.withOpacity(.3),
),
child: const Icon(
FeatherIcons.edit,
size: 20.0,
),
),
],
), ),
), ),
), ),
), ),
), if (widget.note.noteType == NoteType.text)
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(10.1), borderRadius: BorderRadius.circular(10.1),
child: GestureDetector( child: GestureDetector(
@ -140,21 +148,30 @@ class NoteViewScreenState extends State<NoteViewScreen> {
child: Column( child: Column(
children: [ children: [
Expanded( Expanded(
child: MarkdownBody( child: widget.note.noteType == NoteType.text
data: widget.note.content, ? MarkdownBody(
extensionSet: md.ExtensionSet( data: widget.note.content,
md.ExtensionSet.gitHubFlavored.blockSyntaxes, extensionSet: md.ExtensionSet(
<md.InlineSyntax>[ md.ExtensionSet.gitHubFlavored.blockSyntaxes,
md.EmojiSyntax(), <md.InlineSyntax>[
...md.ExtensionSet.gitHubFlavored.inlineSyntaxes md.EmojiSyntax(),
], ...md.ExtensionSet.gitHubFlavored.inlineSyntaxes
), ],
styleSheet: MarkdownStyleSheet( ),
p: const TextStyle( styleSheet: MarkdownStyleSheet(
fontSize: 15.0, p: const TextStyle(
), fontSize: 15.0,
), ),
), ),
)
: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: Image.memory(
const Base64Decoder().convert(widget.note.content),
fit: BoxFit.contain,
gaplessPlayback: true,
),
),
), ),
// Expanded( // Expanded(
// child: Text( // child: Text(

View File

@ -268,6 +268,7 @@ class NotesScreenState extends State<NotesScreen> {
Provider.of<HomeworkProvider>(context, listen: false) Provider.of<HomeworkProvider>(context, listen: false)
.fetch(from: DateTime.now().subtract(const Duration(days: 30))); .fetch(from: DateTime.now().subtract(const Duration(days: 30)));
Provider.of<SelfNoteProvider>(context, listen: false).restore(); Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false).restoreTodo();
return Future(() => null); return Future(() => null);
}, },

View File

@ -18,6 +18,8 @@ extension SettingsLocalization on String {
"click_here": "Click here", "click_here": "Click here",
"select_image": "to select an image", "select_image": "to select an image",
"new_image": "New Image", "new_image": "New Image",
"image_note": "Image",
"title": "Image title...",
}, },
"hu_hu": { "hu_hu": {
"notes": "Füzet", "notes": "Füzet",
@ -34,6 +36,8 @@ extension SettingsLocalization on String {
"click_here": "Kattints ide", "click_here": "Kattints ide",
"select_image": "kép kiválasztásához", "select_image": "kép kiválasztásához",
"new_image": "Új kép", "new_image": "Új kép",
"image_note": "Kép",
"title": "Kép címe...",
}, },
"de_de": { "de_de": {
"notes": "Broschüre", "notes": "Broschüre",
@ -50,6 +54,8 @@ extension SettingsLocalization on String {
"click_here": "Klicken Sie hier", "click_here": "Klicken Sie hier",
"select_image": "um ein Bild auszuwählen", "select_image": "um ein Bild auszuwählen",
"new_image": "Neues Bild", "new_image": "Neues Bild",
"image_note": "Bild",
"title": "Bildtitel...",
}, },
}; };

View File

@ -1,3 +1,6 @@
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:refilc/utils/format.dart'; import 'package:refilc/utils/format.dart';
@ -50,11 +53,26 @@ class _DayTitleState extends State<DayTitle> {
width: MediaQuery.of(context).size.width / 1.5, width: MediaQuery.of(context).size.width / 1.5,
child: Text( child: Text(
widget.dayTitle(index).capital(), widget.dayTitle(index).capital(),
style: TextStyle( style: Provider.of<SettingsProvider>(context)
color: .fontFamily !=
AppColors.of(context).text.withOpacity(opacity), '' &&
fontSize: 32.0, Provider.of<SettingsProvider>(context)
fontWeight: FontWeight.bold), .titleOnlyFont
? GoogleFonts.getFont(
Provider.of<SettingsProvider>(context).fontFamily,
textStyle: TextStyle(
color: AppColors.of(context)
.text
.withOpacity(opacity),
fontSize: 32.0,
fontWeight: FontWeight.bold),
)
: TextStyle(
color: AppColors.of(context)
.text
.withOpacity(opacity),
fontSize: 32.0,
fontWeight: FontWeight.bold),
), ),
); );
}, },

View File

@ -1,5 +1,6 @@
import 'dart:math'; import 'dart:math';
import 'package:animations/animations.dart'; import 'package:animations/animations.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:i18n_extension/i18n_extension.dart'; import 'package:i18n_extension/i18n_extension.dart';
import 'package:refilc/api/providers/database_provider.dart'; import 'package:refilc/api/providers/database_provider.dart';
import 'package:refilc/api/providers/update_provider.dart'; import 'package:refilc/api/providers/update_provider.dart';
@ -19,7 +20,7 @@ import 'package:refilc_mobile_ui/common/empty.dart';
import 'package:refilc_mobile_ui/common/profile_image/profile_button.dart'; import 'package:refilc_mobile_ui/common/profile_image/profile_button.dart';
import 'package:refilc_mobile_ui/common/profile_image/profile_image.dart'; import 'package:refilc_mobile_ui/common/profile_image/profile_image.dart';
import 'package:refilc_mobile_ui/common/system_chrome.dart'; import 'package:refilc_mobile_ui/common/system_chrome.dart';
import 'package:refilc_mobile_ui/common/widgets/lesson/lesson_view.dart'; // import 'package:refilc_mobile_ui/common/widgets/lesson/lesson_view.dart';
import 'package:refilc_kreta_api/controllers/timetable_controller.dart'; import 'package:refilc_kreta_api/controllers/timetable_controller.dart';
import 'package:refilc_mobile_ui/common/widgets/lesson/lesson_viewable.dart'; import 'package:refilc_mobile_ui/common/widgets/lesson/lesson_viewable.dart';
import 'package:refilc_mobile_ui/pages/timetable/day_title.dart'; import 'package:refilc_mobile_ui/pages/timetable/day_title.dart';
@ -60,7 +61,11 @@ class TimetablePage extends StatefulWidget {
NavigationScreen.of(context)?.setPage("timetable"); NavigationScreen.of(context)?.setPage("timetable");
// Show initial Lesson // Show initial Lesson
if (lesson != null) LessonView.show(lesson, context: context); // if (lesson != null) LessonView.show(lesson, context: context);
// changed to new popup
if (lesson != null) {
TimetableLessonPopup.show(context: context, lesson: lesson);
}
} }
@override @override
@ -316,6 +321,7 @@ class TimetablePageState extends State<TimetablePage>
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
), ),
), ),
), ),
@ -374,11 +380,25 @@ class TimetablePageState extends State<TimetablePage>
} else { } else {
return Text( return Text(
"timetable".i18n, "timetable".i18n,
style: TextStyle( style: Provider.of<SettingsProvider>(context)
fontSize: 32.0, .fontFamily !=
fontWeight: FontWeight.bold, '' &&
color: AppColors.of(context).text, Provider.of<SettingsProvider>(context)
), .titleOnlyFont
? GoogleFonts.getFont(
Provider.of<SettingsProvider>(context)
.fontFamily,
textStyle: TextStyle(
fontSize: 32.0,
fontWeight: FontWeight.bold,
color: AppColors.of(context).text,
),
)
: TextStyle(
fontSize: 32.0,
fontWeight: FontWeight.bold,
color: AppColors.of(context).text,
),
); );
} }
}(), }(),

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc_plus/providers/plus_provider.dart'; import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/plus/activation_view/activation_view.dart'; import 'package:refilc_plus/ui/mobile/plus/activation_view/activation_view.dart';
import 'package:refilc_mobile_ui/plus/plus_screen.i18n.dart'; import 'package:refilc_mobile_ui/plus/plus_screen.i18n.dart';
@ -50,6 +51,20 @@ class PlusPlanCard extends StatelessWidget {
return; return;
} }
if (Provider.of<SettingsProvider>(context, listen: false).xFilcId ==
"none") {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text(
"Be kell kapcsolnod a Névtelen Analitikát a beállítások főoldalán, mielőtt reFilc+ előfizetést vásárolnál!",
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
backgroundColor: Colors.white,
));
return;
}
if (Provider.of<PlusProvider>(context, listen: false).hasPremium) { if (Provider.of<PlusProvider>(context, listen: false).hasPremium) {
if (!active) { if (!active) {
launchUrl( launchUrl(

View File

@ -225,6 +225,7 @@ class PlusScreenState extends State<PlusScreen> {
['🎓', 'rfp_6'.i18n], ['🎓', 'rfp_6'.i18n],
['👕', 'rfp_14'.i18n], ['👕', 'rfp_14'.i18n],
['👑', 'rfp_15'.i18n], ['👑', 'rfp_15'.i18n],
['📩', 'rfp_17'.i18n],
['🔜', 'more_soon'.i18n], ['🔜', 'more_soon'.i18n],
], ],
docsAccepted: docsAccepted, docsAccepted: docsAccepted,

View File

@ -45,6 +45,7 @@ extension SettingsLocalization on String {
"rfp_14": "Discount in reFilc Shop (soon)", "rfp_14": "Discount in reFilc Shop (soon)",
"rfp_15": "Subscriber role in our Discord community", "rfp_15": "Subscriber role in our Discord community",
"rfp_16": "Private leaks and informations about upcoming features", "rfp_16": "Private leaks and informations about upcoming features",
"rfp_17": "Grade exporting",
// other // other
"and": " and ", "and": " and ",
"every": "Every ", "every": "Every ",
@ -96,6 +97,7 @@ extension SettingsLocalization on String {
"rfp_14": "Kedvezmény a reFilc Shop-ban (hamarosan)", "rfp_14": "Kedvezmény a reFilc Shop-ban (hamarosan)",
"rfp_15": "Előfizetői rang a Discord szerverünkön", "rfp_15": "Előfizetői rang a Discord szerverünkön",
"rfp_16": "Privát betekintések és információk közelgő újításokról", "rfp_16": "Privát betekintések és információk közelgő újításokról",
"rfp_17": "Jegy exportálás",
// other // other
"and": " és ", "and": " és ",
"every": "Minden ", "every": "Minden ",
@ -133,30 +135,32 @@ extension SettingsLocalization on String {
"Der Preis wird in Euro angegeben im Bezug zum aktuellen Wechselkurs. 1 EUR ≈ 390 HUF", "Der Preis wird in Euro angegeben im Bezug zum aktuellen Wechselkurs. 1 EUR ≈ 390 HUF",
"active": "Aktiv", "active": "Aktiv",
// benefits // benefits
"rfp_1": "Előzetes hozzáférés új verziókhoz", "rfp_1": "Frühzeitiger Zugriff auf Updates",
"rfp_2": "2 fiók használata egyszerre", "rfp_2": "Verwendung von zwei Konten gleichzeitig",
"rfp_3": "Egyedi üdvözlő üzenet", "rfp_3": "Individuelle Begrüßungsnachricht",
"rfp_4": "Korlátlan saját jegyzet és feladat a füzet oldalon", "rfp_4":
"rfp_5": "Egyedi jegy ritkaságok", "Unbegrenzte eigene Notizen und Aufgaben auf der Notizbuchseite",
"rfp_6": "Összesített átlagszámoló", "rfp_5": "Individuelle Notenraritäten",
"rfp_7": "Órarend jegyzetek", "rfp_6": "Gesamtdurchschnittsberechner",
"rfp_8": "Egyedi betütípusok", "rfp_7": "Stundenplan-Notizen",
"rfp_9": "Korlátlan fiók használata egyszerre", "rfp_8": "Individuelle Schriftarten",
"rfp_10": "Alkalmazás ikonjának megváltoztatása (v5.1-től)", "rfp_9": "Unbegrenzte Konten",
"rfp_11": "Live Activity szín", "rfp_10": "Anpassung des App-Symbols (ab v5.1)",
"rfp_12": "Fejlettebb cél kitűzés", "rfp_11": "Änderung der Live-Aktivitätsfarbe",
"rfp_13": "Naptár szinkronizálás", "rfp_12": "Verbesserter Zielplaner",
"rfp_14": "Kedvezmény a reFilc Shop-ban (hamarosan)", "rfp_13": "Importieren Sie Ihren Stundenplan in Ihre Kalender-App",
"rfp_15": "Előfizetői rang a Discord szerverünkön", "rfp_14": "Rabatt im reFilc Shop (bald)",
"rfp_16": "Privát betekintések és információk közelgő újításokról", "rfp_15": "Abonnentenrolle in unserer Discord-Community",
"rfp_16": "Private Leaks und Informationen über kommende Funktionen",
"rfp_17": "Notenexport",
// other // other
"and": " és ", "and": " und ",
"every": "Minden ", "every": "Jeder ",
"benefit": " előny", "benefit": " Vorteil",
"show_lifetime": "Für immer Pakete", "show_lifetime": "Für immer Pakete",
"more_soon": "Mehr folgt bald...", "more_soon": "Mehr folgt bald...",
"faq_dc": "faq_dc":
"Az előnyök beváltásához írj nekünk Discord-on privát üzenetet!", "Um Ihre Vorteile einzulösen, schreiben Sie uns eine private Nachricht auf Discord!",
"reactivate": "Bestehendes Abonnement reaktivieren", "reactivate": "Bestehendes Abonnement reaktivieren",
}, },
}; };

View File

@ -0,0 +1,179 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:refilc_kreta_api/client/api.dart';
import 'package:refilc_kreta_api/client/client.dart';
import 'package:webview_flutter/webview_flutter.dart';
class KretenLoginScreen extends StatefulWidget {
const KretenLoginScreen({super.key});
@override
State<KretenLoginScreen> createState() => _KretenLoginScreenState();
}
class _KretenLoginScreenState extends State<KretenLoginScreen> {
late final WebViewController controller;
var loadingPercentage = 0;
var currentUrl = '';
@override
void initState() {
super.initState();
controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(NavigationDelegate(
onPageStarted: (url) async {
setState(() {
loadingPercentage = 0;
currentUrl = url;
});
List<String> requiredThings = url
.replaceAll(
'https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect?code=',
'')
.replaceAll(
'&scope=openid email offline_access kreta-ellenorzo-webapi.public kreta-eugyintezes-webapi.public kreta-fileservice-webapi.public kreta-mobile-global-webapi.public kreta-dkt-webapi.public kreta-ier-webapi.public&state=refilc_student_mobile&session_state=',
':')
.split(':');
String code = requiredThings[0];
// String sessionState = requiredThings[1];
debugPrint('url: $url');
// actual login (token grant) logic
Map<String, String> headers = {
"content-type": "application/x-www-form-urlencoded",
"accept": "*/*",
"user-agent":
"eKretaStudent/264745 CFNetwork/1494.0.7 Darwin/23.4.0",
"code_verifier": "THDUSddKOOndwCkqBtVHvRjh2LK0V2kMyLP2QirqVWQ",
};
Map? res = await Provider.of<KretaClient>(context, listen: false)
.postAPI(KretaAPI.login, headers: headers, body: {
"code": code,
"redirect_uri":
"https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect",
"client_id": "kreta-ellenorzo-student-mobile-ios",
"grant_type": "authorization_code",
});
if (res != null) {
print(res);
// if (res.containsKey("error")) {
// if (res["error"] == "invalid_grant") {
// print("ERROR: invalid_grant");
// return;
// }
// } else {
// if (res.containsKey("access_token")) {
// try {
// Provider.of<KretaClient>(context, listen: false).accessToken =
// res["access_token"];
// Map? studentJson =
// await Provider.of<KretaClient>(context, listen: false)
// .getAPI(KretaAPI.student(instituteCode));
// Student student = Student.fromJson(studentJson!);
// var user = User(
// username: username,
// password: password,
// instituteCode: instituteCode,
// name: student.name,
// student: student,
// role: JwtUtils.getRoleFromJWT(res["access_token"])!,
// );
// if (onLogin != null) onLogin(user);
// // Store User in the database
// await Provider.of<DatabaseProvider>(context, listen: false)
// .store
// .storeUser(user);
// Provider.of<UserProvider>(context, listen: false)
// .addUser(user);
// Provider.of<UserProvider>(context, listen: false)
// .setUser(user.id);
// // Get user data
// try {
// await Future.wait([
// Provider.of<GradeProvider>(context, listen: false)
// .fetch(),
// Provider.of<TimetableProvider>(context, listen: false)
// .fetch(week: Week.current()),
// Provider.of<ExamProvider>(context, listen: false).fetch(),
// Provider.of<HomeworkProvider>(context, listen: false)
// .fetch(),
// Provider.of<MessageProvider>(context, listen: false)
// .fetchAll(),
// Provider.of<MessageProvider>(context, listen: false)
// .fetchAllRecipients(),
// Provider.of<NoteProvider>(context, listen: false).fetch(),
// Provider.of<EventProvider>(context, listen: false)
// .fetch(),
// Provider.of<AbsenceProvider>(context, listen: false)
// .fetch(),
// ]);
// } catch (error) {
// print("WARNING: failed to fetch user data: $error");
// }
// if (onSuccess != null) onSuccess();
// return LoginState.success;
// } catch (error) {
// print("ERROR: loginAPI: $error");
// // maybe check debug mode
// // ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("ERROR: $error")));
// return LoginState.failed;
// }
// }
// }
}
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
))
..loadRequest(
Uri.parse(
'https://idp.e-kreta.hu/connect/authorize?prompt=login&nonce=refilc&response_type=code&code_challenge_method=S256&scope=openid%20email%20offline_access%20kreta-ellenorzo-webapi.public%20kreta-eugyintezes-webapi.public%20kreta-fileservice-webapi.public%20kreta-mobile-global-webapi.public%20kreta-dkt-webapi.public%20kreta-ier-webapi.public&code_challenge=Oj_aVMRJHYsv00mrtGJY72NJa7HY54lVnU2Cb4CWbWw&redirect_uri=https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect&client_id=kreta-ellenorzo-student-mobile-ios&state=refilc_student_mobile'),
);
}
// Future<void> loadLoginUrl() async {
// String nonceStr = await Provider.of<KretaClient>(context, listen: false)
// .getAPI(KretaAPI.nonce, json: false);
// Nonce nonce = getNonce(nonceStr, );
// }
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: const BackButton(),
title: const Text('e-KRÉTA Bejelentkezés'),
),
body: Stack(
children: [
WebViewWidget(
controller: controller,
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
),
);
}
}

View File

@ -56,6 +56,13 @@ class AccountView extends StatelessWidget {
Detail( Detail(
title: "parents".plural(user.student.parents.length), title: "parents".plural(user.student.parents.length),
description: user.student.parents.join(", ")), description: user.student.parents.join(", ")),
const SizedBox(
height: 10.0,
),
// Detail(
// title: "parents".i18n,
// description: user.student.parents.join(", ")),
Detail(title: "school".i18n, description: user.student.school.name),
], ],
), ),
); );

View File

@ -9,6 +9,7 @@ extension Localization on String {
"class": "Class", "class": "Class",
"address": "Home address", "address": "Home address",
"parents": "Parents".one("Parent"), "parents": "Parents".one("Parent"),
"parents_phone": "Parents' phone number: ".one("Parent"),
}, },
"hu_hu": { "hu_hu": {
"birthdate": "Születési dátum", "birthdate": "Születési dátum",

View File

@ -37,6 +37,9 @@ import 'package:flutter_material_color_picker/flutter_material_color_picker.dart
import 'package:refilc/models/icon_pack.dart'; import 'package:refilc/models/icon_pack.dart';
import 'package:refilc/utils/format.dart'; import 'package:refilc/utils/format.dart';
import 'package:refilc_mobile_ui/screens/settings/theme_screen.dart'; import 'package:refilc_mobile_ui/screens/settings/theme_screen.dart';
import 'package:refilc_plus/models/premium_scopes.dart';
import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
// import 'package:refilc_plus/models/premium_scopes.dart'; // import 'package:refilc_plus/models/premium_scopes.dart';
// import 'package:refilc_plus/providers/plus_provider.dart'; // import 'package:refilc_plus/providers/plus_provider.dart';
// import 'package:refilc_plus/ui/mobile/plus/upsell.dart'; // import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
@ -900,6 +903,15 @@ class _LiveActivityColorSettingState extends State<LiveActivityColorSetting> {
allowShades: false, allowShades: false,
selectedColor: settings.liveActivityColor, selectedColor: settings.liveActivityColor,
onMainColorChange: (k) { onMainColorChange: (k) {
if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.liveActivityColor)) {
PlusLockedFeaturePopup.show(
context: context,
feature: PremiumFeature.liveActivity,
);
return;
}
setState(() { setState(() {
currentColor = k as Color; currentColor = k as Color;
settings.update( settings.update(

View File

@ -27,6 +27,7 @@ import 'package:refilc_mobile_ui/common/bottom_sheet_menu/bottom_sheet_menu.dart
import 'package:refilc_mobile_ui/common/panel/panel.dart'; import 'package:refilc_mobile_ui/common/panel/panel.dart';
import 'package:refilc_mobile_ui/common/panel/panel_button.dart'; import 'package:refilc_mobile_ui/common/panel/panel_button.dart';
import 'package:refilc_mobile_ui/common/profile_image/profile_image.dart'; import 'package:refilc_mobile_ui/common/profile_image/profile_image.dart';
import 'package:refilc_mobile_ui/common/soon_alert/soon_alert.dart';
// import 'package:refilc_mobile_ui/common/soon_alert/soon_alert.dart'; // import 'package:refilc_mobile_ui/common/soon_alert/soon_alert.dart';
import 'package:refilc_mobile_ui/common/splitted_panel/splitted_panel.dart'; import 'package:refilc_mobile_ui/common/splitted_panel/splitted_panel.dart';
// import 'package:refilc_mobile_ui/common/system_chrome.dart'; // import 'package:refilc_mobile_ui/common/system_chrome.dart';
@ -320,6 +321,7 @@ class SettingsScreenState extends State<SettingsScreen>
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
backgroundColor: Theme.of(context) backgroundColor: Theme.of(context)
.colorScheme .colorScheme
.tertiary, //!settings.presentationMode .tertiary, //!settings.presentationMode
@ -702,6 +704,46 @@ class SettingsScreenState extends State<SettingsScreen>
], ],
), ),
if ((user.gradeStreak ?? 0) > 1)
SplittedPanel(
padding: const EdgeInsets.only(
bottom: 12.0, left: 24.0, right: 24.0),
children: [
GestureDetector(
onTap: () {
SoonAlert.show(context: context);
},
child: ListTile(
title: Text(
"grade_streak".i18n,
style: TextStyle(
color: AppColors.of(context).text.withOpacity(0.95),
fontWeight: FontWeight.w500,
),
),
subtitle: Text(
"grade_streak_subtitle".i18n,
style: TextStyle(
color: AppColors.of(context).text.withOpacity(0.75),
),
),
leading: const Text(
"🔥",
style: TextStyle(fontSize: 22.0),
),
trailing: Text(
"${user.gradeStreak}",
style: TextStyle(
color: AppColors.of(context).text.withOpacity(0.95),
fontWeight: FontWeight.w500,
fontSize: 18.0,
),
),
),
),
],
),
// plus subscribe inline // plus subscribe inline
const PlusSettingsInline(), const PlusSettingsInline(),

View File

@ -116,6 +116,14 @@ extension SettingsLocalization on String {
"exp_settings": "Export Settings", "exp_settings": "Export Settings",
"manage_subs": "Manage Subscription", "manage_subs": "Manage Subscription",
"copy_plus_id": "Copy reFilc+ ID", "copy_plus_id": "Copy reFilc+ ID",
// grade streak
"grade_streak": "Grade 5 Streak",
"grade_streak_subtitle": "So many 5s in a row?!",
// other
"only_ch_title_font": "Font Only for Titles",
"new_popups": "New Popups",
"export_method": "Export Method",
"grade_exporting": "Grade Exporting",
}, },
"hu_hu": { "hu_hu": {
"personal_details": "Személyes információk", "personal_details": "Személyes információk",
@ -230,6 +238,14 @@ extension SettingsLocalization on String {
"exp_settings": "Beállítások exportálása", "exp_settings": "Beállítások exportálása",
"manage_subs": "Előfizetés kezelése", "manage_subs": "Előfizetés kezelése",
"copy_plus_id": "reFilc+ ID másolása", "copy_plus_id": "reFilc+ ID másolása",
// grade streak
"grade_streak": "5-ös sorozat",
"grade_streak_subtitle": "Egymás után ennyi 5-ös?!",
// other
"only_ch_title_font": "Betűtípus csak címekre",
"new_popups": "Új felugró ablakok",
"export_method": "Exportálási mód",
"grade_exporting": "Jegy exportálás",
}, },
"de_de": { "de_de": {
"personal_details": "Persönliche Angaben", "personal_details": "Persönliche Angaben",
@ -344,6 +360,14 @@ extension SettingsLocalization on String {
"exp_settings": "Einstellungen exportieren", "exp_settings": "Einstellungen exportieren",
"manage_subs": "Abonnement verwalten", "manage_subs": "Abonnement verwalten",
"copy_plus_id": "reFilc+ ID kopieren", "copy_plus_id": "reFilc+ ID kopieren",
// grade streak
"grade_streak": "5er-Streak",
"grade_streak_subtitle": "So viele 5er in Folge?!",
// other
"only_ch_title_font": "Schriftart nur für Titel",
"new_popups": "Neue Popups",
"export_method": "Exportmethode",
"grade_exporting": "Noten exportieren",
}, },
}; };

View File

@ -10,6 +10,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:refilc_plus/ui/mobile/settings/submenu/calendar_sync.dart'; import 'package:refilc_plus/ui/mobile/settings/submenu/calendar_sync.dart';
import 'package:refilc_plus/ui/mobile/settings/submenu/grade_exporting.dart';
import 'package:refilc_plus/models/premium_scopes.dart'; import 'package:refilc_plus/models/premium_scopes.dart';
import 'package:refilc_plus/providers/plus_provider.dart'; import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/plus/upsell.dart'; import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
@ -158,6 +159,16 @@ class ExtrasSettingsScreenState extends State<ExtrasSettingsScreen> {
), ),
], ],
), ),
SplittedPanel(
padding: const EdgeInsets.only(top: 9.0),
cardPadding: const EdgeInsets.all(4.0),
isSeparated: true,
children: [
MenuGradeExporting(
borderRadius: BorderRadius.circular(12.0),
),
],
),
SplittedPanel( SplittedPanel(
padding: const EdgeInsets.only(top: 9.0), padding: const EdgeInsets.only(top: 9.0),
cardPadding: const EdgeInsets.all(4.0), cardPadding: const EdgeInsets.all(4.0),

View File

@ -0,0 +1,381 @@
import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/colors.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:refilc/ui/flutter_colorpicker/colorpicker.dart';
import 'package:refilc/ui/widgets/grade/grade_tile.dart';
import 'package:refilc_kreta_api/models/grade.dart';
import 'package:refilc_mobile_ui/screens/settings/theme_screen.dart';
import 'submenu_screen.i18n.dart';
enum SelectedGrade { one, two, three, four, five }
class GradeColorsSettingsScreen extends StatefulWidget {
const GradeColorsSettingsScreen({super.key});
@override
GradeColorsSettingsScreenState createState() =>
GradeColorsSettingsScreenState();
}
class GradeColorsSettingsScreenState extends State<GradeColorsSettingsScreen> {
late SettingsProvider settingsProvider;
SelectedGrade currentEditGrade = SelectedGrade.one;
@override
Widget build(BuildContext context) {
SettingsProvider settingsProvider = Provider.of<SettingsProvider>(context);
return Scaffold(
appBar: AppBar(
surfaceTintColor: Theme.of(context).scaffoldBackgroundColor,
leading: BackButton(
color: AppColors.of(context).text,
onPressed: () {
setState(() {
// made this cuz else it will be ugly
currentEditGrade = SelectedGrade.one;
});
Navigator.of(context).pop();
},
),
title: Text(
"grade_colors".i18n,
style: TextStyle(color: AppColors.of(context).text),
),
actions: [
IconButton(
onPressed: () {
List<Color> colors = List.castFrom(settingsProvider.gradeColors);
var defaultColors =
SettingsProvider.defaultSettings().gradeColors;
colors[currentEditGrade.index] =
defaultColors[currentEditGrade.index];
settingsProvider.update(gradeColors: colors);
},
icon: const Icon(
Icons.restore,
size: 26.0,
),
),
const SizedBox(
width: 10.0,
),
],
),
body: SizedBox(
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
SizedBox(
height: MediaQuery.of(context).size.height * 0.14,
),
Stack(
children: [
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
borderRadius: BorderRadius.circular(75.0),
boxShadow: [
BoxShadow(
color: Theme.of(context)
.colorScheme
.shadow
.withOpacity(.1),
blurRadius: 10.0,
offset: const Offset(0, 5),
),
],
),
padding: const EdgeInsets.all(6.0),
child: GradeValueWidget(
GradeValue(currentEditGrade.index + 1, '', '', 100),
fill: true,
size: 75.0,
// color:
// settingsProvider.gradeColors[currentEditGrade.index],
),
),
// before grades
if (currentEditGrade.index > 0)
Transform.translate(
offset: const Offset(-110, 16.5),
child: GradeValueWidget(
GradeValue(currentEditGrade.index, '', '', 100),
fill: true,
size: 60.0,
// color:
// settingsProvider.gradeColors[currentEditGrade.index],
),
),
if (currentEditGrade.index > 1)
Transform.translate(
offset: const Offset(-200, 23),
child: GradeValueWidget(
GradeValue(currentEditGrade.index - 1, '', '', 100),
fill: true,
size: 50.0,
// color:
// settingsProvider.gradeColors[currentEditGrade.index],
),
),
// after grades
if (currentEditGrade.index < 4)
Transform.translate(
offset: const Offset(142, 16.5),
child: GradeValueWidget(
GradeValue(currentEditGrade.index + 2, '', '', 100),
fill: true,
size: 60.0,
// color:
// settingsProvider.gradeColors[currentEditGrade.index],
),
),
if (currentEditGrade.index < 3)
Transform.translate(
offset: const Offset(245, 23),
child: GradeValueWidget(
GradeValue(currentEditGrade.index + 3, '', '', 100),
fill: true,
size: 50.0,
// color:
// settingsProvider.gradeColors[currentEditGrade.index],
),
),
],
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.14,
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: SafeArea(
child: FilcColorPicker(
colorMode: CustomColorMode.grade,
pickerColor:
settingsProvider.gradeColors[currentEditGrade.index],
onColorChanged: (c) {
setState(() {
// update grade color
settingsProvider.update(
gradeColors: settingsProvider.gradeColors
..[currentEditGrade.index] = c);
});
},
onColorChangeEnd: (c, {adaptive}) {
// update grade color
},
onThemeIdProvided: (t) {},
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 20.0, top: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () => setState(() {
currentEditGrade = SelectedGrade.one;
}),
child: Container(
width: 45.0,
height: 45.0,
decoration: BoxDecoration(
border: Border.all(
color: currentEditGrade == SelectedGrade.one
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.2),
width: 1.0,
),
borderRadius: BorderRadius.circular(50.0),
color: currentEditGrade == SelectedGrade.one
? Theme.of(context).colorScheme.secondary
: null,
),
child: Center(
child: Text(
'1',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: currentEditGrade == SelectedGrade.one
? Colors.white
: null,
),
),
),
),
),
const SizedBox(width: 10.0),
GestureDetector(
onTap: () => setState(() {
currentEditGrade = SelectedGrade.two;
}),
child: Container(
width: 45.0,
height: 45.0,
decoration: BoxDecoration(
border: Border.all(
color: currentEditGrade == SelectedGrade.two
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.2),
width: 1.0,
),
borderRadius: BorderRadius.circular(50.0),
color: currentEditGrade == SelectedGrade.two
? Theme.of(context).colorScheme.secondary
: null,
),
child: Center(
child: Text(
'2',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: currentEditGrade == SelectedGrade.two
? Colors.white
: null,
),
),
),
),
),
const SizedBox(width: 10.0),
GestureDetector(
onTap: () => setState(() {
currentEditGrade = SelectedGrade.three;
}),
child: Container(
width: 45.0,
height: 45.0,
decoration: BoxDecoration(
border: Border.all(
color: currentEditGrade == SelectedGrade.three
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.2),
width: 1.0,
),
borderRadius: BorderRadius.circular(50.0),
color: currentEditGrade == SelectedGrade.three
? Theme.of(context).colorScheme.secondary
: null,
),
child: Center(
child: Text(
'3',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: currentEditGrade == SelectedGrade.three
? Colors.white
: null,
),
),
),
),
),
const SizedBox(width: 10.0),
GestureDetector(
onTap: () => setState(() {
currentEditGrade = SelectedGrade.four;
}),
child: Container(
width: 45.0,
height: 45.0,
decoration: BoxDecoration(
border: Border.all(
color: currentEditGrade == SelectedGrade.four
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.2),
width: 1.0,
),
borderRadius: BorderRadius.circular(50.0),
color: currentEditGrade == SelectedGrade.four
? Theme.of(context).colorScheme.secondary
: null,
),
child: Center(
child: Text(
'4',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: currentEditGrade == SelectedGrade.four
? Colors.white
: null,
),
),
),
),
),
const SizedBox(width: 10.0),
GestureDetector(
onTap: () => setState(() {
currentEditGrade = SelectedGrade.five;
}),
child: Container(
width: 45.0,
height: 45.0,
decoration: BoxDecoration(
border: Border.all(
color: currentEditGrade == SelectedGrade.five
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.2),
width: 1.0,
),
borderRadius: BorderRadius.circular(50.0),
color: currentEditGrade == SelectedGrade.five
? Theme.of(context).colorScheme.secondary
: null,
),
child: Center(
child: Text(
'5',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: currentEditGrade == SelectedGrade.five
? Colors.white
: null,
),
),
),
),
),
],
),
),
],
),
],
),
),
);
}
}

View File

@ -16,6 +16,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:refilc_mobile_ui/screens/settings/settings_screen.i18n.dart'; import 'package:refilc_mobile_ui/screens/settings/settings_screen.i18n.dart';
import 'package:refilc_mobile_ui/screens/settings/submenu/share_theme_popup.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
class MenuPaintList extends StatelessWidget { class MenuPaintList extends StatelessWidget {
@ -251,18 +252,7 @@ class PaintListScreenState extends State<PaintListScreen>
subject: 'share_subj_theme'.i18n, subject: 'share_subj_theme'.i18n,
); );
} else { } else {
SharedGradeColors gradeColors = await shareProvider ShareThemeDialog.show(context);
.shareCurrentGradeColors(context);
SharedTheme theme =
await shareProvider.shareCurrentTheme(
context,
gradeColors: gradeColors,
);
Share.share(
theme.id,
subject: 'share_subj_theme'.i18n,
);
} }
}, },
longPressInstead: true, longPressInstead: true,

View File

@ -30,6 +30,8 @@ import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/plus/upsell.dart'; import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'grade_colors.dart';
class MenuPersonalizeSettings extends StatelessWidget { class MenuPersonalizeSettings extends StatelessWidget {
const MenuPersonalizeSettings({ const MenuPersonalizeSettings({
super.key, super.key,
@ -459,6 +461,49 @@ class PersonalizeSettingsScreenState extends State<PersonalizeSettingsScreen>
), ),
], ],
), ),
// new popup toggle
SplittedPanel(
padding: const EdgeInsets.only(top: 9.0),
cardPadding: const EdgeInsets.all(4.0),
isSeparated: true,
children: [
PanelButton(
padding: const EdgeInsets.only(left: 14.0, right: 6.0),
onPressed: () async {
settingsProvider.update(
newPopups: !settingsProvider.newPopups);
setState(() {});
},
title: Text(
"new_popups".i18n,
style: TextStyle(
color: AppColors.of(context).text.withOpacity(
settingsProvider.newPopups ? .95 : .25),
),
),
leading: Icon(
FeatherIcons.alertOctagon,
size: 22.0,
color: AppColors.of(context).text.withOpacity(
settingsProvider.newPopups ? .95 : .25),
),
trailing: Switch(
onChanged: (v) async {
settingsProvider.update(newPopups: v);
setState(() {});
},
value: settingsProvider.newPopups,
activeColor: Theme.of(context).colorScheme.secondary,
),
borderRadius: const BorderRadius.vertical(
top: Radius.circular(12.0),
bottom: Radius.circular(12.0),
),
),
],
),
// change subject icons // change subject icons
// SplittedPanel( // SplittedPanel(
// padding: const EdgeInsets.only(top: 9.0), // padding: const EdgeInsets.only(top: 9.0),
@ -499,8 +544,14 @@ class PersonalizeSettingsScreenState extends State<PersonalizeSettingsScreen>
children: [ children: [
PanelButton( PanelButton(
onPressed: () { onPressed: () {
SettingsHelper.gradeColors(context); // SettingsHelper.gradeColors(context);
setState(() {}); // setState(() {});
Navigator.of(context, rootNavigator: true).push(
CupertinoPageRoute(
builder: (context) =>
const GradeColorsSettingsScreen(),
),
);
}, },
title: Text( title: Text(
"grade_colors".i18n, "grade_colors".i18n,
@ -670,16 +721,6 @@ class PersonalizeSettingsScreenState extends State<PersonalizeSettingsScreen>
children: [ children: [
PanelButton( PanelButton(
onPressed: () { onPressed: () {
if (!Provider.of<PlusProvider>(context,
listen: false)
.hasScope(PremiumScopes.liveActivityColor)) {
PlusLockedFeaturePopup.show(
context: context,
feature: PremiumFeature.liveActivity,
);
return;
}
SettingsHelper.liveActivityColor(context); SettingsHelper.liveActivityColor(context);
setState(() {}); setState(() {});
}, },
@ -882,7 +923,7 @@ class PersonalizeSettingsScreenState extends State<PersonalizeSettingsScreen>
title: Text('fonts'.i18n), title: Text('fonts'.i18n),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
cardPadding: const EdgeInsets.all(4.0), cardPadding: const EdgeInsets.all(4.0),
isSeparated: true, isSeparated: false,
children: [ children: [
PanelButton( PanelButton(
onPressed: () { onPressed: () {
@ -920,11 +961,72 @@ class PersonalizeSettingsScreenState extends State<PersonalizeSettingsScreen>
), ),
borderRadius: const BorderRadius.vertical( borderRadius: const BorderRadius.vertical(
top: Radius.circular(12.0), top: Radius.circular(12.0),
bottom: Radius.circular(6.0),
),
),
PanelButton(
padding: const EdgeInsets.only(left: 14.0, right: 6.0),
onPressed: () async {
if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.customFont)) {
PlusLockedFeaturePopup.show(
context: context,
feature: PremiumFeature.fontChange);
return;
}
settingsProvider.update(
titleOnlyFont: !settingsProvider.titleOnlyFont);
Provider.of<ThemeModeObserver>(context, listen: false)
.changeTheme(settingsProvider.theme,
updateNavbarColor: false);
setState(() {});
},
title: Text(
"only_ch_title_font".i18n,
style: TextStyle(
color: AppColors.of(context).text.withOpacity(
settingsProvider.titleOnlyFont ? .95 : .25),
),
),
leading: Icon(
Icons.text_increase_rounded,
size: 22.0,
color: AppColors.of(context).text.withOpacity(
settingsProvider.titleOnlyFont ? .95 : .25),
),
trailing: Switch(
onChanged: (v) async {
if (!Provider.of<PlusProvider>(context,
listen: false)
.hasScope(PremiumScopes.customFont)) {
PlusLockedFeaturePopup.show(
context: context,
feature: PremiumFeature.fontChange);
return;
}
settingsProvider.update(titleOnlyFont: v);
Provider.of<ThemeModeObserver>(context,
listen: false)
.changeTheme(settingsProvider.theme,
updateNavbarColor: false);
setState(() {});
},
value: settingsProvider.titleOnlyFont,
activeColor: Theme.of(context).colorScheme.secondary,
),
borderRadius: const BorderRadius.vertical(
top: Radius.circular(4.0),
bottom: Radius.circular(12.0), bottom: Radius.circular(12.0),
), ),
), ),
], ],
), ),
// bottom padding
const SizedBox(
height: 20.0,
),
], ],
), ),
), ),

View File

@ -0,0 +1,160 @@
// ignore_for_file: use_build_context_synchronously, deprecated_member_use
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart';
// import 'package:refilc/models/settings.dart';
import 'package:refilc/models/shared_theme.dart';
import 'package:refilc_kreta_api/providers/share_provider.dart';
import 'package:refilc_mobile_ui/common/action_button.dart';
import 'package:refilc_mobile_ui/common/splitted_panel/splitted_panel.dart';
import 'package:share_plus/share_plus.dart';
import 'submenu_screen.i18n.dart';
class ShareThemeDialog extends StatefulWidget {
const ShareThemeDialog({super.key});
static void show(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
title: Text("attention".i18n),
content: Text("share_disclaimer".i18n),
actions: [
ActionButton(
label: "understand".i18n,
onTap: () async {
Navigator.of(context).pop();
showDialog(
context: context,
builder: (context) => const ShareThemeDialog());
},
),
],
),
);
}
@override
ShareThemeDialogState createState() => ShareThemeDialogState();
}
class ShareThemeDialogState extends State<ShareThemeDialog> {
final _title = TextEditingController();
bool isPublic = false;
late ShareProvider shareProvider;
@override
void initState() {
super.initState();
shareProvider = Provider.of<ShareProvider>(context, listen: false);
}
@override
Widget build(BuildContext context) {
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(14.0))),
contentPadding: const EdgeInsets.only(top: 10.0),
title: Text("share_theme".i18n),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding:
const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
child: TextField(
controller: _title,
onEditingComplete: () async {},
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
hintText: 'paint_title'.i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
),
onPressed: () {
setState(() {
_title.text = '';
});
},
),
),
),
),
SplittedPanel(
children: [
SwitchListTile(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.0),
),
value: isPublic,
onChanged: (value) {
setState(() {
isPublic = value;
});
},
title: Text("is_public".i18n),
contentPadding: const EdgeInsets.only(left: 15.0, right: 10.0),
),
],
),
],
),
actions: [
TextButton(
child: Text(
"cancel".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () {
Navigator.of(context).maybePop();
},
),
TextButton(
child: Text(
"share_it".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () async {
// share the fucking theme
SharedGradeColors gradeColors =
await shareProvider.shareCurrentGradeColors(context);
SharedTheme theme = await shareProvider.shareCurrentTheme(
context,
gradeColors: gradeColors,
isPublic: isPublic,
displayName: _title.text,
);
// save theme id in settings
// Provider.of<SettingsProvider>(context, listen: false)
// .update(currentThemeId: theme.id);
// close this popup shit
Navigator.of(context).pop(true);
// show the share popup
Share.share(
theme.id,
subject: 'share_subj_theme'.i18n,
);
},
),
],
);
}
}

View File

@ -17,6 +17,17 @@ extension SettingsLocalization on String {
"rare": "Rare", "rare": "Rare",
"epic": "Epic", "epic": "Epic",
"legendary": "Legendary", "legendary": "Legendary",
// grade colors
"grade_colors": "Grade Colors",
// theme share popup
"share_theme": "Share Paint",
"paint_title": "Paint title...",
"share_it": "Share it!",
"is_public": "Public Paint",
"attention": "Attention!",
"share_disclaimer":
"By sharing the theme, you agree that the nickname you set and all settings of the theme will be shared publicly.",
"understand": "I understand",
}, },
"hu_hu": { "hu_hu": {
"general": "Általános", "general": "Általános",
@ -32,6 +43,17 @@ extension SettingsLocalization on String {
"rare": "Ritka", "rare": "Ritka",
"epic": "Epikus", "epic": "Epikus",
"legendary": "Legendás", "legendary": "Legendás",
// grade colors
"grade_colors": "Jegyek színei",
// theme share popup
"share_theme": "Téma megosztása",
"paint_title": "Téma neve...",
"share_it": "Megosztás!",
"is_public": "Nyilvános téma",
"attention": "Figyelem!",
"share_disclaimer":
"A téma megosztásával elfogadod, hogy az általad beállított becenév és a téma minden beállítása nyilvánosan megosztásra kerüljön.",
"understand": "Értem",
}, },
"de_de": { "de_de": {
"general": "Allgemeine", "general": "Allgemeine",
@ -47,6 +69,17 @@ extension SettingsLocalization on String {
"rare": "Selten", "rare": "Selten",
"epic": "Episch", "epic": "Episch",
"legendary": "Legendär", "legendary": "Legendär",
// grade colors
"grade_colors": "Notenfarben",
// theme share popup
"share_theme": "Thema teilen",
"paint_title": "Thema Titel...",
"share_it": "Teilen!",
"is_public": "Öffentliches Thema",
"attention": "Achtung!",
"share_disclaimer":
"Durch das Teilen des Themes erklären Sie sich damit einverstanden, dass der von Ihnen festgelegte Spitzname und alle Einstellungen des Themes öffentlich geteilt werden.",
"understand": "Ich verstehe",
}, },
}; };

View File

@ -1,7 +1,7 @@
// ignore_for_file: use_build_context_synchronously, deprecated_member_use // ignore_for_file: use_build_context_synchronously, deprecated_member_use
import 'package:refilc/models/settings.dart'; import 'package:refilc/models/settings.dart';
import 'package:refilc/models/shared_theme.dart'; // import 'package:refilc/models/shared_theme.dart';
import 'package:refilc/theme/colors/accent.dart'; import 'package:refilc/theme/colors/accent.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/theme/observer.dart'; import 'package:refilc/theme/observer.dart';
@ -10,7 +10,7 @@ import 'package:refilc/ui/widgets/message/message_tile.dart';
import 'package:refilc_kreta_api/models/grade.dart'; import 'package:refilc_kreta_api/models/grade.dart';
import 'package:refilc_kreta_api/models/homework.dart'; import 'package:refilc_kreta_api/models/homework.dart';
import 'package:refilc_kreta_api/models/message.dart'; import 'package:refilc_kreta_api/models/message.dart';
import 'package:refilc_mobile_ui/common/action_button.dart'; // import 'package:refilc_mobile_ui/common/action_button.dart';
import 'package:refilc_mobile_ui/common/filter_bar.dart'; import 'package:refilc_mobile_ui/common/filter_bar.dart';
import 'package:refilc_mobile_ui/common/panel/panel.dart'; import 'package:refilc_mobile_ui/common/panel/panel.dart';
import 'package:refilc_mobile_ui/common/widgets/grade/new_grades.dart'; import 'package:refilc_mobile_ui/common/widgets/grade/new_grades.dart';
@ -24,6 +24,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:refilc_mobile_ui/screens/settings/submenu/share_theme_popup.dart';
import 'theme_screen.i18n.dart'; import 'theme_screen.i18n.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
@ -44,6 +45,7 @@ enum CustomColorMode {
text, text,
icon, icon,
enterId, enterId,
grade,
} }
class _PremiumCustomAccentColorSettingState class _PremiumCustomAccentColorSettingState
@ -158,6 +160,9 @@ class _PremiumCustomAccentColorSettingState
case CustomColorMode.enterId: case CustomColorMode.enterId:
// do nothing here lol // do nothing here lol
break; break;
case CustomColorMode.grade:
// do nothing here as well
break;
} }
} }
@ -218,6 +223,9 @@ class _PremiumCustomAccentColorSettingState
settings.update(customAccentColor: accent, store: store); settings.update(customAccentColor: accent, store: store);
settings.update(customIconColor: icon, store: store); settings.update(customIconColor: icon, store: store);
break; break;
case CustomColorMode.grade:
// do nothing
break;
} }
} }
@ -297,40 +305,48 @@ class _PremiumCustomAccentColorSettingState
// ), // ),
// ), // ),
// ); // );
showDialog( // showDialog(
context: context, // context: context,
builder: (context) => WillPopScope( // builder: (context) => WillPopScope(
onWillPop: () async => false, // onWillPop: () async => false,
child: AlertDialog( // child: AlertDialog(
shape: RoundedRectangleBorder( // shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0)), // borderRadius: BorderRadius.circular(12.0)),
title: Text("attention".i18n), // title: Text("attention".i18n),
content: Text("share_disclaimer".i18n), // content: Text("share_disclaimer".i18n),
actions: [ // actions: [
ActionButton( // ActionButton(
label: "understand".i18n, // label: "understand".i18n,
onTap: () async { // onTap: () async {
Navigator.of(context).pop(); // Navigator.of(context).pop();
SharedGradeColors gradeColors = // SharedGradeColors gradeColors =
await shareProvider // await shareProvider
.shareCurrentGradeColors(context); // .shareCurrentGradeColors(context);
SharedTheme theme = // SharedTheme theme =
await shareProvider.shareCurrentTheme( // await shareProvider.shareCurrentTheme(
context, // context,
gradeColors: gradeColors, // gradeColors: gradeColors,
); // );
Share.share( // Share.share(
theme.id, // theme.id,
subject: 'share_subj_theme'.i18n, // subject: 'share_subj_theme'.i18n,
); // );
}, // },
), // ),
], // ],
), // ),
), // ),
); // );
if (settings.currentThemeId != '') {
Share.share(
settings.currentThemeId,
subject: 'share_subj_theme'.i18n,
);
} else {
ShareThemeDialog.show(context);
}
}, },
icon: const Icon( icon: const Icon(
FeatherIcons.share2, FeatherIcons.share2,

View File

@ -71,6 +71,7 @@ dependencies:
markdown: ^7.2.2 markdown: ^7.2.2
carousel_slider: ^4.2.1 carousel_slider: ^4.2.1
flutter_portal: ^1.1.4 flutter_portal: ^1.1.4
webview_flutter: ^4.8.0
dev_dependencies: dev_dependencies:
flutter_lints: ^3.0.1 flutter_lints: ^3.0.1

@ -1 +1 @@
Subproject commit 1f5cca7b8e2ac896155a6c494e79fb057628379e Subproject commit 9bd46b81f230cd094787e1436cd5e8cdee7b5529