mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-01-31 13:18:20 +01:00
Merge branch 'release/0.17.0'
This commit is contained in:
commit
232d8d38bd
@ -14,7 +14,7 @@ cache:
|
|||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- develop
|
- develop
|
||||||
- 0.16.0
|
- 0.17.0
|
||||||
|
|
||||||
android:
|
android:
|
||||||
licenses:
|
licenses:
|
||||||
|
@ -4,6 +4,7 @@ apply plugin: 'kotlin-kapt'
|
|||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-android-extensions'
|
||||||
apply plugin: 'io.fabric'
|
apply plugin: 'io.fabric'
|
||||||
apply plugin: 'com.github.triplet.play'
|
apply plugin: 'com.github.triplet.play'
|
||||||
|
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
|
||||||
apply from: 'jacoco.gradle'
|
apply from: 'jacoco.gradle'
|
||||||
apply from: 'sonarqube.gradle'
|
apply from: 'sonarqube.gradle'
|
||||||
apply from: 'hooks.gradle'
|
apply from: 'hooks.gradle'
|
||||||
@ -17,8 +18,8 @@ android {
|
|||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 17
|
minSdkVersion 17
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 53
|
versionCode 54
|
||||||
versionName "0.16.0"
|
versionName "0.17.0"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
@ -96,6 +97,10 @@ android {
|
|||||||
exclude 'META-INF/library_release.kotlin_module'
|
exclude 'META-INF/library_release.kotlin_module'
|
||||||
exclude 'META-INF/library-core_release.kotlin_module'
|
exclude 'META-INF/library-core_release.kotlin_module'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aboutLibraries {
|
||||||
|
configPath = "app/src/main/res/raw"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
androidExtensions {
|
androidExtensions {
|
||||||
@ -110,10 +115,11 @@ play {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
work_manager = "2.3.2"
|
work_manager = "2.3.4"
|
||||||
room = "2.2.4"
|
room = "2.2.5"
|
||||||
dagger = "2.26"
|
dagger = "2.27"
|
||||||
chucker = "2.0.4"
|
// don't update https://github.com/ChuckerTeam/chucker/issues/242
|
||||||
|
chucker = "3.2.0"
|
||||||
mockk = "1.9.2"
|
mockk = "1.9.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,21 +128,21 @@ configurations.all {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "io.github.wulkanowy:sdk:0.16.0"
|
implementation "io.github.wulkanowy:sdk:0.17.0"
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation "androidx.core:core-ktx:1.2.0"
|
implementation "androidx.core:core-ktx:1.2.0"
|
||||||
implementation "androidx.activity:activity-ktx:1.1.0"
|
implementation "androidx.activity:activity-ktx:1.1.0"
|
||||||
implementation "androidx.appcompat:appcompat:1.1.0"
|
implementation "androidx.appcompat:appcompat:1.2.0-beta01"
|
||||||
implementation "androidx.appcompat:appcompat-resources:1.1.0"
|
implementation "androidx.appcompat:appcompat-resources:1.1.0"
|
||||||
implementation "androidx.fragment:fragment-ktx:1.2.2"
|
implementation "androidx.fragment:fragment-ktx:1.2.4"
|
||||||
implementation "androidx.annotation:annotation:1.1.0"
|
implementation "androidx.annotation:annotation:1.1.0"
|
||||||
implementation "androidx.multidex:multidex:2.0.1"
|
implementation "androidx.multidex:multidex:2.0.1"
|
||||||
|
|
||||||
implementation "androidx.preference:preference-ktx:1.1.0"
|
implementation "androidx.preference:preference-ktx:1.1.0"
|
||||||
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||||
implementation "androidx.viewpager:viewpager:1.0.0"
|
implementation "androidx.viewpager:viewpager:1.0.0"
|
||||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03"
|
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-beta01"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
|
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
|
||||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
||||||
implementation "com.google.android.material:material:1.1.0"
|
implementation "com.google.android.material:material:1.1.0"
|
||||||
@ -148,6 +154,8 @@ dependencies {
|
|||||||
implementation "androidx.work:work-rxjava2:$work_manager"
|
implementation "androidx.work:work-rxjava2:$work_manager"
|
||||||
implementation "androidx.work:work-gcm:$work_manager"
|
implementation "androidx.work:work-gcm:$work_manager"
|
||||||
|
|
||||||
|
implementation 'com.github.PaulinaSadowska:RxWorkManagerObservers:1.0.0'
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:$room"
|
implementation "androidx.room:room-runtime:$room"
|
||||||
implementation "androidx.room:room-rxjava2:$room"
|
implementation "androidx.room:room-rxjava2:$room"
|
||||||
implementation "androidx.room:room-ktx:$room"
|
implementation "androidx.room:room-ktx:$room"
|
||||||
@ -163,34 +171,37 @@ dependencies {
|
|||||||
implementation "eu.davidea:flexible-adapter-ui:1.0.0"
|
implementation "eu.davidea:flexible-adapter-ui:1.0.0"
|
||||||
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
|
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
|
||||||
implementation "com.ncapdevi:frag-nav:3.3.0"
|
implementation "com.ncapdevi:frag-nav:3.3.0"
|
||||||
implementation "com.github.YarikSOffice:lingver:1.1.0"
|
implementation "com.github.YarikSOffice:lingver:1.2.1"
|
||||||
|
|
||||||
implementation "com.github.pwittchen:reactivenetwork-rx2:3.0.6"
|
implementation "com.github.pwittchen:reactivenetwork-rx2:3.0.6"
|
||||||
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
|
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
|
||||||
implementation "io.reactivex.rxjava2:rxjava:2.2.18"
|
implementation "io.reactivex.rxjava2:rxjava:2.2.19"
|
||||||
|
|
||||||
implementation "com.google.code.gson:gson:2.8.6"
|
implementation "com.google.code.gson:gson:2.8.6"
|
||||||
implementation "com.jakewharton.threetenabp:threetenabp:1.2.2"
|
implementation "com.jakewharton.threetenabp:threetenabp:1.2.3"
|
||||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||||
implementation "fr.bipi.treessence:treessence:0.3.2"
|
implementation "fr.bipi.treessence:treessence:0.3.2"
|
||||||
implementation "com.mikepenz:aboutlibraries-core:7.1.0"
|
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||||
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
|
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
|
||||||
|
implementation "io.coil-kt:coil:0.9.5"
|
||||||
|
|
||||||
implementation("io.coil-kt:coil:0.9.5")
|
playImplementation 'com.google.firebase:firebase-analytics:17.3.0'
|
||||||
|
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.0.4'
|
||||||
playImplementation "com.google.firebase:firebase-core:17.2.3"
|
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.0.4"
|
||||||
|
playImplementation "com.google.firebase:firebase-messaging:20.1.0"
|
||||||
playImplementation "com.crashlytics.sdk.android:crashlytics:2.10.1"
|
playImplementation "com.crashlytics.sdk.android:crashlytics:2.10.1"
|
||||||
|
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
|
||||||
|
|
||||||
releaseImplementation "fr.o80.chucker:library-no-op:$chucker"
|
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||||
|
|
||||||
debugImplementation "fr.o80.chucker:library:$chucker"
|
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
|
||||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
|
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
|
||||||
|
|
||||||
testImplementation "junit:junit:4.13"
|
testImplementation "junit:junit:4.13"
|
||||||
testImplementation "io.mockk:mockk:$mockk"
|
testImplementation "io.mockk:mockk:$mockk"
|
||||||
testImplementation "org.threeten:threetenbp:1.4.1"
|
testImplementation "org.threeten:threetenbp:1.4.3"
|
||||||
testImplementation "org.mockito:mockito-inline:3.3.1"
|
testImplementation "org.mockito:mockito-inline:3.3.3"
|
||||||
|
|
||||||
androidTestImplementation "androidx.test:core:1.2.0"
|
androidTestImplementation "androidx.test:core:1.2.0"
|
||||||
androidTestImplementation "androidx.test:runner:1.2.0"
|
androidTestImplementation "androidx.test:runner:1.2.0"
|
||||||
@ -198,7 +209,7 @@ dependencies {
|
|||||||
androidTestImplementation "io.mockk:mockk-android:$mockk"
|
androidTestImplementation "io.mockk:mockk-android:$mockk"
|
||||||
androidTestImplementation "androidx.room:room-testing:$room"
|
androidTestImplementation "androidx.room:room-testing:$room"
|
||||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
androidTestImplementation "org.mockito:mockito-android:3.3.1"
|
androidTestImplementation "org.mockito:mockito-android:3.3.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
|
7
app/proguard-rules.pro
vendored
7
app/proguard-rules.pro
vendored
@ -43,3 +43,10 @@
|
|||||||
|
|
||||||
#Config for Material Components
|
#Config for Material Components
|
||||||
-keep class com.google.android.material.tabs.** { *; }
|
-keep class com.google.android.material.tabs.** { *; }
|
||||||
|
|
||||||
|
|
||||||
|
#Config for About Libraries
|
||||||
|
-keep class .R
|
||||||
|
-keep class **.R$* {
|
||||||
|
<fields>;
|
||||||
|
}
|
||||||
|
1682
app/schemas/io.github.wulkanowy.data.db.AppDatabase/23.json
Normal file
1682
app/schemas/io.github.wulkanowy.data.db.AppDatabase/23.json
Normal file
File diff suppressed because it is too large
Load Diff
1732
app/schemas/io.github.wulkanowy.data.db.AppDatabase/24.json
Normal file
1732
app/schemas/io.github.wulkanowy.data.db.AppDatabase/24.json
Normal file
File diff suppressed because it is too large
Load Diff
1744
app/schemas/io.github.wulkanowy.data.db.AppDatabase/25.json
Normal file
1744
app/schemas/io.github.wulkanowy.data.db.AppDatabase/25.json
Normal file
File diff suppressed because it is too large
Load Diff
4
app/src/debug/res/values/preferences_defaults.xml
Normal file
4
app/src/debug/res/values/preferences_defaults.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||||
|
|
||||||
|
<bool name="pref_default_notification_debug">true</bool>
|
||||||
|
</resources>
|
@ -22,7 +22,8 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.splash.SplashActivity"
|
android:name=".ui.modules.splash.SplashActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:theme="@style/WulkanowyTheme.SplashScreen">
|
android:theme="@style/WulkanowyTheme.SplashScreen"
|
||||||
|
tools:ignore="LockedOrientationActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
@ -112,5 +113,13 @@
|
|||||||
<meta-data
|
<meta-data
|
||||||
android:name="firebase_crashlytics_collection_enabled"
|
android:name="firebase_crashlytics_collection_enabled"
|
||||||
android:value="${crashlytics_enabled}" />
|
android:value="${crashlytics_enabled}" />
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||||
|
android:resource="@drawable/ic_stat_push" />
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||||
|
android:value="push_channel" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -7,9 +7,9 @@ import android.content.res.Resources
|
|||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy
|
||||||
import com.readystatesoftware.chuck.api.ChuckCollector
|
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||||
import com.readystatesoftware.chuck.api.ChuckInterceptor
|
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||||
import com.readystatesoftware.chuck.api.RetentionManager
|
import com.chuckerteam.chucker.api.RetentionManager
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import io.github.wulkanowy.data.db.AppDatabase
|
import io.github.wulkanowy.data.db.AppDatabase
|
||||||
@ -32,23 +32,25 @@ internal class RepositoryModule {
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideSdk(chuckCollector: ChuckCollector, context: Context): Sdk {
|
fun provideSdk(chuckerCollector: ChuckerCollector, context: Context): Sdk {
|
||||||
return Sdk().apply {
|
return Sdk().apply {
|
||||||
androidVersion = android.os.Build.VERSION.RELEASE
|
androidVersion = android.os.Build.VERSION.RELEASE
|
||||||
buildTag = android.os.Build.MODEL
|
buildTag = android.os.Build.MODEL
|
||||||
setSimpleHttpLogger { Timber.d(it) }
|
setSimpleHttpLogger { Timber.d(it) }
|
||||||
|
|
||||||
// for debug only
|
// for debug only
|
||||||
addInterceptor(ChuckInterceptor(context, chuckCollector).maxContentLength(250000L), true)
|
addInterceptor(ChuckerInterceptor(context, chuckerCollector), true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideChuckCollector(context: Context, prefRepository: PreferencesRepository): ChuckCollector {
|
fun provideChuckerCollector(context: Context, prefRepository: PreferencesRepository): ChuckerCollector {
|
||||||
return ChuckCollector(context)
|
return ChuckerCollector(
|
||||||
.showNotification(prefRepository.isDebugNotificationEnable)
|
context = context,
|
||||||
.retentionManager(RetentionManager(context, ChuckCollector.Period.ONE_HOUR))
|
showNotification = prefRepository.isDebugNotificationEnable,
|
||||||
|
retentionPeriod = RetentionManager.Period.ONE_HOUR
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@ -95,6 +97,10 @@ internal class RepositoryModule {
|
|||||||
@Provides
|
@Provides
|
||||||
fun provideMessagesDao(database: AppDatabase) = database.messagesDao
|
fun provideMessagesDao(database: AppDatabase) = database.messagesDao
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideMessageAttachmentsDao(database: AppDatabase) = database.messageAttachmentDao
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideExamDao(database: AppDatabase) = database.examsDao
|
fun provideExamDao(database: AppDatabase) = database.examsDao
|
||||||
|
@ -17,6 +17,7 @@ import io.github.wulkanowy.data.db.dao.GradeStatisticsDao
|
|||||||
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
|
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
|
||||||
import io.github.wulkanowy.data.db.dao.HomeworkDao
|
import io.github.wulkanowy.data.db.dao.HomeworkDao
|
||||||
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
|
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||||
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
|
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
|
||||||
import io.github.wulkanowy.data.db.dao.NoteDao
|
import io.github.wulkanowy.data.db.dao.NoteDao
|
||||||
@ -39,6 +40,7 @@ import io.github.wulkanowy.data.db.entities.GradeSummary
|
|||||||
import io.github.wulkanowy.data.db.entities.Homework
|
import io.github.wulkanowy.data.db.entities.Homework
|
||||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||||
import io.github.wulkanowy.data.db.entities.MobileDevice
|
import io.github.wulkanowy.data.db.entities.MobileDevice
|
||||||
import io.github.wulkanowy.data.db.entities.Note
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
@ -63,6 +65,9 @@ import io.github.wulkanowy.data.db.migrations.Migration2
|
|||||||
import io.github.wulkanowy.data.db.migrations.Migration20
|
import io.github.wulkanowy.data.db.migrations.Migration20
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration21
|
import io.github.wulkanowy.data.db.migrations.Migration21
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration22
|
import io.github.wulkanowy.data.db.migrations.Migration22
|
||||||
|
import io.github.wulkanowy.data.db.migrations.Migration23
|
||||||
|
import io.github.wulkanowy.data.db.migrations.Migration24
|
||||||
|
import io.github.wulkanowy.data.db.migrations.Migration25
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration3
|
import io.github.wulkanowy.data.db.migrations.Migration3
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration4
|
import io.github.wulkanowy.data.db.migrations.Migration4
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration5
|
import io.github.wulkanowy.data.db.migrations.Migration5
|
||||||
@ -86,6 +91,7 @@ import javax.inject.Singleton
|
|||||||
GradeStatistics::class,
|
GradeStatistics::class,
|
||||||
GradePointsStatistics::class,
|
GradePointsStatistics::class,
|
||||||
Message::class,
|
Message::class,
|
||||||
|
MessageAttachment::class,
|
||||||
Note::class,
|
Note::class,
|
||||||
Homework::class,
|
Homework::class,
|
||||||
Subject::class,
|
Subject::class,
|
||||||
@ -104,7 +110,7 @@ import javax.inject.Singleton
|
|||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 22
|
const val VERSION_SCHEMA = 25
|
||||||
|
|
||||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
|
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
|
||||||
return arrayOf(
|
return arrayOf(
|
||||||
@ -128,7 +134,10 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
Migration19(sharedPrefProvider),
|
Migration19(sharedPrefProvider),
|
||||||
Migration20(),
|
Migration20(),
|
||||||
Migration21(),
|
Migration21(),
|
||||||
Migration22()
|
Migration22(),
|
||||||
|
Migration23(),
|
||||||
|
Migration24(),
|
||||||
|
Migration25()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +173,8 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
|
|
||||||
abstract val messagesDao: MessagesDao
|
abstract val messagesDao: MessagesDao
|
||||||
|
|
||||||
|
abstract val messageAttachmentDao: MessageAttachmentDao
|
||||||
|
|
||||||
abstract val noteDao: NoteDao
|
abstract val noteDao: NoteDao
|
||||||
|
|
||||||
abstract val homeworkDao: HomeworkDao
|
abstract val homeworkDao: HomeworkDao
|
||||||
|
@ -48,4 +48,14 @@ class Converters {
|
|||||||
fun gsonToIntList(value: String): List<Int> {
|
fun gsonToIntList(value: String): List<Int> {
|
||||||
return Gson().fromJson(value, object : TypeToken<List<Int>>() {}.type)
|
return Gson().fromJson(value, object : TypeToken<List<Int>>() {}.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun stringPairListToGson(list: List<Pair<String, String>>): String {
|
||||||
|
return Gson().toJson(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun gsonToStringPairList(value: String): List<Pair<String, String>> {
|
||||||
|
return Gson().fromJson(value, object : TypeToken<List<Pair<String, String>>>() {}.type)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package io.github.wulkanowy.data.db.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface MessageAttachmentDao : BaseDao<MessageAttachment> {
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
fun insertAttachments(items: List<MessageAttachment>): List<Long>
|
||||||
|
}
|
@ -2,19 +2,22 @@ package io.github.wulkanowy.data.db.dao
|
|||||||
|
|
||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
|
import androidx.room.Transaction
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
import io.reactivex.Maybe
|
import io.reactivex.Maybe
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface MessagesDao : BaseDao<Message> {
|
interface MessagesDao : BaseDao<Message> {
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND message_id = :messageId")
|
||||||
|
fun loadMessageWithAttachment(studentId: Int, messageId: Int): Single<MessageWithAttachment>
|
||||||
|
|
||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder AND removed = 0 ORDER BY date DESC")
|
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder AND removed = 0 ORDER BY date DESC")
|
||||||
fun loadAll(studentId: Int, folder: Int): Maybe<List<Message>>
|
fun loadAll(studentId: Int, folder: Int): Maybe<List<Message>>
|
||||||
|
|
||||||
@Query("SELECT * FROM Messages WHERE id = :id")
|
|
||||||
fun load(id: Long): Single<Message>
|
|
||||||
|
|
||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC")
|
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC")
|
||||||
fun loadDeleted(studentId: Int): Maybe<List<Message>>
|
fun loadDeleted(studentId: Int): Maybe<List<Message>>
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,14 @@ data class Homework(
|
|||||||
val teacher: String,
|
val teacher: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "teacher_symbol")
|
@ColumnInfo(name = "teacher_symbol")
|
||||||
val teacherSymbol: String
|
val teacherSymbol: String,
|
||||||
|
|
||||||
|
val attachments: List<Pair<String, String>>
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
var id: Long = 0
|
var id: Long = 0
|
||||||
|
|
||||||
|
@ColumnInfo(name = "is_done")
|
||||||
|
var isDone: Boolean = false
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,10 @@ data class Message(
|
|||||||
@ColumnInfo(name = "read_by")
|
@ColumnInfo(name = "read_by")
|
||||||
val readBy: Int,
|
val readBy: Int,
|
||||||
|
|
||||||
val removed: Boolean
|
val removed: Boolean,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "has_attachments")
|
||||||
|
val hasAttachments: Boolean
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
@Entity(tableName = "MessageAttachments")
|
||||||
|
data class MessageAttachment(
|
||||||
|
|
||||||
|
@PrimaryKey
|
||||||
|
@ColumnInfo(name = "real_id")
|
||||||
|
val realId: Int,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "message_id")
|
||||||
|
val messageId: Int,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "one_drive_id")
|
||||||
|
val oneDriveId: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "url")
|
||||||
|
val url: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "filename")
|
||||||
|
val filename: String
|
||||||
|
) : Serializable
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import androidx.room.Embedded
|
||||||
|
import androidx.room.Relation
|
||||||
|
|
||||||
|
data class MessageWithAttachment(
|
||||||
|
@Embedded
|
||||||
|
val message: Message,
|
||||||
|
|
||||||
|
@Relation(parentColumn = "message_id", entityColumn = "message_id")
|
||||||
|
val attachments: List<MessageAttachment>
|
||||||
|
)
|
@ -16,8 +16,19 @@ data class Note(
|
|||||||
|
|
||||||
val teacher: String,
|
val teacher: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "teacher_symbol")
|
||||||
|
val teacherSymbol: String,
|
||||||
|
|
||||||
val category: String,
|
val category: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "category_type")
|
||||||
|
val categoryType: Int,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "is_points_show")
|
||||||
|
val isPointsShow: Boolean,
|
||||||
|
|
||||||
|
val points: Int,
|
||||||
|
|
||||||
val content: String
|
val content: String
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
|
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration23 : Migration(22, 23) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("ALTER TABLE Notes ADD COLUMN teacher_symbol TEXT NOT NULL DEFAULT ''")
|
||||||
|
database.execSQL("ALTER TABLE Notes ADD COLUMN category_type INTEGER NOT NULL DEFAULT 0")
|
||||||
|
database.execSQL("ALTER TABLE Notes ADD COLUMN is_points_show INTEGER NOT NULL DEFAULT 0")
|
||||||
|
database.execSQL("ALTER TABLE Notes ADD COLUMN points INTEGER NOT NULL DEFAULT 0")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration24 : Migration(23, 24) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("ALTER TABLE Messages ADD COLUMN has_attachments INTEGER NOT NULL DEFAULT 0")
|
||||||
|
database.execSQL("""
|
||||||
|
CREATE TABLE IF NOT EXISTS MessageAttachments (
|
||||||
|
real_id INTEGER NOT NULL,
|
||||||
|
message_id INTEGER NOT NULL,
|
||||||
|
one_drive_id TEXT NOT NULL,
|
||||||
|
url TEXT NOT NULL,
|
||||||
|
filename TEXT NOT NULL,
|
||||||
|
PRIMARY KEY(real_id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration25 : Migration(24, 25) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("ALTER TABLE Homework ADD COLUMN is_done INTEGER NOT NULL DEFAULT 0")
|
||||||
|
database.execSQL("ALTER TABLE Homework ADD COLUMN attachments TEXT NOT NULL DEFAULT \"[]\"")
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,10 @@ class HomeworkLocal @Inject constructor(private val homeworkDb: HomeworkDao) {
|
|||||||
homeworkDb.deleteAll(homework)
|
homeworkDb.deleteAll(homework)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateHomework(homework: List<Homework>) {
|
||||||
|
homeworkDb.updateAll(homework)
|
||||||
|
}
|
||||||
|
|
||||||
fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Homework>> {
|
fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Homework>> {
|
||||||
return homeworkDb.loadAll(semester.semesterId, semester.studentId, startDate, endDate)
|
return homeworkDb.loadAll(semester.semesterId, semester.studentId, startDate, endDate)
|
||||||
.filter { it.isNotEmpty() }
|
.filter { it.isNotEmpty() }
|
||||||
|
@ -23,7 +23,8 @@ class HomeworkRemote @Inject constructor(private val sdk: Sdk) {
|
|||||||
subject = it.subject,
|
subject = it.subject,
|
||||||
content = it.content,
|
content = it.content,
|
||||||
teacher = it.teacher,
|
teacher = it.teacher,
|
||||||
teacherSymbol = it.teacherSymbol
|
teacherSymbol = it.teacherSymbol,
|
||||||
|
attachments = it.attachments.map { attachment -> attachment.url to attachment.name }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import io.github.wulkanowy.data.db.entities.Semester
|
|||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
|
import io.reactivex.Completable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -36,4 +37,12 @@ class HomeworkRepository @Inject constructor(
|
|||||||
}.flatMap { local.getHomework(semester, monday, friday).toSingle(emptyList()) })
|
}.flatMap { local.getHomework(semester, monday, friday).toSingle(emptyList()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun toggleDone(homework: Homework): Completable {
|
||||||
|
return Completable.fromCallable {
|
||||||
|
local.updateHomework(listOf(homework.apply {
|
||||||
|
isDone = !isDone
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.data.repositories.luckynumber
|
|||||||
|
|
||||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
|
import io.github.wulkanowy.data.SdkHelper
|
||||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
@ -15,33 +16,36 @@ import javax.inject.Singleton
|
|||||||
class LuckyNumberRepository @Inject constructor(
|
class LuckyNumberRepository @Inject constructor(
|
||||||
private val settings: InternetObservingSettings,
|
private val settings: InternetObservingSettings,
|
||||||
private val local: LuckyNumberLocal,
|
private val local: LuckyNumberLocal,
|
||||||
private val remote: LuckyNumberRemote
|
private val remote: LuckyNumberRemote,
|
||||||
|
private val sdkHelper: SdkHelper
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun getLuckyNumber(student: Student, forceRefresh: Boolean = false, notify: Boolean = false): Maybe<LuckyNumber> {
|
fun getLuckyNumber(student: Student, forceRefresh: Boolean = false, notify: Boolean = false): Maybe<LuckyNumber> {
|
||||||
return local.getLuckyNumber(student, LocalDate.now()).filter { !forceRefresh }
|
return Maybe.just(sdkHelper.init(student)).flatMap {
|
||||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
local.getLuckyNumber(student, LocalDate.now()).filter { !forceRefresh }
|
||||||
.flatMapMaybe {
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
if (it) remote.getLuckyNumber(student)
|
.flatMapMaybe {
|
||||||
else Maybe.error(UnknownHostException())
|
if (it) remote.getLuckyNumber(student)
|
||||||
}.flatMap { new ->
|
else Maybe.error(UnknownHostException())
|
||||||
local.getLuckyNumber(student, LocalDate.now())
|
}.flatMap { new ->
|
||||||
.doOnSuccess { old ->
|
local.getLuckyNumber(student, LocalDate.now())
|
||||||
if (new != old) {
|
.doOnSuccess { old ->
|
||||||
local.deleteLuckyNumber(old)
|
if (new != old) {
|
||||||
|
local.deleteLuckyNumber(old)
|
||||||
|
local.saveLuckyNumber(new.apply {
|
||||||
|
if (notify) isNotified = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.doOnComplete {
|
||||||
local.saveLuckyNumber(new.apply {
|
local.saveLuckyNumber(new.apply {
|
||||||
if (notify) isNotified = false
|
if (notify) isNotified = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}.flatMap({ local.getLuckyNumber(student, LocalDate.now()) }, { Maybe.error(it) },
|
||||||
.doOnComplete {
|
{ local.getLuckyNumber(student, LocalDate.now()) })
|
||||||
local.saveLuckyNumber(new.apply {
|
)
|
||||||
if (notify) isNotified = false
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
}.flatMap({ local.getLuckyNumber(student, LocalDate.now()) }, { Maybe.error(it) },
|
|
||||||
{ local.getLuckyNumber(student, LocalDate.now()) })
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNotNotifiedLuckyNumber(student: Student): Maybe<LuckyNumber> {
|
fun getNotNotifiedLuckyNumber(student: Student): Maybe<LuckyNumber> {
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package io.github.wulkanowy.data.repositories.message
|
package io.github.wulkanowy.data.repositories.message
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED
|
import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED
|
||||||
import io.reactivex.Maybe
|
import io.reactivex.Maybe
|
||||||
@ -10,7 +13,10 @@ import javax.inject.Inject
|
|||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class MessageLocal @Inject constructor(private val messagesDb: MessagesDao) {
|
class MessageLocal @Inject constructor(
|
||||||
|
private val messagesDb: MessagesDao,
|
||||||
|
private val messageAttachmentDao: MessageAttachmentDao
|
||||||
|
) {
|
||||||
|
|
||||||
fun saveMessages(messages: List<Message>) {
|
fun saveMessages(messages: List<Message>) {
|
||||||
messagesDb.insertAll(messages)
|
messagesDb.insertAll(messages)
|
||||||
@ -24,8 +30,12 @@ class MessageLocal @Inject constructor(private val messagesDb: MessagesDao) {
|
|||||||
messagesDb.deleteAll(messages)
|
messagesDb.deleteAll(messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMessage(id: Long): Single<Message> {
|
fun getMessageWithAttachment(student: Student, message: Message): Single<MessageWithAttachment> {
|
||||||
return messagesDb.load(id)
|
return messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveMessageAttachments(attachments: List<MessageAttachment>) {
|
||||||
|
messageAttachmentDao.insertAttachments(attachments)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMessages(student: Student, folder: MessageFolder): Maybe<List<Message>> {
|
fun getMessages(student: Student, folder: MessageFolder): Maybe<List<Message>> {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package io.github.wulkanowy.data.repositories.message
|
package io.github.wulkanowy.data.repositories.message
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
@ -33,14 +34,25 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) {
|
|||||||
unread = it.unread ?: false,
|
unread = it.unread ?: false,
|
||||||
unreadBy = it.unreadBy ?: 0,
|
unreadBy = it.unreadBy ?: 0,
|
||||||
readBy = it.readBy ?: 0,
|
readBy = it.readBy ?: 0,
|
||||||
removed = it.removed
|
removed = it.removed,
|
||||||
|
hasAttachments = it.hasAttachments
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMessagesContent(message: Message, markAsRead: Boolean = false): Single<String> {
|
fun getMessagesContentDetails(message: Message, markAsRead: Boolean = false): Single<Pair<String, List<MessageAttachment>>> {
|
||||||
return sdk.getMessageContent(message.messageId, message.folderId, markAsRead, message.realId)
|
return sdk.getMessageDetails(message.messageId, message.folderId, markAsRead, message.realId).map { details ->
|
||||||
|
details.content to details.attachments.map {
|
||||||
|
MessageAttachment(
|
||||||
|
realId = it.id,
|
||||||
|
messageId = it.messageId,
|
||||||
|
oneDriveId = it.oneDriveId,
|
||||||
|
url = it.url,
|
||||||
|
filename = it.filename
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendMessage(subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> {
|
fun sendMessage(subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> {
|
||||||
|
@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
|||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
import io.github.wulkanowy.data.SdkHelper
|
import io.github.wulkanowy.data.SdkHelper
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
@ -11,7 +12,6 @@ import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
|
|||||||
import io.github.wulkanowy.sdk.pojo.SentMessage
|
import io.github.wulkanowy.sdk.pojo.SentMessage
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.Maybe
|
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -48,30 +48,31 @@ class MessageRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMessage(student: Student, messageDbId: Long, markAsRead: Boolean = false): Single<Message> {
|
fun getMessage(student: Student, message: Message, markAsRead: Boolean = false): Single<MessageWithAttachment> {
|
||||||
return Single.just(sdkHelper.init(student))
|
return Single.just(sdkHelper.init(student))
|
||||||
.flatMap { _ ->
|
.flatMap { _ ->
|
||||||
local.getMessage(messageDbId)
|
local.getMessageWithAttachment(student, message)
|
||||||
.filter {
|
.filter {
|
||||||
it.content.isNotEmpty().also { status ->
|
it.message.content.isNotEmpty().also { status ->
|
||||||
Timber.d("Message content in db empty: ${!status}")
|
Timber.d("Message content in db empty: ${!status}")
|
||||||
}
|
} && !it.message.unread
|
||||||
}
|
}
|
||||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) local.getMessage(messageDbId)
|
if (it) local.getMessageWithAttachment(student, message)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}
|
}
|
||||||
.flatMap { dbMessage ->
|
.flatMap { dbMessage ->
|
||||||
remote.getMessagesContent(dbMessage, markAsRead).doOnSuccess {
|
remote.getMessagesContentDetails(dbMessage.message, markAsRead).doOnSuccess { (downloadedMessage, attachments) ->
|
||||||
local.updateMessages(listOf(dbMessage.copy(unread = !markAsRead).apply {
|
local.updateMessages(listOf(dbMessage.message.copy(unread = !markAsRead).apply {
|
||||||
id = dbMessage.id
|
id = dbMessage.message.id
|
||||||
content = content.ifBlank { it }
|
content = content.ifBlank { downloadedMessage }
|
||||||
}))
|
}))
|
||||||
Timber.d("Message $messageDbId with blank content: ${dbMessage.content.isBlank()}, marked as read")
|
local.saveMessageAttachments(attachments)
|
||||||
|
Timber.d("Message ${message.messageId} with blank content: ${dbMessage.message.content.isBlank()}, marked as read")
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getMessage(messageDbId)
|
local.getMessageWithAttachment(student, message)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -83,10 +84,6 @@ class MessageRepository @Inject constructor(
|
|||||||
.toSingle(emptyList())
|
.toSingle(emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateMessage(message: Message): Completable {
|
|
||||||
return Completable.fromCallable { local.updateMessages(listOf(message)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateMessages(messages: List<Message>): Completable {
|
fun updateMessages(messages: List<Message>): Completable {
|
||||||
return Completable.fromCallable { local.updateMessages(messages) }
|
return Completable.fromCallable { local.updateMessages(messages) }
|
||||||
}
|
}
|
||||||
@ -99,13 +96,12 @@ class MessageRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteMessage(message: Message): Maybe<Boolean> {
|
fun deleteMessage(message: Message): Single<Boolean> {
|
||||||
return ReactiveNetwork.checkInternetConnectivity(settings)
|
return ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.deleteMessage(message)
|
if (it) remote.deleteMessage(message)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}
|
}
|
||||||
.filter { it }
|
|
||||||
.doOnSuccess {
|
.doOnSuccess {
|
||||||
if (!message.removed) local.updateMessages(listOf(message.copy(removed = true).apply {
|
if (!message.removed) local.updateMessages(listOf(message.copy(removed = true).apply {
|
||||||
id = message.id
|
id = message.id
|
||||||
|
@ -18,7 +18,11 @@ class NoteRemote @Inject constructor(private val sdk: Sdk) {
|
|||||||
studentId = semester.studentId,
|
studentId = semester.studentId,
|
||||||
date = it.date,
|
date = it.date,
|
||||||
teacher = it.teacher,
|
teacher = it.teacher,
|
||||||
|
teacherSymbol = it.teacherSymbol,
|
||||||
category = it.category,
|
category = it.category,
|
||||||
|
categoryType = it.categoryType.id,
|
||||||
|
isPointsShow = it.showPoints,
|
||||||
|
points = it.points,
|
||||||
content = it.content
|
content = it.content
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import io.github.wulkanowy.services.sync.channels.LuckyNumberChannel
|
|||||||
import io.github.wulkanowy.services.sync.channels.NewGradesChannel
|
import io.github.wulkanowy.services.sync.channels.NewGradesChannel
|
||||||
import io.github.wulkanowy.services.sync.channels.NewMessagesChannel
|
import io.github.wulkanowy.services.sync.channels.NewMessagesChannel
|
||||||
import io.github.wulkanowy.services.sync.channels.NewNotesChannel
|
import io.github.wulkanowy.services.sync.channels.NewNotesChannel
|
||||||
|
import io.github.wulkanowy.services.sync.channels.PushChannel
|
||||||
import io.github.wulkanowy.services.sync.works.AttendanceSummaryWork
|
import io.github.wulkanowy.services.sync.works.AttendanceSummaryWork
|
||||||
import io.github.wulkanowy.services.sync.works.AttendanceWork
|
import io.github.wulkanowy.services.sync.works.AttendanceWork
|
||||||
import io.github.wulkanowy.services.sync.works.CompletedLessonWork
|
import io.github.wulkanowy.services.sync.works.CompletedLessonWork
|
||||||
@ -126,4 +127,8 @@ abstract class ServicesModule {
|
|||||||
@Binds
|
@Binds
|
||||||
@IntoSet
|
@IntoSet
|
||||||
abstract fun provideNewNotesChannel(channel: NewNotesChannel): Channel
|
abstract fun provideNewNotesChannel(channel: NewNotesChannel): Channel
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoSet
|
||||||
|
abstract fun providePushChannel(channel: PushChannel): Channel
|
||||||
}
|
}
|
||||||
|
@ -5,18 +5,24 @@ import android.os.Build.VERSION_CODES.O
|
|||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.work.BackoffPolicy.EXPONENTIAL
|
import androidx.work.BackoffPolicy.EXPONENTIAL
|
||||||
import androidx.work.Constraints
|
import androidx.work.Constraints
|
||||||
|
import androidx.work.Data
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
|
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy.REPLACE
|
import androidx.work.ExistingPeriodicWorkPolicy.REPLACE
|
||||||
|
import androidx.work.ExistingWorkPolicy
|
||||||
import androidx.work.NetworkType.CONNECTED
|
import androidx.work.NetworkType.CONNECTED
|
||||||
import androidx.work.NetworkType.UNMETERED
|
import androidx.work.NetworkType.UNMETERED
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
import androidx.work.PeriodicWorkRequestBuilder
|
import androidx.work.PeriodicWorkRequestBuilder
|
||||||
|
import androidx.work.WorkInfo
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
|
import com.paulinasadowska.rxworkmanagerobservers.extensions.getWorkInfoByIdObservable
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider.Companion.APP_VERSION_CODE_KEY
|
import io.github.wulkanowy.data.db.SharedPrefProvider.Companion.APP_VERSION_CODE_KEY
|
||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
import io.github.wulkanowy.services.sync.channels.Channel
|
import io.github.wulkanowy.services.sync.channels.Channel
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import io.github.wulkanowy.utils.isHolidays
|
import io.github.wulkanowy.utils.isHolidays
|
||||||
|
import io.reactivex.Observable
|
||||||
import org.threeten.bp.LocalDate.now
|
import org.threeten.bp.LocalDate.now
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.concurrent.TimeUnit.MINUTES
|
import java.util.concurrent.TimeUnit.MINUTES
|
||||||
@ -42,13 +48,13 @@ class SyncManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sharedPrefProvider.getLong(APP_VERSION_CODE_KEY, -1L) != appInfo.versionCode.toLong()) {
|
if (sharedPrefProvider.getLong(APP_VERSION_CODE_KEY, -1L) != appInfo.versionCode.toLong()) {
|
||||||
startSyncWorker(true)
|
startPeriodicSyncWorker(true)
|
||||||
sharedPrefProvider.putLong(APP_VERSION_CODE_KEY, appInfo.versionCode.toLong(), true)
|
sharedPrefProvider.putLong(APP_VERSION_CODE_KEY, appInfo.versionCode.toLong(), true)
|
||||||
}
|
}
|
||||||
Timber.i("SyncManager was initialized")
|
Timber.i("SyncManager was initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startSyncWorker(restart: Boolean = false) {
|
fun startPeriodicSyncWorker(restart: Boolean = false) {
|
||||||
if (preferencesRepository.isServiceEnabled && !now().isHolidays) {
|
if (preferencesRepository.isServiceEnabled && !now().isHolidays) {
|
||||||
workManager.enqueueUniquePeriodicWork(SyncWorker::class.java.simpleName, if (restart) REPLACE else KEEP,
|
workManager.enqueueUniquePeriodicWork(SyncWorker::class.java.simpleName, if (restart) REPLACE else KEEP,
|
||||||
PeriodicWorkRequestBuilder<SyncWorker>(preferencesRepository.servicesInterval, MINUTES)
|
PeriodicWorkRequestBuilder<SyncWorker>(preferencesRepository.servicesInterval, MINUTES)
|
||||||
@ -61,6 +67,19 @@ class SyncManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startOneTimeSyncWorker(): Observable<WorkInfo> {
|
||||||
|
val work = OneTimeWorkRequestBuilder<SyncWorker>()
|
||||||
|
.setInputData(
|
||||||
|
Data.Builder()
|
||||||
|
.putBoolean("one_time", true)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
workManager.enqueueUniqueWork("${SyncWorker::class.java.simpleName}_one_time", ExistingWorkPolicy.REPLACE, work)
|
||||||
|
return workManager.getWorkInfoByIdObservable(work.id)
|
||||||
|
}
|
||||||
|
|
||||||
fun stopSyncWorker() {
|
fun stopSyncWorker() {
|
||||||
workManager.cancelUniqueWork(SyncWorker::class.java.simpleName)
|
workManager.cancelUniqueWork(SyncWorker::class.java.simpleName)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package io.github.wulkanowy.services.sync
|
package io.github.wulkanowy.services.sync
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Build.VERSION_CODES.LOLLIPOP
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationCompat.BigTextStyle
|
import androidx.core.app.NotificationCompat.BigTextStyle
|
||||||
import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT
|
import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import androidx.work.Data
|
||||||
import androidx.work.ListenableWorker
|
import androidx.work.ListenableWorker
|
||||||
import androidx.work.RxWorker
|
import androidx.work.RxWorker
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
@ -17,6 +19,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
|||||||
import io.github.wulkanowy.sdk.exception.FeatureDisabledException
|
import io.github.wulkanowy.sdk.exception.FeatureDisabledException
|
||||||
import io.github.wulkanowy.services.sync.channels.DebugChannel
|
import io.github.wulkanowy.services.sync.channels.DebugChannel
|
||||||
import io.github.wulkanowy.services.sync.works.Work
|
import io.github.wulkanowy.services.sync.works.Work
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
@ -30,7 +33,8 @@ class SyncWorker @AssistedInject constructor(
|
|||||||
private val semesterRepository: SemesterRepository,
|
private val semesterRepository: SemesterRepository,
|
||||||
private val works: Set<@JvmSuppressWildcards Work>,
|
private val works: Set<@JvmSuppressWildcards Work>,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val notificationManager: NotificationManagerCompat
|
private val notificationManager: NotificationManagerCompat,
|
||||||
|
private val appInfo: AppInfo
|
||||||
) : RxWorker(appContext, workerParameters) {
|
) : RxWorker(appContext, workerParameters) {
|
||||||
|
|
||||||
override fun createWork(): Single<Result> {
|
override fun createWork(): Single<Result> {
|
||||||
@ -52,8 +56,15 @@ class SyncWorker @AssistedInject constructor(
|
|||||||
.toSingleDefault(Result.success())
|
.toSingleDefault(Result.success())
|
||||||
.onErrorReturn {
|
.onErrorReturn {
|
||||||
Timber.e(it, "There was an error during synchronization")
|
Timber.e(it, "There was an error during synchronization")
|
||||||
if (it is FeatureDisabledException) Result.success()
|
when {
|
||||||
else Result.retry()
|
it is FeatureDisabledException -> Result.success()
|
||||||
|
inputData.getBoolean("one_time", false) -> {
|
||||||
|
Result.failure(Data.Builder()
|
||||||
|
.putString("error", it.toString())
|
||||||
|
.build())
|
||||||
|
}
|
||||||
|
else -> Result.retry()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.doOnSuccess {
|
.doOnSuccess {
|
||||||
if (preferencesRepository.isDebugNotificationEnable) notify(it)
|
if (preferencesRepository.isDebugNotificationEnable) notify(it)
|
||||||
@ -64,7 +75,7 @@ class SyncWorker @AssistedInject constructor(
|
|||||||
private fun notify(result: Result) {
|
private fun notify(result: Result) {
|
||||||
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(applicationContext, DebugChannel.CHANNEL_ID)
|
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(applicationContext, DebugChannel.CHANNEL_ID)
|
||||||
.setContentTitle("Debug notification")
|
.setContentTitle("Debug notification")
|
||||||
.setSmallIcon(R.drawable.ic_more_settings)
|
.setSmallIcon(R.drawable.ic_stat_push)
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setColor(applicationContext.getCompatColor(R.color.colorPrimary))
|
.setColor(applicationContext.getCompatColor(R.color.colorPrimary))
|
||||||
.setStyle(BigTextStyle().bigText("${SyncWorker::class.java.simpleName} result: $result"))
|
.setStyle(BigTextStyle().bigText("${SyncWorker::class.java.simpleName} result: $result"))
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package io.github.wulkanowy.services.sync.channels
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.app.Notification
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@TargetApi(26)
|
||||||
|
class PushChannel @Inject constructor(
|
||||||
|
private val notificationManager: NotificationManagerCompat,
|
||||||
|
private val context: Context
|
||||||
|
) : Channel {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val CHANNEL_ID = "push_channel"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun create() {
|
||||||
|
notificationManager.createNotificationChannel(
|
||||||
|
NotificationChannel(CHANNEL_ID, context.getString(R.string.channel_push), NotificationManager.IMPORTANCE_HIGH)
|
||||||
|
.apply {
|
||||||
|
enableLights(true)
|
||||||
|
enableVibration(true)
|
||||||
|
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package io.github.wulkanowy.ui.base
|
package io.github.wulkanowy.ui.base
|
||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import com.readystatesoftware.chuck.api.ChuckCollector
|
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
||||||
import io.github.wulkanowy.sdk.exception.BadCredentialsException
|
import io.github.wulkanowy.sdk.exception.BadCredentialsException
|
||||||
@ -15,7 +15,7 @@ import java.net.SocketTimeoutException
|
|||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
open class ErrorHandler @Inject constructor(protected val resources: Resources, private val chuckCollector: ChuckCollector) {
|
open class ErrorHandler @Inject constructor(protected val resources: Resources, private val chuckerCollector: ChuckerCollector) {
|
||||||
|
|
||||||
var showErrorMessage: (String, Throwable) -> Unit = { _, _ -> }
|
var showErrorMessage: (String, Throwable) -> Unit = { _, _ -> }
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ open class ErrorHandler @Inject constructor(protected val resources: Resources,
|
|||||||
var onNoCurrentStudent: () -> Unit = {}
|
var onNoCurrentStudent: () -> Unit = {}
|
||||||
|
|
||||||
fun dispatch(error: Throwable) {
|
fun dispatch(error: Throwable) {
|
||||||
chuckCollector.onError(error.javaClass.simpleName, error)
|
chuckerCollector.onError(error.javaClass.simpleName, error)
|
||||||
Timber.e(error, "An exception occurred while the Wulkanowy was running")
|
Timber.e(error, "An exception occurred while the Wulkanowy was running")
|
||||||
proceed(error)
|
proceed(error)
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
package io.github.wulkanowy.ui.modules.about
|
package io.github.wulkanowy.ui.modules.about
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.Intent.ACTION_SENDTO
|
|
||||||
import android.content.Intent.EXTRA_EMAIL
|
|
||||||
import android.content.Intent.EXTRA_SUBJECT
|
|
||||||
import android.content.Intent.EXTRA_TEXT
|
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -23,6 +17,7 @@ import io.github.wulkanowy.ui.modules.main.MainActivity
|
|||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import io.github.wulkanowy.utils.getCompatDrawable
|
import io.github.wulkanowy.utils.getCompatDrawable
|
||||||
|
import io.github.wulkanowy.utils.openEmailClient
|
||||||
import io.github.wulkanowy.utils.openInternetBrowser
|
import io.github.wulkanowy.utils.openInternetBrowser
|
||||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||||
import kotlinx.android.synthetic.main.fragment_about.*
|
import kotlinx.android.synthetic.main.fragment_about.*
|
||||||
@ -124,26 +119,17 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun openEmailClient() {
|
override fun openEmailClient() {
|
||||||
val intent = Intent(ACTION_SENDTO)
|
requireContext().openEmailClient(
|
||||||
.apply {
|
chooserTitle = getString(R.string.about_feedback),
|
||||||
data = Uri.parse("mailto:")
|
email = "wulkanowyinc@gmail.com",
|
||||||
putExtra(EXTRA_EMAIL, arrayOf("wulkanowyinc@gmail.com"))
|
subject = "Zgłoszenie błędu",
|
||||||
putExtra(EXTRA_SUBJECT, "Zgłoszenie błędu")
|
body = requireContext().getString(R.string.about_feedback_template,
|
||||||
putExtra(EXTRA_TEXT, "Tu umieść treść zgłoszenia\n\n${"-".repeat(40)}\n " +
|
"${appInfo.systemManufacturer} ${appInfo.systemModel}", appInfo.systemVersion.toString(), appInfo.versionName
|
||||||
"""
|
),
|
||||||
Build: ${appInfo.versionCode}
|
onActivityNotFound = {
|
||||||
SDK: ${appInfo.systemVersion}
|
requireContext().openInternetBrowser("https://github.com/wulkanowy/wulkanowy/issues", ::showMessage)
|
||||||
Device: ${appInfo.systemManufacturer} ${appInfo.systemModel}
|
|
||||||
""".trimIndent())
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
context?.let {
|
|
||||||
if (intent.resolveActivity(it.packageManager) != null) {
|
|
||||||
startActivity(Intent.createChooser(intent, getString(R.string.about_feedback)))
|
|
||||||
} else {
|
|
||||||
it.openInternetBrowser("https://github.com/wulkanowy/wulkanowy/issues", ::showMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openFaqPage() {
|
override fun openFaqPage() {
|
||||||
|
@ -19,7 +19,7 @@ class LicenseItem(val library: Library) : AbstractFlexibleItem<LicenseItem.ViewH
|
|||||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||||
with(holder) {
|
with(holder) {
|
||||||
licenseItemName.text = library.libraryName
|
licenseItemName.text = library.libraryName
|
||||||
licenseItemSummary.text = library.license?.licenseName
|
licenseItemSummary.text = library.license?.licenseName?.takeIf { it.isNotBlank() } ?: library.libraryVersion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +27,6 @@ class LicensePresenter @Inject constructor(
|
|||||||
|
|
||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
disposable.add(Single.fromCallable { view?.appLibraries }
|
disposable.add(Single.fromCallable { view?.appLibraries }
|
||||||
.map {
|
|
||||||
val exclude = listOf("Android-Iconics", "CircleImageView", "FastAdapter", "Jsoup", "okio", "Retrofit")
|
|
||||||
it.filter { library -> !exclude.contains(library.libraryName) }
|
|
||||||
}
|
|
||||||
.map { it.map { library -> LicenseItem(library) } }
|
.map { it.map { library -> LicenseItem(library) } }
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
.observeOn(schedulers.mainThread)
|
.observeOn(schedulers.mainThread)
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
package io.github.wulkanowy.ui.modules.homework
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import io.github.wulkanowy.R
|
|
||||||
import io.github.wulkanowy.data.db.entities.Homework
|
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
|
||||||
import kotlinx.android.synthetic.main.dialog_homework.*
|
|
||||||
|
|
||||||
class HomeworkDialog : DialogFragment() {
|
|
||||||
|
|
||||||
private lateinit var homework: Homework
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val ARGUMENT_KEY = "Item"
|
|
||||||
|
|
||||||
fun newInstance(homework: Homework): HomeworkDialog {
|
|
||||||
return HomeworkDialog().apply {
|
|
||||||
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, homework) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
|
||||||
arguments?.run {
|
|
||||||
homework = getSerializable(HomeworkDialog.ARGUMENT_KEY) as Homework
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
|
||||||
return inflater.inflate(R.layout.dialog_homework, container, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
|
|
||||||
homeworkDialogDate.text = homework.date.toFormattedString()
|
|
||||||
homeworkDialogEntryDate.text = homework.entryDate.toFormattedString()
|
|
||||||
homeworkDialogSubject.text = homework.subject
|
|
||||||
homeworkDialogTeacher.text = homework.teacher
|
|
||||||
homeworkDialogContent.text = homework.content
|
|
||||||
homeworkDialogClose.setOnClickListener { dismiss() }
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,6 +13,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
|||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Homework
|
import io.github.wulkanowy.data.db.entities.Homework
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.homework.details.HomeworkDetailsDialog
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.github.wulkanowy.utils.dpToPx
|
import io.github.wulkanowy.utils.dpToPx
|
||||||
@ -73,6 +74,10 @@ class HomeworkFragment : BaseFragment(), HomeworkView, MainView.TitledView {
|
|||||||
homeworkAdapter.updateDataSet(data, true)
|
homeworkAdapter.updateDataSet(data, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onReloadList() {
|
||||||
|
presenter.reloadData()
|
||||||
|
}
|
||||||
|
|
||||||
override fun clearData() {
|
override fun clearData() {
|
||||||
homeworkAdapter.clear()
|
homeworkAdapter.clear()
|
||||||
}
|
}
|
||||||
@ -118,7 +123,7 @@ class HomeworkFragment : BaseFragment(), HomeworkView, MainView.TitledView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showTimetableDialog(homework: Homework) {
|
override fun showTimetableDialog(homework: Homework) {
|
||||||
(activity as? MainActivity)?.showDialogFragment(HomeworkDialog.newInstance(homework))
|
(activity as? MainActivity)?.showDialogFragment(HomeworkDetailsDialog.newInstance(homework))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
@ -24,6 +24,8 @@ class HomeworkItem(header: HomeworkHeader, val homework: Homework) :
|
|||||||
homeworkItemSubject.text = homework.subject
|
homeworkItemSubject.text = homework.subject
|
||||||
homeworkItemTeacher.text = homework.teacher
|
homeworkItemTeacher.text = homework.teacher
|
||||||
homeworkItemContent.text = homework.content
|
homeworkItemContent.text = homework.content
|
||||||
|
homeworkItemCheckImage.visibility = if (homework.isDone) View.VISIBLE else View.GONE
|
||||||
|
homeworkItemAttachmentImage.visibility = if (!homework.isDone && homework.attachments.isNotEmpty()) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +45,8 @@ class HomeworkItem(header: HomeworkHeader, val homework: Homework) :
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) :
|
||||||
|
FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||||
override val containerView: View
|
override val containerView: View
|
||||||
get() = contentView
|
get() = contentView
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,10 @@ class HomeworkPresenter @Inject constructor(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun reloadData() {
|
||||||
|
loadData(currentDate, false)
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
|
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
|
||||||
Timber.i("Loading homework data started")
|
Timber.i("Loading homework data started")
|
||||||
currentDate = date
|
currentDate = date
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.homework.details
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.text.HtmlCompat
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Homework
|
||||||
|
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
import kotlinx.android.synthetic.main.dialog_homework.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class HomeworkDetailsDialog : BaseDialogFragment(), HomeworkDetailsView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: HomeworkDetailsPresenter
|
||||||
|
|
||||||
|
private lateinit var homework: Homework
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ARGUMENT_KEY = "Item"
|
||||||
|
|
||||||
|
fun newInstance(homework: Homework): HomeworkDetailsDialog {
|
||||||
|
return HomeworkDetailsDialog().apply {
|
||||||
|
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, homework) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(STYLE_NO_TITLE, 0)
|
||||||
|
arguments?.run {
|
||||||
|
homework = getSerializable(ARGUMENT_KEY) as Homework
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
return inflater.inflate(R.layout.dialog_homework, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun initView() {
|
||||||
|
homeworkDialogDate.text = homework.date.toFormattedString()
|
||||||
|
homeworkDialogEntryDate.text = homework.entryDate.toFormattedString()
|
||||||
|
homeworkDialogSubject.text = homework.subject
|
||||||
|
homeworkDialogTeacher.text = homework.teacher
|
||||||
|
homeworkDialogContent.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
homeworkDialogContent.text = homework.content
|
||||||
|
homeworkDialogAttachments.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
homeworkDialogAttachments.text = HtmlCompat.fromHtml(homework.attachments.joinToString("<br>") {
|
||||||
|
"<a href='${it.first}'>${it.second}</a>"
|
||||||
|
}, HtmlCompat.FROM_HTML_MODE_COMPACT).ifBlank { getString(R.string.all_no_data) }
|
||||||
|
|
||||||
|
homeworkDialogRead.text = view?.context?.getString(if (homework.isDone) R.string.homework_mark_as_undone else R.string.homework_mark_as_done)
|
||||||
|
homeworkDialogRead.setOnClickListener { presenter.toggleDone(homework) }
|
||||||
|
homeworkDialogClose.setOnClickListener { dismiss() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateMarkAsDoneLabel(isDone: Boolean) {
|
||||||
|
(parentFragment as? HomeworkFragment)?.onReloadList()
|
||||||
|
homeworkDialogRead.text = view?.context?.getString(if (isDone) R.string.homework_mark_as_undone else R.string.homework_mark_as_done)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
presenter.onDetachView()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.homework.details
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Homework
|
||||||
|
import io.github.wulkanowy.data.repositories.homework.HomeworkRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class HomeworkDetailsPresenter @Inject constructor(
|
||||||
|
schedulers: SchedulersProvider,
|
||||||
|
errorHandler: ErrorHandler,
|
||||||
|
studentRepository: StudentRepository,
|
||||||
|
private val homeworkRepository: HomeworkRepository,
|
||||||
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
|
) : BasePresenter<HomeworkDetailsView>(errorHandler, studentRepository, schedulers) {
|
||||||
|
|
||||||
|
override fun onAttachView(view: HomeworkDetailsView) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
view.initView()
|
||||||
|
Timber.i("Homework details view was initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleDone(homework: Homework) {
|
||||||
|
Timber.i("Homework details update start")
|
||||||
|
disposable.add(homeworkRepository.toggleDone(homework)
|
||||||
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
|
.observeOn(schedulers.mainThread)
|
||||||
|
.subscribe({
|
||||||
|
Timber.i("Homework details update: Success")
|
||||||
|
view?.run {
|
||||||
|
updateMarkAsDoneLabel(homework.isDone)
|
||||||
|
}
|
||||||
|
analytics.logEvent("homework_mark_as_done")
|
||||||
|
}) {
|
||||||
|
Timber.i("Homework details update result: An exception occurred")
|
||||||
|
errorHandler.dispatch(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.homework.details
|
||||||
|
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
|
interface HomeworkDetailsView : BaseView {
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun updateMarkAsDoneLabel(isDone: Boolean)
|
||||||
|
}
|
@ -2,7 +2,7 @@ package io.github.wulkanowy.ui.modules.login
|
|||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.database.sqlite.SQLiteConstraintException
|
import android.database.sqlite.SQLiteConstraintException
|
||||||
import com.readystatesoftware.chuck.api.ChuckCollector
|
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.sdk.exception.BadCredentialsException
|
import io.github.wulkanowy.sdk.exception.BadCredentialsException
|
||||||
import io.github.wulkanowy.sdk.mobile.exception.InvalidPinException
|
import io.github.wulkanowy.sdk.mobile.exception.InvalidPinException
|
||||||
@ -14,8 +14,8 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class LoginErrorHandler @Inject constructor(
|
class LoginErrorHandler @Inject constructor(
|
||||||
resources: Resources,
|
resources: Resources,
|
||||||
chuckCollector: ChuckCollector
|
chuckerCollector: ChuckerCollector
|
||||||
) : ErrorHandler(resources, chuckCollector) {
|
) : ErrorHandler(resources, chuckerCollector) {
|
||||||
|
|
||||||
var onBadCredentials: () -> Unit = {}
|
var onBadCredentials: () -> Unit = {}
|
||||||
|
|
||||||
|
@ -146,6 +146,20 @@ class LoginAdvancedFragment : BaseFragment(), LoginAdvancedView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setErrorLoginRequired() {
|
||||||
|
with(loginFormUsernameLayout) {
|
||||||
|
requestFocus()
|
||||||
|
error = getString(R.string.login_invalid_login)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setErrorEmailRequired() {
|
||||||
|
with(loginFormUsernameLayout) {
|
||||||
|
requestFocus()
|
||||||
|
error = getString(R.string.login_invalid_email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun setErrorPassRequired(focus: Boolean) {
|
override fun setErrorPassRequired(focus: Boolean) {
|
||||||
with(loginFormPassLayout) {
|
with(loginFormPassLayout) {
|
||||||
if (focus) requestFocus()
|
if (focus) requestFocus()
|
||||||
|
@ -173,6 +173,8 @@ class LoginAdvancedPresenter @Inject constructor(
|
|||||||
val login = view?.formUsernameValue.orEmpty()
|
val login = view?.formUsernameValue.orEmpty()
|
||||||
val password = view?.formPassValue.orEmpty()
|
val password = view?.formPassValue.orEmpty()
|
||||||
|
|
||||||
|
val host = view?.formHostValue.orEmpty()
|
||||||
|
|
||||||
val pin = view?.formPinValue.orEmpty()
|
val pin = view?.formPinValue.orEmpty()
|
||||||
val symbol = view?.formSymbolValue.orEmpty()
|
val symbol = view?.formSymbolValue.orEmpty()
|
||||||
val token = view?.formTokenValue.orEmpty()
|
val token = view?.formTokenValue.orEmpty()
|
||||||
@ -196,26 +198,20 @@ class LoginAdvancedPresenter @Inject constructor(
|
|||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Sdk.Mode.SCRAPPER -> {
|
Sdk.Mode.HYBRID, Sdk.Mode.SCRAPPER -> {
|
||||||
if (login.isEmpty()) {
|
if (login.isEmpty()) {
|
||||||
view?.setErrorUsernameRequired()
|
view?.setErrorUsernameRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
} else {
|
||||||
|
if ("@" in login && "standard" !in host) {
|
||||||
|
view?.setErrorLoginRequired()
|
||||||
|
isCorrect = false
|
||||||
|
}
|
||||||
|
|
||||||
if (password.isEmpty()) {
|
if ("@" !in login && "standard" in host) {
|
||||||
view?.setErrorPassRequired(focus = isCorrect)
|
view?.setErrorEmailRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password.length < 6 && password.isNotEmpty()) {
|
|
||||||
view?.setErrorPassInvalid(focus = isCorrect)
|
|
||||||
isCorrect = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Sdk.Mode.HYBRID -> {
|
|
||||||
if (login.isEmpty()) {
|
|
||||||
view?.setErrorUsernameRequired()
|
|
||||||
isCorrect = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password.isEmpty()) {
|
if (password.isEmpty()) {
|
||||||
|
@ -41,6 +41,10 @@ interface LoginAdvancedView : BaseView {
|
|||||||
|
|
||||||
fun setErrorUsernameRequired()
|
fun setErrorUsernameRequired()
|
||||||
|
|
||||||
|
fun setErrorLoginRequired()
|
||||||
|
|
||||||
|
fun setErrorEmailRequired()
|
||||||
|
|
||||||
fun setErrorPassRequired(focus: Boolean)
|
fun setErrorPassRequired(focus: Boolean)
|
||||||
|
|
||||||
fun setErrorPassInvalid(focus: Boolean)
|
fun setErrorPassInvalid(focus: Boolean)
|
||||||
|
@ -121,6 +121,20 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setErrorLoginRequired() {
|
||||||
|
with(loginFormUsernameLayout) {
|
||||||
|
requestFocus()
|
||||||
|
error = getString(R.string.login_invalid_login)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setErrorEmailRequired() {
|
||||||
|
with(loginFormUsernameLayout) {
|
||||||
|
requestFocus()
|
||||||
|
error = getString(R.string.login_invalid_email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun setErrorSymbolRequired(focus: Boolean) {
|
override fun setErrorSymbolRequired(focus: Boolean) {
|
||||||
with(loginFormSymbolLayout) {
|
with(loginFormSymbolLayout) {
|
||||||
if (focus) requestFocus()
|
if (focus) requestFocus()
|
||||||
@ -219,12 +233,18 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openEmail() {
|
override fun openEmail(lastError: String) {
|
||||||
context?.openEmailClient(
|
context?.openEmailClient(
|
||||||
requireContext().getString(R.string.login_email_intent_title),
|
chooserTitle = requireContext().getString(R.string.login_email_intent_title),
|
||||||
"wulkanowyinc@gmail.com",
|
email = "wulkanowyinc@gmail.com",
|
||||||
requireContext().getString(R.string.login_email_subject),
|
subject = requireContext().getString(R.string.login_email_subject),
|
||||||
requireContext().getString(R.string.login_email_text, appInfo.systemModel, appInfo.systemVersion.toString(), appInfo.versionName)
|
body = requireContext().getString(R.string.login_email_text,
|
||||||
|
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
|
||||||
|
appInfo.systemVersion.toString(),
|
||||||
|
appInfo.versionName,
|
||||||
|
"$formHostValue/$formSymbolValue",
|
||||||
|
lastError
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
private val analytics: FirebaseAnalyticsHelper
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
) : BasePresenter<LoginFormView>(loginErrorHandler, studentRepository, schedulers) {
|
) : BasePresenter<LoginFormView>(loginErrorHandler, studentRepository, schedulers) {
|
||||||
|
|
||||||
|
private var lastError: Throwable? = null
|
||||||
|
|
||||||
override fun onAttachView(view: LoginFormView) {
|
override fun onAttachView(view: LoginFormView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.run {
|
view.run {
|
||||||
@ -109,6 +111,7 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
Timber.i("Login result: An exception occurred")
|
Timber.i("Login result: An exception occurred")
|
||||||
analytics.logEvent("registration_form", "success" to false, "students" to -1, "scrapperBaseUrl" to host, "error" to it.message.ifNullOrBlank { "No message" })
|
analytics.logEvent("registration_form", "success" to false, "students" to -1, "scrapperBaseUrl" to host, "error" to it.message.ifNullOrBlank { "No message" })
|
||||||
loginErrorHandler.dispatch(it)
|
loginErrorHandler.dispatch(it)
|
||||||
|
lastError = it
|
||||||
view?.showContact(true)
|
view?.showContact(true)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -118,7 +121,7 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onEmailClick() {
|
fun onEmailClick() {
|
||||||
view?.openEmail()
|
view?.openEmail(lastError?.message.ifNullOrBlank { "none" })
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onRecoverClick() {
|
fun onRecoverClick() {
|
||||||
@ -131,6 +134,16 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
if (login.isEmpty()) {
|
if (login.isEmpty()) {
|
||||||
view?.setErrorUsernameRequired()
|
view?.setErrorUsernameRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
|
} else {
|
||||||
|
if ("@" in login && "standard" !in host) {
|
||||||
|
view?.setErrorLoginRequired()
|
||||||
|
isCorrect = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("@" !in login && "standard" in host) {
|
||||||
|
view?.setErrorEmailRequired()
|
||||||
|
isCorrect = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password.isEmpty()) {
|
if (password.isEmpty()) {
|
||||||
|
@ -31,6 +31,10 @@ interface LoginFormView : BaseView {
|
|||||||
|
|
||||||
fun setErrorUsernameRequired()
|
fun setErrorUsernameRequired()
|
||||||
|
|
||||||
|
fun setErrorLoginRequired()
|
||||||
|
|
||||||
|
fun setErrorEmailRequired()
|
||||||
|
|
||||||
fun setErrorSymbolRequired(focus: Boolean)
|
fun setErrorSymbolRequired(focus: Boolean)
|
||||||
|
|
||||||
fun setErrorPassRequired(focus: Boolean)
|
fun setErrorPassRequired(focus: Boolean)
|
||||||
@ -63,7 +67,7 @@ interface LoginFormView : BaseView {
|
|||||||
|
|
||||||
fun openFaqPage()
|
fun openFaqPage()
|
||||||
|
|
||||||
fun openEmail()
|
fun openEmail(lastError: String)
|
||||||
|
|
||||||
fun openAdvancedLogin()
|
fun openAdvancedLogin()
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package io.github.wulkanowy.ui.modules.login.recover
|
package io.github.wulkanowy.ui.modules.login.recover
|
||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import com.readystatesoftware.chuck.api.ChuckCollector
|
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||||
import io.github.wulkanowy.sdk.scrapper.exception.InvalidCaptchaException
|
import io.github.wulkanowy.sdk.scrapper.exception.InvalidCaptchaException
|
||||||
import io.github.wulkanowy.sdk.scrapper.exception.InvalidEmailException
|
import io.github.wulkanowy.sdk.scrapper.exception.InvalidEmailException
|
||||||
import io.github.wulkanowy.sdk.scrapper.exception.NoAccountFoundException
|
import io.github.wulkanowy.sdk.scrapper.exception.NoAccountFoundException
|
||||||
@ -10,8 +10,8 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class RecoverErrorHandler @Inject constructor(
|
class RecoverErrorHandler @Inject constructor(
|
||||||
resources: Resources,
|
resources: Resources,
|
||||||
chuckCollector: ChuckCollector
|
chuckerCollector: ChuckerCollector
|
||||||
) : ErrorHandler(resources, chuckCollector) {
|
) : ErrorHandler(resources, chuckerCollector) {
|
||||||
|
|
||||||
var onInvalidUsername: (String) -> Unit = {}
|
var onInvalidUsername: (String) -> Unit = {}
|
||||||
|
|
||||||
|
@ -101,12 +101,17 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView {
|
|||||||
context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage)
|
context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openEmail() {
|
override fun openEmail(lastError: String) {
|
||||||
context?.openEmailClient(
|
context?.openEmailClient(
|
||||||
requireContext().getString(R.string.login_email_intent_title),
|
chooserTitle = requireContext().getString(R.string.login_email_intent_title),
|
||||||
"wulkanowyinc@gmail.com",
|
email = "wulkanowyinc@gmail.com",
|
||||||
requireContext().getString(R.string.login_email_subject),
|
subject = requireContext().getString(R.string.login_email_subject),
|
||||||
requireContext().getString(R.string.login_email_text, appInfo.systemModel, appInfo.systemVersion.toString(), appInfo.versionName)
|
body = requireContext().getString(R.string.login_email_text, appInfo.systemModel,
|
||||||
|
appInfo.systemVersion.toString(),
|
||||||
|
appInfo.versionName,
|
||||||
|
"Select users to log in",
|
||||||
|
lastError
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
|||||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||||
import io.reactivex.Single
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -20,6 +19,8 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
private val analytics: FirebaseAnalyticsHelper
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
) : BasePresenter<LoginStudentSelectView>(loginErrorHandler, studentRepository, schedulers) {
|
) : BasePresenter<LoginStudentSelectView>(loginErrorHandler, studentRepository, schedulers) {
|
||||||
|
|
||||||
|
private var lastError: Throwable? = null
|
||||||
|
|
||||||
var students = emptyList<Student>()
|
var students = emptyList<Student>()
|
||||||
|
|
||||||
private var selectedStudents = mutableListOf<Student>()
|
private var selectedStudents = mutableListOf<Student>()
|
||||||
@ -83,6 +84,7 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
})
|
})
|
||||||
}, {
|
}, {
|
||||||
errorHandler.dispatch(it)
|
errorHandler.dispatch(it)
|
||||||
|
lastError = it
|
||||||
view?.updateData(students.map { student -> LoginStudentSelectItem(student, false) })
|
view?.updateData(students.map { student -> LoginStudentSelectItem(student, false) })
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -109,6 +111,7 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
students.forEach { analytics.logEvent("registration_student_select", "success" to false, "scrapperBaseUrl" to it.scrapperBaseUrl, "symbol" to it.symbol, "error" to error.message.ifNullOrBlank { "No message" }) }
|
students.forEach { analytics.logEvent("registration_student_select", "success" to false, "scrapperBaseUrl" to it.scrapperBaseUrl, "symbol" to it.symbol, "error" to error.message.ifNullOrBlank { "No message" }) }
|
||||||
Timber.i("Registration result: An exception occurred ")
|
Timber.i("Registration result: An exception occurred ")
|
||||||
loginErrorHandler.dispatch(error)
|
loginErrorHandler.dispatch(error)
|
||||||
|
lastError = error
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showProgress(false)
|
showProgress(false)
|
||||||
showContent(true)
|
showContent(true)
|
||||||
@ -122,6 +125,6 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onEmailClick() {
|
fun onEmailClick() {
|
||||||
view?.openEmail()
|
view?.openEmail(lastError?.message.ifNullOrBlank { "empty" })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,5 +20,5 @@ interface LoginStudentSelectView : BaseView {
|
|||||||
|
|
||||||
fun openDiscordInvite()
|
fun openDiscordInvite()
|
||||||
|
|
||||||
fun openEmail()
|
fun openEmail(lastError: String)
|
||||||
}
|
}
|
||||||
|
@ -130,12 +130,18 @@ class LoginSymbolFragment : BaseFragment(), LoginSymbolView {
|
|||||||
context?.openInternetBrowser("https://wulkanowy.github.io/czesto-zadawane-pytania/co-to-jest-symbol", ::showMessage)
|
context?.openInternetBrowser("https://wulkanowy.github.io/czesto-zadawane-pytania/co-to-jest-symbol", ::showMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openEmail() {
|
override fun openEmail(host: String, lastError: String) {
|
||||||
context?.openEmailClient(
|
context?.openEmailClient(
|
||||||
requireContext().getString(R.string.login_email_intent_title),
|
chooserTitle = requireContext().getString(R.string.login_email_intent_title),
|
||||||
"wulkanowyinc@gmail.com",
|
email = "wulkanowyinc@gmail.com",
|
||||||
requireContext().getString(R.string.login_email_subject),
|
subject = requireContext().getString(R.string.login_email_subject),
|
||||||
requireContext().getString(R.string.login_email_text, appInfo.systemModel, appInfo.systemVersion.toString(), appInfo.versionName)
|
body = requireContext().getString(R.string.login_email_text,
|
||||||
|
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
|
||||||
|
appInfo.systemVersion.toString(),
|
||||||
|
appInfo.versionName,
|
||||||
|
"$host/${loginSymbolName.text}",
|
||||||
|
lastError
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ class LoginSymbolPresenter @Inject constructor(
|
|||||||
private val analytics: FirebaseAnalyticsHelper
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
) : BasePresenter<LoginSymbolView>(loginErrorHandler, studentRepository, schedulers) {
|
) : BasePresenter<LoginSymbolView>(loginErrorHandler, studentRepository, schedulers) {
|
||||||
|
|
||||||
|
private var lastError: Throwable? = null
|
||||||
|
|
||||||
var loginData: Triple<String, String, String>? = null
|
var loginData: Triple<String, String, String>? = null
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
@ -37,13 +39,15 @@ class LoginSymbolPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun attemptLogin(symbol: String) {
|
fun attemptLogin(symbol: String) {
|
||||||
|
if (loginData == null) throw IllegalArgumentException("Login data is null")
|
||||||
|
|
||||||
if (symbol.isBlank()) {
|
if (symbol.isBlank()) {
|
||||||
view?.setErrorSymbolRequire()
|
view?.setErrorSymbolRequire()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
disposable.add(
|
disposable.add(
|
||||||
Single.fromCallable { if (loginData == null) throw IllegalArgumentException("Login data is null") else loginData }
|
Single.fromCallable { loginData }
|
||||||
.flatMap { studentRepository.getStudentsScrapper(it.first, it.second, it.third, symbol) }
|
.flatMap { studentRepository.getStudentsScrapper(it.first, it.second, it.third, symbol) }
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
.observeOn(schedulers.mainThread)
|
.observeOn(schedulers.mainThread)
|
||||||
@ -77,6 +81,7 @@ class LoginSymbolPresenter @Inject constructor(
|
|||||||
Timber.i("Login with symbol result: An exception occurred")
|
Timber.i("Login with symbol result: An exception occurred")
|
||||||
analytics.logEvent("registration_symbol", "success" to false, "students" to -1, "scrapperBaseUrl" to loginData?.third, "symbol" to symbol, "error" to it.message.ifNullOrBlank { "No message" })
|
analytics.logEvent("registration_symbol", "success" to false, "students" to -1, "scrapperBaseUrl" to loginData?.third, "symbol" to symbol, "error" to it.message.ifNullOrBlank { "No message" })
|
||||||
loginErrorHandler.dispatch(it)
|
loginErrorHandler.dispatch(it)
|
||||||
|
lastError = it
|
||||||
view?.showContact(true)
|
view?.showContact(true)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -94,6 +99,6 @@ class LoginSymbolPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onEmailClick() {
|
fun onEmailClick() {
|
||||||
view?.openEmail()
|
view?.openEmail(loginData?.third.orEmpty(), lastError?.message.ifNullOrBlank { "empty" })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,5 +31,5 @@ interface LoginSymbolView : BaseView {
|
|||||||
|
|
||||||
fun openFaqPage()
|
fun openFaqPage()
|
||||||
|
|
||||||
fun openEmail()
|
fun openEmail(host: String, lastError: String)
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
|||||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeModule
|
import io.github.wulkanowy.ui.modules.grade.GradeModule
|
||||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.homework.details.HomeworkDetailsDialog
|
||||||
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageModule
|
import io.github.wulkanowy.ui.modules.message.MessageModule
|
||||||
@ -98,6 +99,10 @@ abstract class MainModule {
|
|||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindHomeworkFragment(): HomeworkFragment
|
abstract fun bindHomeworkFragment(): HomeworkFragment
|
||||||
|
|
||||||
|
@PerFragment
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindHomeworkDetailsDialog(): HomeworkDetailsDialog
|
||||||
|
|
||||||
@PerFragment
|
@PerFragment
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindLuckyNumberFragment(): LuckyNumberFragment
|
abstract fun bindLuckyNumberFragment(): LuckyNumberFragment
|
||||||
|
@ -33,7 +33,7 @@ class MainPresenter @Inject constructor(
|
|||||||
Timber.i("Main view was initialized with $startMenuIndex menu index and $startMenuMoreIndex more index")
|
Timber.i("Main view was initialized with $startMenuIndex menu index and $startMenuMoreIndex more index")
|
||||||
}
|
}
|
||||||
|
|
||||||
syncManager.startSyncWorker()
|
syncManager.startPeriodicSyncWorker()
|
||||||
analytics.logEvent("app_open", "destination" to initMenu?.name)
|
analytics.logEvent("app_open", "destination" to initMenu?.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,9 @@ class MessageItem(val message: Message, private val noSubjectString: String) :
|
|||||||
text = message.date.toFormattedString()
|
text = message.date.toFormattedString()
|
||||||
setTypeface(null, style)
|
setTypeface(null, style)
|
||||||
}
|
}
|
||||||
|
with(messageItemAttachmentIcon) {
|
||||||
|
visibility = if (message.hasAttachments) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +59,8 @@ class MessageItem(val message: Message, private val noSubjectString: String) :
|
|||||||
return message.hashCode()
|
return message.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) :
|
||||||
|
FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||||
override val containerView: View
|
override val containerView: View
|
||||||
get() = contentView
|
get() = contentView
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.message.preview
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
|
import io.github.wulkanowy.data.repositories.message.MessageFolder
|
||||||
|
import io.github.wulkanowy.utils.openInternetBrowser
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
import kotlinx.android.synthetic.main.item_message_attachment.view.*
|
||||||
|
import kotlinx.android.synthetic.main.item_message_preview.view.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MessagePreviewAdapter @Inject constructor() :
|
||||||
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
|
enum class ViewType(val id: Int) {
|
||||||
|
MESSAGE(1),
|
||||||
|
DIVIDER(2),
|
||||||
|
ATTACHMENT(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
var messageWithAttachment: MessageWithAttachment? = null
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
attachments = value?.attachments.orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var attachments: List<MessageAttachment> = emptyList()
|
||||||
|
|
||||||
|
override fun getItemCount() = if (messageWithAttachment == null) 0 else attachments.size + 1 + if (attachments.isNotEmpty()) 1 else 0
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int) = when (position) {
|
||||||
|
0 -> ViewType.MESSAGE.id
|
||||||
|
1 -> ViewType.DIVIDER.id
|
||||||
|
else -> ViewType.ATTACHMENT.id
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
|
|
||||||
|
return when (viewType) {
|
||||||
|
ViewType.MESSAGE.id -> MessageViewHolder(inflater.inflate(R.layout.item_message_preview, parent, false))
|
||||||
|
ViewType.DIVIDER.id -> DividerViewHolder(inflater.inflate(R.layout.item_message_divider, parent, false))
|
||||||
|
ViewType.ATTACHMENT.id -> AttachmentViewHolder(inflater.inflate(R.layout.item_message_attachment, parent, false))
|
||||||
|
else -> throw IllegalStateException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
when (holder) {
|
||||||
|
is MessageViewHolder -> bindMessage(holder.view, requireNotNull(messageWithAttachment).message)
|
||||||
|
is AttachmentViewHolder -> bindAttachment(holder.view, requireNotNull(messageWithAttachment).attachments[position - 2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
private fun bindMessage(view: View, message: Message) {
|
||||||
|
with(view) {
|
||||||
|
messagePreviewSubject.text = if (message.subject.isNotBlank()) message.subject else context.getString(R.string.message_no_subject)
|
||||||
|
messagePreviewDate.text = context.getString(R.string.message_date, message.date.toFormattedString("yyyy-MM-dd HH:mm:ss"))
|
||||||
|
messagePreviewContent.text = message.content
|
||||||
|
messagePreviewAuthor.text = if (message.folderId == MessageFolder.SENT.id) "${context.getString(R.string.message_to)} ${message.recipient}"
|
||||||
|
else "${context.getString(R.string.message_from)} ${message.sender}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindAttachment(view: View, attachment: MessageAttachment) {
|
||||||
|
with(view) {
|
||||||
|
messagePreviewAttachment.visibility = View.VISIBLE
|
||||||
|
messagePreviewAttachment.text = attachment.filename
|
||||||
|
setOnClickListener {
|
||||||
|
context.openInternetBrowser(attachment.url) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageViewHolder(val view: View) : RecyclerView.ViewHolder(view)
|
||||||
|
|
||||||
|
class DividerViewHolder(val view: View) : RecyclerView.ViewHolder(view)
|
||||||
|
|
||||||
|
class AttachmentViewHolder(val view: View) : RecyclerView.ViewHolder(view)
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.preview
|
package io.github.wulkanowy.ui.modules.message.preview
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
@ -10,8 +9,10 @@ import android.view.View
|
|||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
@ -25,6 +26,9 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: MessagePreviewPresenter
|
lateinit var presenter: MessagePreviewPresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var previewAdapter: MessagePreviewAdapter
|
||||||
|
|
||||||
private var menuReplyButton: MenuItem? = null
|
private var menuReplyButton: MenuItem? = null
|
||||||
|
|
||||||
private var menuForwardButton: MenuItem? = null
|
private var menuForwardButton: MenuItem? = null
|
||||||
@ -34,18 +38,15 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl
|
|||||||
override val titleStringId: Int
|
override val titleStringId: Int
|
||||||
get() = R.string.message_title
|
get() = R.string.message_title
|
||||||
|
|
||||||
override val noSubjectString: String
|
|
||||||
get() = getString(R.string.message_no_subject)
|
|
||||||
|
|
||||||
override val deleteMessageSuccessString: String
|
override val deleteMessageSuccessString: String
|
||||||
get() = getString(R.string.message_delete_success)
|
get() = getString(R.string.message_delete_success)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val MESSAGE_ID_KEY = "message_id"
|
const val MESSAGE_ID_KEY = "message_id"
|
||||||
|
|
||||||
fun newInstance(messageId: Long): MessagePreviewFragment {
|
fun newInstance(message: Message): MessagePreviewFragment {
|
||||||
return MessagePreviewFragment().apply {
|
return MessagePreviewFragment().apply {
|
||||||
arguments = Bundle().apply { putLong(MESSAGE_ID_KEY, messageId) }
|
arguments = Bundle().apply { putSerializable(MESSAGE_ID_KEY, message) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,11 +63,16 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl
|
|||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
messageContainer = messagePreviewContainer
|
messageContainer = messagePreviewContainer
|
||||||
presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getLong(MESSAGE_ID_KEY) ?: 0L)
|
presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getSerializable(MESSAGE_ID_KEY) as Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
messagePreviewErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
messagePreviewErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||||
|
|
||||||
|
with(messagePreviewRecycler) {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
adapter = previewAdapter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
@ -86,26 +92,11 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setSubject(subject: String) {
|
override fun setMessageWithAttachment(item: MessageWithAttachment) {
|
||||||
messagePreviewSubject.text = subject
|
with(previewAdapter) {
|
||||||
}
|
messageWithAttachment = item
|
||||||
|
notifyDataSetChanged()
|
||||||
@SuppressLint("SetTextI18n")
|
}
|
||||||
override fun setRecipient(recipient: String) {
|
|
||||||
messagePreviewAuthor.text = "${getString(R.string.message_to)} $recipient"
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
|
||||||
override fun setSender(sender: String) {
|
|
||||||
messagePreviewAuthor.text = "${getString(R.string.message_from)} $sender"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setDate(date: String) {
|
|
||||||
messagePreviewDate.text = getString(R.string.message_date, date)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setContent(content: String) {
|
|
||||||
messagePreviewContent.text = content
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showProgress(show: Boolean) {
|
override fun showProgress(show: Boolean) {
|
||||||
@ -113,7 +104,7 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showContent(show: Boolean) {
|
override fun showContent(show: Boolean) {
|
||||||
messagePreviewContentContainer.visibility = if (show) VISIBLE else GONE
|
messagePreviewRecycler.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showOptions(show: Boolean) {
|
override fun showOptions(show: Boolean) {
|
||||||
@ -160,7 +151,7 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl
|
|||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
outState.putLong(MESSAGE_ID_KEY, presenter.messageId)
|
outState.putSerializable(MESSAGE_ID_KEY, presenter.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.preview
|
package io.github.wulkanowy.ui.modules.message.preview
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageFolder
|
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageRepository
|
import io.github.wulkanowy.data.repositories.message.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -20,61 +18,51 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
private val analytics: FirebaseAnalyticsHelper
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository, schedulers) {
|
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository, schedulers) {
|
||||||
|
|
||||||
var messageId = 0L
|
var message: Message? = null
|
||||||
|
|
||||||
private var message: Message? = null
|
|
||||||
|
|
||||||
private lateinit var lastError: Throwable
|
private lateinit var lastError: Throwable
|
||||||
|
|
||||||
private var retryCallback: () -> Unit = {}
|
private var retryCallback: () -> Unit = {}
|
||||||
|
|
||||||
fun onAttachView(view: MessagePreviewView, id: Long) {
|
fun onAttachView(view: MessagePreviewView, message: Message) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.initView()
|
view.initView()
|
||||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||||
loadData(id)
|
loadData(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onMessageLoadRetry() {
|
private fun onMessageLoadRetry(message: Message) {
|
||||||
view?.run {
|
view?.run {
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
}
|
}
|
||||||
loadData(messageId)
|
loadData(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onDetailsClick() {
|
fun onDetailsClick() {
|
||||||
view?.showErrorDetailsDialog(lastError)
|
view?.showErrorDetailsDialog(lastError)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData(id: Long) {
|
private fun loadData(message: Message) {
|
||||||
Timber.i("Loading message $id preview started")
|
Timber.i("Loading message ${message.messageId} preview started")
|
||||||
messageId = id
|
|
||||||
disposable.apply {
|
disposable.apply {
|
||||||
clear()
|
clear()
|
||||||
add(studentRepository.getCurrentStudent()
|
add(studentRepository.getCurrentStudent()
|
||||||
.flatMap { messageRepository.getMessage(it, messageId, true) }
|
.flatMap { messageRepository.getMessage(it, message, true) }
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
.observeOn(schedulers.mainThread)
|
.observeOn(schedulers.mainThread)
|
||||||
.doFinally { view?.showProgress(false) }
|
.doFinally { view?.showProgress(false) }
|
||||||
.subscribe({ message ->
|
.subscribe({ message ->
|
||||||
Timber.i("Loading message $id preview result: Success ")
|
Timber.i("Loading message ${message.message.messageId} preview result: Success ")
|
||||||
this@MessagePreviewPresenter.message = message
|
this@MessagePreviewPresenter.message = message.message
|
||||||
view?.run {
|
view?.apply {
|
||||||
message.let {
|
setMessageWithAttachment(message)
|
||||||
setSubject(if (it.subject.isNotBlank()) it.subject else noSubjectString)
|
initOptions()
|
||||||
setDate(it.date.toFormattedString("yyyy-MM-dd HH:mm:ss"))
|
|
||||||
setContent(it.content)
|
|
||||||
initOptions()
|
|
||||||
|
|
||||||
if (it.folderId == MessageFolder.SENT.id) setRecipient(it.recipient)
|
|
||||||
else setSender(it.sender)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
analytics.logEvent("load_message_preview", "length" to message.content.length)
|
analytics.logEvent("load_message_preview", "length" to message.message.content.length)
|
||||||
}) {
|
}) {
|
||||||
Timber.i("Loading message $id preview result: An exception occurred ")
|
Timber.i("Loading message ${message.messageId} preview result: An exception occurred ")
|
||||||
retryCallback = { onMessageLoadRetry() }
|
retryCallback = { onMessageLoadRetry(message) }
|
||||||
errorHandler.dispatch(it)
|
errorHandler.dispatch(it)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -119,8 +107,6 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
}, { error ->
|
}, { error ->
|
||||||
retryCallback = { onMessageDelete() }
|
retryCallback = { onMessageDelete() }
|
||||||
errorHandler.dispatch(error)
|
errorHandler.dispatch(error)
|
||||||
}, {
|
|
||||||
view?.showErrorView(true)
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,16 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.preview
|
package io.github.wulkanowy.ui.modules.message.preview
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
interface MessagePreviewView : BaseView {
|
interface MessagePreviewView : BaseView {
|
||||||
|
|
||||||
val noSubjectString: String
|
|
||||||
|
|
||||||
val deleteMessageSuccessString: String
|
val deleteMessageSuccessString: String
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun setSubject(subject: String)
|
fun setMessageWithAttachment(item: MessageWithAttachment)
|
||||||
|
|
||||||
fun setRecipient(recipient: String)
|
|
||||||
|
|
||||||
fun setSender(sender: String)
|
|
||||||
|
|
||||||
fun setDate(date: String)
|
|
||||||
|
|
||||||
fun setContent(content: String)
|
|
||||||
|
|
||||||
fun showProgress(show: Boolean)
|
fun showProgress(show: Boolean)
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
|
|||||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageFolder
|
import io.github.wulkanowy.data.repositories.message.MessageFolder
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
@ -116,8 +117,8 @@ class MessageTabFragment : BaseFragment(), MessageTabView {
|
|||||||
messageTabSwipe.isRefreshing = show
|
messageTabSwipe.isRefreshing = show
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openMessage(messageId: Long) {
|
override fun openMessage(message: Message) {
|
||||||
(activity as? MainActivity)?.pushView(MessagePreviewFragment.newInstance(messageId))
|
(activity as? MainActivity)?.pushView(MessagePreviewFragment.newInstance(message))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun notifyParentDataLoaded() {
|
override fun notifyParentDataLoaded() {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.tab
|
package io.github.wulkanowy.ui.modules.message.tab
|
||||||
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageFolder
|
import io.github.wulkanowy.data.repositories.message.MessageFolder
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageRepository
|
import io.github.wulkanowy.data.repositories.message.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||||
@ -63,11 +62,10 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
if (item is MessageItem) {
|
if (item is MessageItem) {
|
||||||
Timber.i("Select message ${item.message.id} item")
|
Timber.i("Select message ${item.message.id} item")
|
||||||
view?.run {
|
view?.run {
|
||||||
openMessage(item.message.id)
|
openMessage(item.message)
|
||||||
if (item.message.unread) {
|
if (item.message.unread) {
|
||||||
item.message.unread = false
|
item.message.unread = false
|
||||||
updateItem(item)
|
updateItem(item)
|
||||||
updateMessage(item.message)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,16 +117,4 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
} else showError(message, error)
|
} else showError(message, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateMessage(message: Message) {
|
|
||||||
Timber.i("Attempt to update message ${message.id}")
|
|
||||||
disposable.add(messageRepository.updateMessage(message)
|
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
|
||||||
.observeOn(schedulers.mainThread)
|
|
||||||
.subscribe({ Timber.d("Update message ${message.id} result: Success") })
|
|
||||||
{ error ->
|
|
||||||
Timber.i("Update message ${message.id} result: An exception occurred")
|
|
||||||
errorHandler.dispatch(error)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.tab
|
package io.github.wulkanowy.ui.modules.message.tab
|
||||||
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageItem
|
import io.github.wulkanowy.ui.modules.message.MessageItem
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ interface MessageTabView : BaseView {
|
|||||||
|
|
||||||
fun showRefresh(show: Boolean)
|
fun showRefresh(show: Boolean)
|
||||||
|
|
||||||
fun openMessage(messageId: Long)
|
fun openMessage(message: Message)
|
||||||
|
|
||||||
fun notifyParentDataLoaded()
|
fun notifyParentDataLoaded()
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
package io.github.wulkanowy.ui.modules.note
|
package io.github.wulkanowy.ui.modules.note
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Note
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import kotlinx.android.synthetic.main.dialog_note.*
|
import kotlinx.android.synthetic.main.dialog_note.*
|
||||||
|
import io.github.wulkanowy.sdk.scrapper.notes.Note.CategoryType
|
||||||
|
|
||||||
class NoteDialog : DialogFragment() {
|
class NoteDialog : DialogFragment() {
|
||||||
|
|
||||||
@ -36,6 +40,7 @@ class NoteDialog : DialogFragment() {
|
|||||||
return inflater.inflate(R.layout.dialog_note, container, false)
|
return inflater.inflate(R.layout.dialog_note, container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
@ -43,6 +48,16 @@ class NoteDialog : DialogFragment() {
|
|||||||
noteDialogCategory.text = note.category
|
noteDialogCategory.text = note.category
|
||||||
noteDialogTeacher.text = note.teacher
|
noteDialogTeacher.text = note.teacher
|
||||||
noteDialogContent.text = note.content
|
noteDialogContent.text = note.content
|
||||||
|
if (note.isPointsShow) {
|
||||||
|
with(noteDialogPoints) {
|
||||||
|
text = "${if (note.points > 0) "+" else ""}${note.points}"
|
||||||
|
setTextColor(when (CategoryType.getByValue(note.categoryType)) {
|
||||||
|
CategoryType.POSITIVE -> ContextCompat.getColor(requireContext(), R.color.note_positive)
|
||||||
|
CategoryType.NEGATIVE -> ContextCompat.getColor(requireContext(), R.color.note_negative)
|
||||||
|
else -> requireContext().getThemeAttrColor(android.R.attr.textColorPrimary)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
noteDialogClose.setOnClickListener { dismiss() }
|
noteDialogClose.setOnClickListener { dismiss() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
package io.github.wulkanowy.ui.modules.note
|
package io.github.wulkanowy.ui.modules.note
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.graphics.Typeface.BOLD
|
import android.graphics.Typeface.BOLD
|
||||||
import android.graphics.Typeface.NORMAL
|
import android.graphics.Typeface.NORMAL
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Note
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
|
import io.github.wulkanowy.sdk.scrapper.notes.Note.CategoryType
|
||||||
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
import kotlinx.android.synthetic.main.item_note.*
|
import kotlinx.android.synthetic.main.item_note.*
|
||||||
@ -17,20 +23,30 @@ class NoteItem(val note: Note) : AbstractFlexibleItem<NoteItem.ViewHolder>() {
|
|||||||
|
|
||||||
override fun getLayoutRes() = R.layout.item_note
|
override fun getLayoutRes() = R.layout.item_note
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): NoteItem.ViewHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||||
return NoteItem.ViewHolder(view, adapter)
|
return ViewHolder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: NoteItem.ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||||
holder.apply {
|
holder.apply {
|
||||||
noteItemDate.apply {
|
with(noteItemDate) {
|
||||||
text = note.date.toFormattedString()
|
text = note.date.toFormattedString()
|
||||||
setTypeface(null, if (note.isRead) NORMAL else BOLD)
|
setTypeface(null, if (note.isRead) NORMAL else BOLD)
|
||||||
}
|
}
|
||||||
noteItemType.apply {
|
with(noteItemType) {
|
||||||
text = note.category
|
text = note.category
|
||||||
setTypeface(null, if (note.isRead) NORMAL else BOLD)
|
setTypeface(null, if (note.isRead) NORMAL else BOLD)
|
||||||
}
|
}
|
||||||
|
with(noteItemPoints) {
|
||||||
|
text = "${if (note.points > 0) "+" else ""}${note.points}"
|
||||||
|
visibility = if (note.isPointsShow) VISIBLE else GONE
|
||||||
|
setTextColor(when(CategoryType.getByValue(note.categoryType)) {
|
||||||
|
CategoryType.POSITIVE -> ContextCompat.getColor(context, R.color.note_positive)
|
||||||
|
CategoryType.NEGATIVE -> ContextCompat.getColor(context, R.color.note_negative)
|
||||||
|
else -> context.getThemeAttrColor(android.R.attr.textColorPrimary)
|
||||||
|
})
|
||||||
|
}
|
||||||
noteItemTeacher.text = note.teacher
|
noteItemTeacher.text = note.teacher
|
||||||
noteItemContent.text = note.content
|
noteItemContent.text = note.content
|
||||||
}
|
}
|
||||||
@ -53,7 +69,8 @@ class NoteItem(val note: Note) : AbstractFlexibleItem<NoteItem.ViewHolder>() {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) :
|
||||||
|
FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||||
override val containerView: View
|
override val containerView: View
|
||||||
get() = contentView
|
get() = contentView
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.settings
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import com.yariksoffice.lingver.Lingver
|
import com.yariksoffice.lingver.Lingver
|
||||||
@ -33,11 +34,24 @@ class SettingsFragment : PreferenceFragmentCompat(),
|
|||||||
|
|
||||||
override val titleStringId get() = R.string.settings_title
|
override val titleStringId get() = R.string.settings_title
|
||||||
|
|
||||||
|
override val syncSuccessString get() = getString(R.string.pref_services_message_sync_success)
|
||||||
|
|
||||||
|
override val syncFailedString get() = getString(R.string.pref_services_message_sync_failed)
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
AndroidSupportInjection.inject(this)
|
AndroidSupportInjection.inject(this)
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
|
||||||
|
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
presenter.onSyncNowClicked()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
presenter.onAttachView(this)
|
presenter.onAttachView(this)
|
||||||
@ -61,12 +75,19 @@ class SettingsFragment : PreferenceFragmentCompat(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) {
|
override fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) {
|
||||||
findPreference<Preference>(serviceEnablesKey)?.apply {
|
findPreference<Preference>(serviceEnablesKey)?.run {
|
||||||
summary = if (isHolidays) getString(R.string.pref_services_suspended) else ""
|
summary = if (isHolidays) getString(R.string.pref_services_suspended) else ""
|
||||||
isEnabled = !isHolidays
|
isEnabled = !isHolidays
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setSyncInProgress(inProgress: Boolean) {
|
||||||
|
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
|
||||||
|
isEnabled = !inProgress
|
||||||
|
summary = if (inProgress) getString(R.string.pref_services_sync_in_progress) else ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun showError(text: String, error: Throwable) {
|
override fun showError(text: String, error: Throwable) {
|
||||||
(activity as? BaseActivity<*>)?.showError(text, error)
|
(activity as? BaseActivity<*>)?.showError(text, error)
|
||||||
}
|
}
|
||||||
@ -87,6 +108,15 @@ class SettingsFragment : PreferenceFragmentCompat(),
|
|||||||
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showForceSyncDialog() {
|
||||||
|
AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle(R.string.pref_services_dialog_force_sync_title)
|
||||||
|
.setMessage(R.string.pref_services_dialog_force_sync_summary)
|
||||||
|
.setPositiveButton(android.R.string.ok) { _, _ -> presenter.onForceSyncDialogSubmit() }
|
||||||
|
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package io.github.wulkanowy.ui.modules.settings
|
package io.github.wulkanowy.ui.modules.settings
|
||||||
|
|
||||||
import com.readystatesoftware.chuck.api.ChuckCollector
|
import androidx.work.WorkInfo
|
||||||
|
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.services.sync.SyncManager
|
import io.github.wulkanowy.services.sync.SyncManager
|
||||||
@ -21,7 +22,7 @@ class SettingsPresenter @Inject constructor(
|
|||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val analytics: FirebaseAnalyticsHelper,
|
private val analytics: FirebaseAnalyticsHelper,
|
||||||
private val syncManager: SyncManager,
|
private val syncManager: SyncManager,
|
||||||
private val chuckCollector: ChuckCollector,
|
private val chuckerCollector: ChuckerCollector,
|
||||||
private val appInfo: AppInfo
|
private val appInfo: AppInfo
|
||||||
) : BasePresenter<SettingsView>(errorHandler, studentRepository, schedulers) {
|
) : BasePresenter<SettingsView>(errorHandler, studentRepository, schedulers) {
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ class SettingsPresenter @Inject constructor(
|
|||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Settings view was initialized")
|
Timber.i("Settings view was initialized")
|
||||||
view.setServicesSuspended(preferencesRepository.serviceEnableKey, now().isHolidays)
|
view.setServicesSuspended(preferencesRepository.serviceEnableKey, now().isHolidays)
|
||||||
|
view.initView()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSharedPreferenceChanged(key: String) {
|
fun onSharedPreferenceChanged(key: String) {
|
||||||
@ -36,9 +38,9 @@ class SettingsPresenter @Inject constructor(
|
|||||||
|
|
||||||
with(preferencesRepository) {
|
with(preferencesRepository) {
|
||||||
when (key) {
|
when (key) {
|
||||||
serviceEnableKey -> with(syncManager) { if (isServiceEnabled) startSyncWorker() else stopSyncWorker() }
|
serviceEnableKey -> with(syncManager) { if (isServiceEnabled) startPeriodicSyncWorker() else stopSyncWorker() }
|
||||||
servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startSyncWorker(true)
|
servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startPeriodicSyncWorker(true)
|
||||||
isDebugNotificationEnableKey -> chuckCollector.showNotification(isDebugNotificationEnable)
|
isDebugNotificationEnableKey -> chuckerCollector.showNotification = isDebugNotificationEnable
|
||||||
appThemeKey -> view?.recreateView()
|
appThemeKey -> view?.recreateView()
|
||||||
appLanguageKey -> view?.run {
|
appLanguageKey -> view?.run {
|
||||||
updateLanguage(if (appLanguage == "system") appInfo.systemLanguage else appLanguage)
|
updateLanguage(if (appLanguage == "system") appInfo.systemLanguage else appLanguage)
|
||||||
@ -49,4 +51,25 @@ class SettingsPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
analytics.logEvent("setting_changed", "name" to key)
|
analytics.logEvent("setting_changed", "name" to key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onSyncNowClicked() {
|
||||||
|
view?.showForceSyncDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onForceSyncDialogSubmit() {
|
||||||
|
view?.run {
|
||||||
|
Timber.i("Setting sync now started")
|
||||||
|
analytics.logEvent("sync_now_started")
|
||||||
|
disposable.add(syncManager.startOneTimeSyncWorker()
|
||||||
|
.doOnSubscribe { setSyncInProgress(true) }
|
||||||
|
.doFinally { setSyncInProgress(false) }
|
||||||
|
.subscribe({ workInfo ->
|
||||||
|
if (workInfo.state == WorkInfo.State.SUCCEEDED) showMessage(syncSuccessString)
|
||||||
|
else if (workInfo.state == WorkInfo.State.FAILED) showError(syncFailedString, Throwable(workInfo.outputData.getString("error")))
|
||||||
|
}, {
|
||||||
|
Timber.e("Sync now failed")
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,19 @@ import io.github.wulkanowy.ui.base.BaseView
|
|||||||
|
|
||||||
interface SettingsView : BaseView {
|
interface SettingsView : BaseView {
|
||||||
|
|
||||||
|
val syncSuccessString: String
|
||||||
|
|
||||||
|
val syncFailedString: String
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
fun recreateView()
|
fun recreateView()
|
||||||
|
|
||||||
fun updateLanguage(langCode: String)
|
fun updateLanguage(langCode: String)
|
||||||
|
|
||||||
fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean)
|
fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean)
|
||||||
|
|
||||||
|
fun setSyncInProgress(inProgress: Boolean)
|
||||||
|
|
||||||
|
fun showForceSyncDialog()
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package io.github.wulkanowy.ui.modules.timetable.completed
|
package io.github.wulkanowy.ui.modules.timetable.completed
|
||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import com.readystatesoftware.chuck.api.ChuckCollector
|
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||||
import io.github.wulkanowy.sdk.exception.FeatureDisabledException
|
import io.github.wulkanowy.sdk.exception.FeatureDisabledException
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class CompletedLessonsErrorHandler @Inject constructor(
|
class CompletedLessonsErrorHandler @Inject constructor(
|
||||||
resources: Resources,
|
resources: Resources,
|
||||||
chuckCollector: ChuckCollector
|
chuckerCollector: ChuckerCollector
|
||||||
) : ErrorHandler(resources, chuckCollector) {
|
) : ErrorHandler(resources, chuckerCollector) {
|
||||||
|
|
||||||
var onFeatureDisabled: () -> Unit = {}
|
var onFeatureDisabled: () -> Unit = {}
|
||||||
|
|
||||||
|
@ -32,12 +32,16 @@ fun Context.openInternetBrowser(uri: String, onActivityNotFound: (uri: String) -
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.openEmailClient(chooserTitle: String, email: String, subject: String?, body: String?) {
|
fun Context.openEmailClient(chooserTitle: String, email: String, subject: String, body: String, onActivityNotFound: () -> Unit = {}) {
|
||||||
val emailIntent = Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", email, null))
|
val intent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:")).apply {
|
||||||
emailIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf(email))
|
putExtra(Intent.EXTRA_EMAIL, arrayOf(email))
|
||||||
if (subject != null) emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject)
|
putExtra(Intent.EXTRA_SUBJECT, subject)
|
||||||
if (body != null) emailIntent.putExtra(Intent.EXTRA_TEXT, body)
|
putExtra(Intent.EXTRA_TEXT, body)
|
||||||
startActivity(Intent.createChooser(emailIntent, chooserTitle))
|
}
|
||||||
|
|
||||||
|
if (intent.resolveActivity(packageManager) != null) {
|
||||||
|
startActivity(Intent.createChooser(intent, chooserTitle))
|
||||||
|
} else onActivityNotFound()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.openNavigation(location: String) {
|
fun Context.openNavigation(location: String) {
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
Wersja 0.16.0
|
Wersja 0.17.0
|
||||||
|
|
||||||
- oceny zapisane w nawiasach nie są już liczone do średniej
|
- dodaliśmy wsparcie dla załączników w wiadomosciach i zadaniach domowych
|
||||||
- naprawiliśmy wyświetlanie szczęśliwych numerków na kontach rodziców (może być potrzebne zalogowanie się ponownie)
|
- dodaliśmy oznaczanie zadań domowych jako wykonanych
|
||||||
- dodaliśmy opcję przywracania hasła, ulepszyliśmy formularz logowania
|
- dodaliśmy wyświetlanie punktów przy uwagach
|
||||||
- dodaliśmy język ukraiński i niemiecki
|
- dodaliśmy funkcję powiadomień o awariach dziennika
|
||||||
- dodaliśmy informację na górnym pasku o bieżącym semestrze w widoku ocen
|
- dodaliśmy funkcję wymuszenia pełnej synchronizacji
|
||||||
- ulepszyliśmy przełączanie aplikacji na nowy semestr
|
- zmieniliśmy sposób zwracania się do użytkownika na bezosobowy
|
||||||
|
- naprawiliśmy logowanie na androidach niższych niż 5.0
|
||||||
|
|
||||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||||
|
BIN
app/src/main/res/drawable-hdpi/ic_stat_push.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_stat_push.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 724 B |
BIN
app/src/main/res/drawable-mdpi/ic_stat_push.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_stat_push.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 470 B |
BIN
app/src/main/res/drawable-xhdpi/ic_stat_push.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_stat_push.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 955 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_stat_push.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_stat_push.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_stat_push.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_stat_push.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
9
app/src/main/res/drawable/ic_attachment.xml
Normal file
9
app/src/main/res/drawable/ic_attachment.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M2,12.5C2,9.46 4.46,7 7.5,7H18c2.21,0 4,1.79 4,4s-1.79,4 -4,4H9.5C8.12,15 7,13.88 7,12.5S8.12,10 9.5,10H17v2H9.41c-0.55,0 -0.55,1 0,1H18c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2H7.5C5.57,9 4,10.57 4,12.5S5.57,16 7.5,16H17v2H7.5C4.46,18 2,15.54 2,12.5z"/>
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_check.xml
Normal file
9
app/src/main/res/drawable/ic_check.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
|
||||||
|
</vector>
|
5
app/src/main/res/drawable/ic_share.xml
Normal file
5
app/src/main/res/drawable/ic_share.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
|
||||||
|
</vector>
|
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
@ -97,13 +98,46 @@
|
|||||||
android:textIsSelectable="true"
|
android:textIsSelectable="true"
|
||||||
android:textSize="12sp" />
|
android:textSize="12sp" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<TextView
|
||||||
android:id="@+id/homeworkDialogClose"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginTop="15dp"
|
android:text="@string/homework_attachments"
|
||||||
android:text="@string/all_close" />
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/homeworkDialogAttachments"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:lineSpacingMultiplier="1.2"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="15dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/homeworkDialogRead"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/homework_mark_as_done"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/homeworkDialogClose"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="1dp"
|
||||||
|
android:text="@string/all_close"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
@ -64,6 +64,22 @@
|
|||||||
android:textIsSelectable="true"
|
android:textIsSelectable="true"
|
||||||
android:textSize="12sp" />
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/note_points"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/noteDialogPoints"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -108,31 +108,41 @@
|
|||||||
android:text="@string/login_header_symbol"
|
android:text="@string/login_header_symbol"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
app:fontFamily="sans-serif-light"
|
app:fontFamily="sans-serif-light"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/loginSymbolNameLayout"
|
app:layout_constraintBottom_toTopOf="@+id/loginSymbolHelper"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/loginSymbolContact"
|
app:layout_constraintTop_toBottomOf="@+id/loginSymbolContact"
|
||||||
app:layout_constraintVertical_chainStyle="packed" />
|
app:layout_constraintVertical_chainStyle="packed" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/loginSymbolHelper"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:layout_marginEnd="32dp"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:text="@string/login_symbol_helper"
|
||||||
|
app:fontFamily="sans-serif-light"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/loginSymbolNameLayout"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/loginSymbolHeader"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed" />
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/loginSymbolNameLayout"
|
android:id="@+id/loginSymbolNameLayout"
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_margin="24dp"
|
||||||
android:layout_marginLeft="24dp"
|
|
||||||
android:layout_marginTop="48dp"
|
|
||||||
android:layout_marginEnd="24dp"
|
|
||||||
android:layout_marginRight="24dp"
|
|
||||||
android:hint="@string/login_symbol_hint"
|
android:hint="@string/login_symbol_hint"
|
||||||
app:helperText="@string/login_symbol_helper"
|
|
||||||
app:helperTextEnabled="true"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/loginSymbolSignIn"
|
app:layout_constraintBottom_toTopOf="@+id/loginSymbolSignIn"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/loginSymbolHeader">
|
app:layout_constraintTop_toBottomOf="@+id/loginSymbolHelper">
|
||||||
|
|
||||||
<AutoCompleteTextView
|
<AutoCompleteTextView
|
||||||
android:id="@+id/loginSymbolName"
|
android:id="@+id/loginSymbolName"
|
||||||
|
@ -5,55 +5,12 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/messagePreviewRecycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
tools:itemCount="1"
|
||||||
<LinearLayout
|
tools:listitem="@layout/item_message_preview" />
|
||||||
android:id="@+id/messagePreviewContentContainer"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/messagePreviewSubject"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="15dp"
|
|
||||||
android:lineSpacingMultiplier="1.2"
|
|
||||||
android:textSize="22sp"
|
|
||||||
tools:text="@tools:sample/lorem" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/messagePreviewAuthor"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="4dp"
|
|
||||||
android:textColor="?android:textColorSecondary"
|
|
||||||
android:textSize="15sp"
|
|
||||||
tools:text="@tools:sample/full_names" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/messagePreviewDate"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="15dp"
|
|
||||||
android:textColor="?android:textColorSecondary"
|
|
||||||
android:textSize="15sp"
|
|
||||||
tools:text="@tools:sample/date/ddmmyy" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/messagePreviewContent"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:autoLink="web"
|
|
||||||
android:lineSpacingMultiplier="1.2"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
tools:text="@tools:sample/lorem" />
|
|
||||||
</LinearLayout>
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/messagePreviewError"
|
android:id="@+id/messagePreviewError"
|
||||||
@ -95,7 +52,6 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginRight="8dp"
|
|
||||||
android:text="@string/all_details" />
|
android:text="@string/all_details" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/homework_subitem_container"
|
android:id="@+id/homework_subitem_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -8,43 +9,75 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/homeworkItemSubject"
|
android:id="@+id/homeworkItemSubject"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="15dp"
|
android:layout_marginStart="15dp"
|
||||||
android:layout_marginLeft="15dp"
|
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginBottom="5dp"
|
android:layout_marginBottom="5dp"
|
||||||
android:textSize="17sp"
|
android:ellipsize="end"
|
||||||
tools:text="@tools:sample/lorem" />
|
android:singleLine="true"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/homeworkItemTeacher"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/homeworkItemTeacher"
|
android:id="@+id/homeworkItemTeacher"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:layout_marginLeft="10dp"
|
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginEnd="15dp"
|
android:layout_marginEnd="15dp"
|
||||||
android:layout_marginRight="15dp"
|
android:ellipsize="end"
|
||||||
android:layout_toEndOf="@id/homeworkItemSubject"
|
|
||||||
android:layout_toRightOf="@id/homeworkItemSubject"
|
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
|
android:maxWidth="200dp"
|
||||||
|
android:minWidth="80dp"
|
||||||
|
android:singleLine="true"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/homeworkItemSubject"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="@tools:sample/full_names" />
|
tools:text="@tools:sample/full_names" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/homeworkItemContent"
|
android:id="@+id/homeworkItemContent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/homeworkItemSubject"
|
android:layout_marginTop="5dp"
|
||||||
android:layout_alignStart="@id/homeworkItemSubject"
|
android:layout_marginEnd="50dp"
|
||||||
android:layout_alignLeft="@id/homeworkItemSubject"
|
|
||||||
android:layout_marginEnd="15dp"
|
|
||||||
android:layout_marginRight="15dp"
|
|
||||||
android:layout_marginBottom="15dp"
|
android:layout_marginBottom="15dp"
|
||||||
|
android:ellipsize="end"
|
||||||
android:lineSpacingMultiplier="1.2"
|
android:lineSpacingMultiplier="1.2"
|
||||||
|
android:maxLines="2"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
tools:text="@tools:sample/lorem" />
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
</RelativeLayout>
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/homeworkItemSubject"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/homeworkItemSubject"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/homeworkItemCheckImage"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/homeworkItemTeacher"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/homeworkItemTeacher"
|
||||||
|
app:srcCompat="@drawable/ic_check"
|
||||||
|
app:tint="?android:textColorSecondary"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/homeworkItemAttachmentImage"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/homeworkItemTeacher"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/homeworkItemTeacher"
|
||||||
|
app:srcCompat="@drawable/ic_attachment"
|
||||||
|
app:tint="?android:textColorSecondary"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -14,9 +14,11 @@
|
|||||||
android:id="@+id/licenseItemName"
|
android:id="@+id/licenseItemName"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="28dp"
|
android:layout_height="28dp"
|
||||||
|
android:ellipsize="end"
|
||||||
android:gravity="bottom"
|
android:gravity="bottom"
|
||||||
|
android:singleLine="true"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
tools:text="@tools:sample/lorem" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/licenseItemSummary"
|
android:id="@+id/licenseItemSummary"
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/relativeLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?selectableItemBackground"
|
android:background="?selectableItemBackground"
|
||||||
@ -11,41 +13,53 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/messageItemAuthor"
|
android:id="@+id/messageItemAuthor"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_marginEnd="10dp"
|
||||||
android:layout_marginEnd="40dp"
|
android:layout_marginRight="10dp"
|
||||||
android:layout_marginRight="40dp"
|
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:singleLine="true"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
tools:text="@tools:sample/full_names" />
|
app:layout_constraintEnd_toStartOf="@+id/messageItemDate"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/messageItemDate"
|
android:id="@+id/messageItemDate"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_marginStart="10dp"
|
|
||||||
android:layout_marginLeft="10dp"
|
|
||||||
android:layout_toEndOf="@id/messageItemAuthor"
|
|
||||||
android:layout_toRightOf="@id/messageItemAuthor"
|
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="@tools:sample/date/ddmmyy" />
|
tools:text="@tools:sample/date/ddmmyy" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/messageItemSubject"
|
android:id="@+id/messageItemSubject"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/messageItemAuthor"
|
|
||||||
android:layout_alignStart="@id/messageItemAuthor"
|
|
||||||
android:layout_alignLeft="@id/messageItemAuthor"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:singleLine="true"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/messageItemAttachmentIcon"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/messageItemAuthor"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/messageItemAuthor"
|
||||||
|
app:layout_goneMarginEnd="0dp"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
</RelativeLayout>
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/messageItemAttachmentIcon"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/messageItemSubject"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/messageItemDate"
|
||||||
|
app:srcCompat="@drawable/ic_attachment"
|
||||||
|
app:tint="?colorOnBackground"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
22
app/src/main/res/layout/item_message_attachment.xml
Normal file
22
app/src/main/res/layout/item_message_attachment.xml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingBottom="10dp">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/messagePreviewAttachment"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:drawablePadding="10dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:drawableStartCompat="@drawable/ic_attachment"
|
||||||
|
app:drawableTint="?colorOnBackground"
|
||||||
|
tools:text="@tools:sample/lorem"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</LinearLayout>
|
6
app/src/main/res/layout/item_message_divider.xml
Normal file
6
app/src/main/res/layout/item_message_divider.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="2dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:background="?android:attr/listDivider" />
|
45
app/src/main/res/layout/item_message_preview.xml
Normal file
45
app/src/main/res/layout/item_message_preview.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/messagePreviewContentContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/messagePreviewSubject"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="15dp"
|
||||||
|
android:lineSpacingMultiplier="1.2"
|
||||||
|
android:textSize="22sp"
|
||||||
|
tools:text="@tools:sample/lorem" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/messagePreviewAuthor"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="@tools:sample/full_names" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/messagePreviewDate"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="15dp"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="@tools:sample/date/ddmmyy" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/messagePreviewContent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="web"
|
||||||
|
android:lineSpacingMultiplier="1.2"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
</LinearLayout>
|
@ -1,4 +1,5 @@
|
|||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/note_subitem_container"
|
android:id="@+id/note_subitem_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -8,54 +9,76 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/noteItemDate"
|
android:id="@+id/noteItemDate"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="15dp"
|
android:layout_marginStart="15dp"
|
||||||
android:layout_marginLeft="15dp"
|
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintRight_toLeftOf="@+id/noteItemTeacher"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="@tools:sample/date/ddmmyy" />
|
tools:text="@tools:sample/date/ddmmyy" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/noteItemTeacher"
|
android:id="@+id/noteItemTeacher"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:layout_marginLeft="10dp"
|
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginEnd="15dp"
|
android:layout_marginEnd="15dp"
|
||||||
android:layout_marginRight="15dp"
|
android:ellipsize="end"
|
||||||
android:layout_toEndOf="@id/noteItemDate"
|
|
||||||
android:layout_toRightOf="@id/noteItemDate"
|
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
|
android:singleLine="true"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/noteItemDate"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="@tools:sample/full_names" />
|
tools:text="@tools:sample/full_names" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/noteItemType"
|
android:id="@+id/noteItemType"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/noteItemDate"
|
|
||||||
android:layout_alignStart="@id/noteItemDate"
|
|
||||||
android:layout_alignLeft="@id/noteItemDate"
|
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
android:layout_marginBottom="5dp"
|
android:layout_marginBottom="5dp"
|
||||||
android:textSize="13sp"
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintLeft_toLeftOf="@id/noteItemDate"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/noteItemPoints"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/noteItemDate"
|
||||||
|
app:layout_goneMarginEnd="0dp"
|
||||||
tools:text="@tools:sample/lorem" />
|
tools:text="@tools:sample/lorem" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/noteItemContent"
|
android:id="@+id/noteItemPoints"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/noteItemType"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_alignStart="@id/noteItemDate"
|
android:textSize="16sp"
|
||||||
android:layout_alignLeft="@id/noteItemDate"
|
android:textStyle="bold"
|
||||||
android:layout_marginEnd="15dp"
|
android:visibility="gone"
|
||||||
android:layout_marginRight="15dp"
|
app:layout_constraintRight_toRightOf="@id/noteItemTeacher"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/noteItemTeacher"
|
||||||
|
tools:text="-5"
|
||||||
|
tools:textColor="@color/note_positive"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/noteItemContent"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
android:layout_marginBottom="15dp"
|
android:layout_marginBottom="15dp"
|
||||||
|
android:ellipsize="end"
|
||||||
android:lineSpacingMultiplier="1.2"
|
android:lineSpacingMultiplier="1.2"
|
||||||
|
android:maxLines="2"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="@id/noteItemDate"
|
||||||
|
app:layout_constraintRight_toRightOf="@+id/noteItemTeacher"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/noteItemType"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
</RelativeLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/logViewerMenuShare"
|
android:id="@+id/logViewerMenuShare"
|
||||||
android:icon="@drawable/chuck_ic_share_white_24dp"
|
android:icon="@drawable/ic_share"
|
||||||
android:orderInCategory="1"
|
android:orderInCategory="1"
|
||||||
android:title="@string/logviewer_share"
|
android:title="@string/logviewer_share"
|
||||||
app:iconTint="@color/material_on_surface_emphasis_medium"
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
|
1
app/src/main/res/raw/custom_license_mappings.prop
Normal file
1
app/src/main/res/raw/custom_license_mappings.prop
Normal file
@ -0,0 +1 @@
|
|||||||
|
io_github_wulkanowy__sdk:apache_2_0
|
3
app/src/main/res/raw/custom_license_year_mappings.prop
Normal file
3
app/src/main/res/raw/custom_license_year_mappings.prop
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
com_github_wulkanowy__material_chips_input:2019
|
||||||
|
io_github_wulkanowy__uonet_request_signer:2019
|
||||||
|
io_github_wulkanowy__sdk:2020
|
3
app/src/main/res/raw/custom_name_mappings.prop
Normal file
3
app/src/main/res/raw/custom_name_mappings.prop
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
com_github_wulkanowy__material_chips_input:Material Chips Input
|
||||||
|
io_github_wulkanowy__uonet_request_signer:UONET+ Request Signer
|
||||||
|
io_github_wulkanowy__sdk:VULCAN UONET+ SDK
|
@ -48,11 +48,12 @@
|
|||||||
<string name="login_invalid_token">Ungültige token</string>
|
<string name="login_invalid_token">Ungültige token</string>
|
||||||
<string name="login_expired_token">Token ist nicht mehr gültig</string>
|
<string name="login_expired_token">Token ist nicht mehr gültig</string>
|
||||||
<string name="login_invalid_email">Ungültige email</string>
|
<string name="login_invalid_email">Ungültige email</string>
|
||||||
|
<string name="login_invalid_login">Ungültige login</string>
|
||||||
<string name="login_invalid_symbol">Ungültige symbol</string>
|
<string name="login_invalid_symbol">Ungültige symbol</string>
|
||||||
<string name="login_incorrect_symbol">Student nicht gefunden. Überprüfen Sie das Symbol</string>
|
<string name="login_incorrect_symbol">Student nicht gefunden. Überprüfen Sie das Symbol</string>
|
||||||
<string name="login_field_required">Dieses Datenfeld ist erforderlich</string>
|
<string name="login_field_required">Dieses Datenfeld ist erforderlich</string>
|
||||||
<string name="login_duplicate_student">Ausgewählter Student ist bereits angemeldet.</string>
|
<string name="login_duplicate_student">Ausgewählter Student ist bereits angemeldet.</string>
|
||||||
<string name="login_symbol_helper">Das Symbol finden Sie auf der Registerseite unter Uczeń -> Dostęp Mobilny -> Zarejestruj urządzenie mobilne</string>
|
<string name="login_symbol_helper">Das Symbol finden Sie auf der Registerseite unter <b>Uczeń</b> → <b>Dostęp Mobilny</b> → <b>Zarejestruj urządzenie mobilne</b></string>
|
||||||
<string name="login_select_student">Wählen Sie die Studenten aus, die sich bei der Anwendung anmelden sollen.</string>
|
<string name="login_select_student">Wählen Sie die Studenten aus, die sich bei der Anwendung anmelden sollen.</string>
|
||||||
<string name="login_advanced">Andere Optionen</string>
|
<string name="login_advanced">Andere Optionen</string>
|
||||||
<string name="login_privacy_policy">Datenschutzerklärung</string>
|
<string name="login_privacy_policy">Datenschutzerklärung</string>
|
||||||
@ -201,6 +202,7 @@
|
|||||||
|
|
||||||
<!--Note-->
|
<!--Note-->
|
||||||
<string name="note_no_items">Keine Informationen über Eintragen</string>
|
<string name="note_no_items">Keine Informationen über Eintragen</string>
|
||||||
|
<string name="note_points">Punkte</string>
|
||||||
<plurals name="note_number_item">
|
<plurals name="note_number_item">
|
||||||
<item quantity="one">%d Eintrag</item>
|
<item quantity="one">%d Eintrag</item>
|
||||||
<item quantity="other">%d Eintragen</item>
|
<item quantity="other">%d Eintragen</item>
|
||||||
@ -217,6 +219,9 @@
|
|||||||
|
|
||||||
<!--Homework-->
|
<!--Homework-->
|
||||||
<string name="homework_no_items">Keine Informationen über Hausaufgaben</string>
|
<string name="homework_no_items">Keine Informationen über Hausaufgaben</string>
|
||||||
|
<string name="homework_mark_as_done">Gemacht</string>
|
||||||
|
<string name="homework_mark_as_undone">Unvollständig</string>
|
||||||
|
<string name="homework_attachments">Anhänge</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Lucky number-->
|
<!--Lucky number-->
|
||||||
@ -354,6 +359,7 @@
|
|||||||
<string name="channel_lucky_number">Glückliche Nummer</string>
|
<string name="channel_lucky_number">Glückliche Nummer</string>
|
||||||
<string name="channel_new_message">Neue Nachrichten</string>
|
<string name="channel_new_message">Neue Nachrichten</string>
|
||||||
<string name="channel_new_notes">Neue Eintragen</string>
|
<string name="channel_new_notes">Neue Eintragen</string>
|
||||||
|
<string name="channel_push">Push-Benachrichtigungen</string>
|
||||||
<string name="channel_debug">Debuggen</string>
|
<string name="channel_debug">Debuggen</string>
|
||||||
|
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user