From 3ab15e0e0092bd65710e90dd2673287a1923e03d Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Thu, 20 Dec 2018 15:03:42 +0100 Subject: [PATCH 001/192] Added icon for the DEV version (#203) --- .../res/drawable/ic_launcher_foreground.xml | 58 ++++++++++++++++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 ++ .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 ++ app/src/debug/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2451 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4369 bytes app/src/debug/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1756 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2798 bytes .../debug/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 3378 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6193 bytes .../debug/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 5136 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 9606 bytes .../debug/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 6957 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 13447 bytes .../res/values/ic_launcher_background.xml | 4 ++ 14 files changed, 72 insertions(+) create mode 100644 app/src/debug/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/debug/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/debug/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/debug/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/debug/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/debug/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/debug/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/debug/res/values/ic_launcher_background.xml diff --git a/app/src/debug/res/drawable/ic_launcher_foreground.xml b/app/src/debug/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 000000000..6be799094 --- /dev/null +++ b/app/src/debug/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..7353dbd1f --- /dev/null +++ b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..7353dbd1f --- /dev/null +++ b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/debug/res/mipmap-hdpi/ic_launcher.png b/app/src/debug/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..5b688d7cbff579fe4a06fe19d9f7035a34d7ce43 GIT binary patch literal 2451 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 literal 0 HcmV?d00001 diff --git a/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..81e723eccf63eb93c41506650615abaf157a8f93 GIT binary patch literal 4369 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 Sp4|)#3=E#GelF{r5}E)q0tuu5 literal 0 HcmV?d00001 diff --git a/app/src/debug/res/mipmap-mdpi/ic_launcher.png b/app/src/debug/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..48b13240cafe343673a9d76341f8b77e70026987 GIT binary patch literal 1756 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F~)omuG<5-xIV z`PErbKD{eDGZ(1|iL^yBum=XPFfLXxowjL42X|HoPiNQZ`LAYl2pAd)i3dDtaui@p zTw$_lXOo!YMAz)ln4py7jt)xR`25c2A6*vd z>vPvFWnt^v_3EYNtvN~jht2$yE?(F1o_Qki=f%Gdl*OmZuM+86DH`-rq`0Ggw(Xba zxdES5xsH~L_Vpbj8FZ&{2$+_xIugLp-Q#d%ismJKhWWW33l|in zKmX6!uvppl)7Pc5n%P&rJHolDyL<7n9-gd#l`E1iDxGFqQBb;cmUH`x)e9R(puAvSU`4_x6^Qz6{cuc3PKvLCrItEH8g`U;pzB&+gmQ`GkkB zSzxkqijnFhM@2We14mo0u(JM@djIatl4I51HO`;!4|@Cd_Yr||_6CE~LRCUSPO|*+ zT+4Rfy1g>xyxgvRWx7vwBAp_OpTC-U-OJQL<;=7r=MNoTxo$H#S@7=S)W#y7fd#hVb?L}O~6zZ-wN<=bT`TOeZ?3FqH>vpw0 zzOL>cbbEF9mCILM-s z-lW8!4%Bc- zUA4cseOF-bkH7Zk=SrJ7ESfvFYO^N8DjVD1*Xmz?e(uD&iaj7YTG}+xbE=%R+w|rp zjogDwTDP|M&$>9*?&R5}pLduEdM9f5WEbXXi}aTkK&RQri_m<}2i6WrwX_cJ;;!rf28X>$iwHYaX~7D%|k#xn=Q{yrhi` z4>C;{rkwgUWy-#DpY=@&{q@St>+2y)vBST9{P^M2x+-+a)Tycr1|9nEt_5uj|FO_Ib+V<5m& z+~Ljb_UYKMW8Y?`oSkPI-LSjpY1f95lJkWo33pB~oICeLNw4n}7x&kYW|n8tVtLp4 zk}Nm8WZEMxE9;w?nYpFtsaN96CyQF#+}wg(Tv&7uKEJs_=&hN1V|uLkf^ez6mO$kI zu8z|`K6&qQa=lbGYof)o$j{%uiwjNBo@Bi4q3YrHy3yO#tT)=|d9JfHL;shdzn`C< zR3A&xu^pagc&BAGT(gK%TP!exx2-ARk2pi^sz0(aCjTV<%E-2F<(K$!{_Z13g`gev z2Q9;l`s_oWZxsGqA+^?JhT{J_w)V+wcMHlM9aQL1yc?%c^C{(K1H-L$HbXPB$?s35 z_&z;caUif~Hs8D3!98obb*g`_Ghvvsb!%>%UFIay>X0s%#q8BbzPw$ZRLHf+K~#oy zU#yA49N`-26ZUC3OTYDHEY-Yq%S!g%F)iK-H?vcTcPuEXDxIe+;TnOqkcT5M_BXTEt&K-Dn~`=gTe~DWM4fGLlN- literal 0 HcmV?d00001 diff --git a/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..394b5707650277a585ca2ea7cd3bf0d446e86a33 GIT binary patch literal 2798 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 m_9a{KcgkZ9tK>0JyA3=E#GelF{r5}E*`xJ=Ig literal 0 HcmV?d00001 diff --git a/app/src/debug/res/mipmap-xhdpi/ic_launcher.png b/app/src/debug/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..ff8bfa3e9118ca1886aca579b3a8866f51b476ce GIT binary patch literal 3378 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 KKbLh*2~7a>_(fCz literal 0 HcmV?d00001 diff --git a/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..365b4d663a8eae4600393c92446ebcbb629b0d1b GIT binary patch literal 6193 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 literal 0 HcmV?d00001 diff --git a/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..463c089b3e4df8c3a886cba98803ca235999570c GIT binary patch literal 9606 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 literal 0 HcmV?d00001 diff --git a/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..57c7416f196958125b5c9b29dcf7d99e0e08bcd2 GIT binary patch literal 6957 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

fpbE8Z1P)v7$OIK7oi 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 + + #D32F2F + \ No newline at end of file From 4e1fd6b2cfeaa5674085f8170d52f8ab7f11e013 Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Thu, 3 Jan 2019 09:49:54 +0100 Subject: [PATCH 002/192] English translation fix (#204) --- app/src/main/res/values/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e7cde31c1..20df69b9e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -91,7 +91,7 @@ Group Hours Changes - No lesson in this day + No lessons on this day @@ -192,7 +192,7 @@ - No lesson + No lessons Today Tomorrow @@ -214,7 +214,7 @@ Automatic update Suspended on holiday Updates interval - Only WiFi + Wi-Fi only From ca504f6efcf3a19f5b3b4ffb6229dc1b909df773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 6 Jan 2019 23:53:20 +0100 Subject: [PATCH 003/192] Change icon of the attendance summary (#206) --- app/build.gradle | 6 +++--- .../res/drawable/ic_menu_main_attendance_summary_24dp.xml | 5 +++++ app/src/main/res/menu/action_menu_attendance.xml | 4 ++-- app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 5 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 app/src/main/res/drawable/ic_menu_main_attendance_summary_24dp.xml diff --git a/app/build.gradle b/app/build.gradle index f9b6f3d3e..e2f144b2c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -84,13 +84,13 @@ configurations.all { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation('io.github.wulkanowy:api:0.6.0') { exclude module: "threetenbp" } + implementation('com.github.wulkanowy:api:fe371b2') { exclude module: "threetenbp" } implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.appcompat:appcompat:1.0.2" implementation "androidx.cardview:cardview:1.0.0" implementation "com.google.android.material:material:1.0.0" - implementation 'androidx.multidex:multidex:2.0.0' + implementation 'androidx.multidex:multidex:2.0.1' implementation 'com.takisoft.preferencex:preferencex:1.0.0' implementation "com.mikepenz:aboutlibraries:6.2.0" @@ -120,7 +120,7 @@ dependencies { implementation "at.favre.lib:slf4j-timber:1.0.1" implementation 'com.google.firebase:firebase-core:16.0.6' - implementation 'com.crashlytics.sdk.android:crashlytics:2.9.7' + implementation 'com.crashlytics.sdk.android:crashlytics:2.9.8' debugImplementation "com.amitshekhar.android:debug-db:1.0.4" diff --git a/app/src/main/res/drawable/ic_menu_main_attendance_summary_24dp.xml b/app/src/main/res/drawable/ic_menu_main_attendance_summary_24dp.xml new file mode 100644 index 000000000..13cfc8fad --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_main_attendance_summary_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/menu/action_menu_attendance.xml b/app/src/main/res/menu/action_menu_attendance.xml index efafe135c..94baf338c 100644 --- a/app/src/main/res/menu/action_menu_attendance.xml +++ b/app/src/main/res/menu/action_menu_attendance.xml @@ -3,8 +3,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 0e6d7e38a..f2e48b4da 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -104,6 +104,7 @@ + Podsumowanie frekwencji Nieobecny z przyczyn szkolnych Nieobecność usprawiedliwiona Nieobecność nieusprawiedliwiona diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 20df69b9e..a4cb76952 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -95,6 +95,7 @@ + Attendance summary Absent for school reasons Excused absence Unexcused absence From 450ae4e124b44a0420bde8d8c7312527d89edfc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 6 Jan 2019 23:56:01 +0100 Subject: [PATCH 004/192] Fix item sorting in grades details (#209) --- .../wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt index b80a71089..bc3b6c1e9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt @@ -97,6 +97,7 @@ class GradeDetailsPresenter @Inject constructor( disposable.add(studentRepository.getCurrentStudent() .flatMap { semesterRepository.getSemesters(it) } .flatMap { gradeRepository.getGrades(it.first { item -> item.semesterId == semesterId }, forceRefresh) } + .map { it.sortedByDescending { grade -> grade.date } } .map { it.map { item -> item.changeModifier(preferencesRepository.gradePlusModifier, preferencesRepository.gradeMinusModifier) } } .map { createGradeItems(it.groupBy { grade -> grade.subject }.toSortedMap()) } .subscribeOn(schedulers.backgroundThread) From b9ac592ea94494ee87bcb640ad378dcbf7607cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Mon, 7 Jan 2019 00:55:39 +0100 Subject: [PATCH 005/192] Fix broken grade summary view (#208) --- .../grade/summary/GradeSummaryHeader.kt | 52 -------- .../modules/grade/summary/GradeSummaryItem.kt | 27 +++-- .../grade/summary/GradeSummaryPresenter.kt | 25 ++-- .../main/res/layout/header_grade_summary.xml | 30 ----- .../main/res/layout/item_grade_summary.xml | 113 ++++++++++++++---- 5 files changed, 115 insertions(+), 132 deletions(-) delete mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryHeader.kt delete mode 100644 app/src/main/res/layout/header_grade_summary.xml diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryHeader.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryHeader.kt deleted file mode 100644 index fba3fde62..000000000 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryHeader.kt +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.wulkanowy.ui.modules.grade.summary - -import android.view.View -import eu.davidea.flexibleadapter.FlexibleAdapter -import eu.davidea.flexibleadapter.items.AbstractHeaderItem -import eu.davidea.flexibleadapter.items.IFlexible -import eu.davidea.viewholders.FlexibleViewHolder -import io.github.wulkanowy.R -import kotlinx.android.extensions.LayoutContainer -import kotlinx.android.synthetic.main.header_grade_summary.* - -class GradeSummaryHeader(private val name: String, private val average: String) : AbstractHeaderItem() { - - override fun getLayoutRes() = R.layout.header_grade_summary - - override fun createViewHolder(view: View?, adapter: FlexibleAdapter>?): ViewHolder { - return ViewHolder(view, adapter) - } - - override fun bindViewHolder(adapter: FlexibleAdapter>?, holder: ViewHolder?, - position: Int, payloads: MutableList?) { - holder?.run { - gradeSummaryHeaderName.text = name - gradeSummaryHeaderAverage.text = average - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as GradeSummaryHeader - - if (name != other.name) return false - if (average != other.average) return false - - return true - } - - override fun hashCode(): Int { - var result = name.hashCode() - result = 31 * result + average.hashCode() - return result - } - - class ViewHolder(view: View?, adapter: FlexibleAdapter>?) : - FlexibleViewHolder(view, adapter), LayoutContainer { - - override val containerView: View? - get() = contentView - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt index 54302fa60..0daf06657 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryItem.kt @@ -2,16 +2,19 @@ package io.github.wulkanowy.ui.modules.grade.summary import android.view.View import eu.davidea.flexibleadapter.FlexibleAdapter -import eu.davidea.flexibleadapter.items.AbstractSectionableItem +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.viewholders.FlexibleViewHolder import io.github.wulkanowy.R -import io.github.wulkanowy.data.db.entities.GradeSummary import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.main.item_grade_summary.* -class GradeSummaryItem(header: GradeSummaryHeader, private val grade: String, private val title: String) : - AbstractSectionableItem(header) { +class GradeSummaryItem( + private val title: String, + private val average: String, + private val predictedGrade: String, + private val finalGrade: String +) : AbstractFlexibleItem() { override fun getLayoutRes() = R.layout.item_grade_summary @@ -24,8 +27,10 @@ class GradeSummaryItem(header: GradeSummaryHeader, private val grade: String, pr position: Int, payloads: MutableList? ) { holder?.run { - gradeSummaryItemGrade.text = grade gradeSummaryItemTitle.text = title + gradeSummaryItemAverage.text = average + gradeSummaryItemPredicted.text = predictedGrade + gradeSummaryItemFinal.text = finalGrade } } @@ -35,17 +40,19 @@ class GradeSummaryItem(header: GradeSummaryHeader, private val grade: String, pr other as GradeSummaryItem - if (grade != other.grade) return false + if (average != other.average) return false if (title != other.title) return false - if (header != other.header) return false + if (predictedGrade != other.predictedGrade) return false + if (finalGrade != other.finalGrade) return false return true } override fun hashCode(): Int { - var result = header.hashCode() - result = 31 * result + grade.hashCode() - result = 31 * result + title.hashCode() + var result = title.hashCode() + result = 31 * result + average.hashCode() + result = 31 * result + predictedGrade.hashCode() + result = 31 * result + finalGrade.hashCode() return result } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt index a67ad8940..7920ca288 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt @@ -99,23 +99,14 @@ class GradeSummaryPresenter @Inject constructor( private fun createGradeSummaryItems(gradesSummary: List, averages: Map) : List { - return gradesSummary.filter { !checkEmpty(it, averages) } - .flatMap { gradeSummary -> - GradeSummaryHeader( - name = gradeSummary.subject, - average = formatAverage(averages.getOrElse(gradeSummary.subject) { 0.0 }, "") - ).let { - listOf(GradeSummaryItem( - header = it, - title = view?.predictedString.orEmpty(), - grade = gradeSummary.predictedGrade - ), GradeSummaryItem( - header = it, - title = view?.finalString.orEmpty(), - grade = gradeSummary.finalGrade - )) - } - } + return gradesSummary.filter { !checkEmpty(it, averages) }.map { it -> + GradeSummaryItem( + title = it.subject, + average = formatAverage(averages.getOrElse(it.subject) { 0.0 }, ""), + predictedGrade = it.predictedGrade, + finalGrade = it.finalGrade + ) + } } private fun checkEmpty(gradeSummary: GradeSummary, averages: Map): Boolean { diff --git a/app/src/main/res/layout/header_grade_summary.xml b/app/src/main/res/layout/header_grade_summary.xml deleted file mode 100644 index 3dca71e7a..000000000 --- a/app/src/main/res/layout/header_grade_summary.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/item_grade_summary.xml b/app/src/main/res/layout/item_grade_summary.xml index 81d7693e5..a650e9dc5 100644 --- a/app/src/main/res/layout/item_grade_summary.xml +++ b/app/src/main/res/layout/item_grade_summary.xml @@ -1,31 +1,98 @@ + + android:orientation="vertical"> - + android:background="?colorControlHighlight" + android:orientation="horizontal" + android:paddingLeft="20dp" + android:paddingTop="7dp" + android:paddingRight="20dp" + android:paddingBottom="7dp"> - + + + + + + android:background="@drawable/ic_all_divider" + android:minHeight="35dp" + android:orientation="horizontal"> + + + + + + + + + + + + From ea6a928cb4c07d20343c3b435f12e478073bf1b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Mon, 7 Jan 2019 00:56:32 +0100 Subject: [PATCH 006/192] Fix spinner dropdown arrow not displaying in attendance summary (#207) --- .../summary/AttendanceSummaryFragment.kt | 3 +- .../layout/fragment_attendance_summary.xml | 33 +++++++++++++---- .../res/layout/item_attendance_summary.xml | 37 ++++++++++--------- .../item_attendance_summary_subject.xml | 1 + 4 files changed, 48 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt index 1a3fc16f8..8f36d7468 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryFragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.View.GONE +import android.view.View.INVISIBLE import android.view.View.VISIBLE import android.view.ViewGroup import android.widget.ArrayAdapter @@ -101,7 +102,7 @@ class AttendanceSummaryFragment : BaseSessionFragment(), AttendanceSummaryView, } override fun showSubjects(show: Boolean) { - attendanceSummarySubjects.visibility = if (show) VISIBLE else VISIBLE + attendanceSummarySubjectsContainer.visibility = if (show) VISIBLE else INVISIBLE } override fun hideRefresh() { diff --git a/app/src/main/res/layout/fragment_attendance_summary.xml b/app/src/main/res/layout/fragment_attendance_summary.xml index a3bdeb489..5d03c2f4b 100644 --- a/app/src/main/res/layout/fragment_attendance_summary.xml +++ b/app/src/main/res/layout/fragment_attendance_summary.xml @@ -2,22 +2,40 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + tools:context=".ui.modules.attendance.summary.AttendanceSummaryFragment"> - + android:padding="5dp" + android:visibility="invisible" + tools:listitem="@layout/item_attendance_summary" + tools:targetApi="lollipop" + tools:visibility="visible"> + + + + android:layout_height="match_parent" + tools:listitem="@layout/item_attendance_summary" /> diff --git a/app/src/main/res/layout/item_attendance_summary.xml b/app/src/main/res/layout/item_attendance_summary.xml index 9a2540384..07392e56f 100644 --- a/app/src/main/res/layout/item_attendance_summary.xml +++ b/app/src/main/res/layout/item_attendance_summary.xml @@ -1,5 +1,6 @@ @@ -21,16 +22,16 @@ android:layout_marginEnd="40dp" android:layout_marginRight="40dp" android:layout_weight="1" - android:text="@string/app_name" - android:textSize="17sp" /> + android:textSize="17sp" + tools:text="January" /> + android:textSize="12sp" + tools:text="75%" /> + android:textSize="12sp" + tools:text="50" /> + android:textSize="12sp" + tools:text="0" /> + android:textSize="12sp" + tools:text="25" /> + android:textSize="12sp" + tools:text="0" /> + android:textSize="12sp" + tools:text="6" /> + android:textSize="12sp" + tools:text="0" /> + android:textSize="12sp" + tools:text="0" /> diff --git a/app/src/main/res/layout/item_attendance_summary_subject.xml b/app/src/main/res/layout/item_attendance_summary_subject.xml index ce8e9b5ee..6e19a0817 100644 --- a/app/src/main/res/layout/item_attendance_summary_subject.xml +++ b/app/src/main/res/layout/item_attendance_summary_subject.xml @@ -10,5 +10,6 @@ android:paddingRight="16dp" android:textAlignment="textStart" android:paddingBottom="12dp" + android:ellipsize="end" android:text="@string/app_name" android:textSize="16sp" /> From a9e788f7ffac494ae01a2c86043a7e499adfa771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Mon, 7 Jan 2019 12:52:55 +0100 Subject: [PATCH 007/192] Fix scroll to start in grade fragment (#210) --- .../wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt | 2 +- .../wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt index a9ee9ce2b..e1bc1e9b2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt @@ -103,7 +103,7 @@ class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView. } override fun scrollToStart() { - gradeDetailsAdapter.smoothScrollToPosition(0) + gradeDetailsRecycler.scrollToPosition(0) } override fun getHeaderOfItem(item: AbstractFlexibleItem<*>): IExpandable<*, out IFlexible<*>>? { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt index 13833b74a..67e7d4614 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryFragment.kt @@ -71,7 +71,7 @@ class GradeSummaryFragment : BaseSessionFragment(), GradeSummaryView, GradeView. } override fun resetView() { - gradeSummaryAdapter.smoothScrollToPosition(0) + gradeSummaryRecycler.scrollToPosition(0) } override fun showContent(show: Boolean) { From d2a736295a97c5e2c2a6ad83a46c2a98428385a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Mon, 7 Jan 2019 13:31:49 +0100 Subject: [PATCH 008/192] Version 0.6.2 --- app/build.gradle | 10 +++------- app/src/main/play/pl-PL/whatsnew | 22 ++++++++-------------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e2f144b2c..9325c91c7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,8 +23,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 28 - versionCode 20 - versionName "0.6.1" + versionCode 21 + versionName "0.6.2" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true @@ -77,14 +77,10 @@ play { uploadImages = false } -configurations.all { - resolutionStrategy.force "com.squareup.okhttp3:okhttp-urlconnection:3.11.0" -} - dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation('com.github.wulkanowy:api:fe371b2') { exclude module: "threetenbp" } + implementation('io.github.wulkanowy:api:0.6.2') { exclude module: "threetenbp" } implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.appcompat:appcompat:1.0.2" diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/pl-PL/whatsnew index e6916874a..65998b20a 100644 --- a/app/src/main/play/pl-PL/whatsnew +++ b/app/src/main/play/pl-PL/whatsnew @@ -1,16 +1,10 @@ -Wersja 0.6.0 +Wersja 0.6.2 -Aplikacja została całkowicie przepisana! -Przez wielkie zmian, które w niej zaszły, wymagane jest ponowne logowanie w aplikacji -oraz ponowne dodanie widgetu planu lekcji do ekranu głównego. +- zmieniono ikonę podsumowania frekwencji +- naprawiono niepokazującą się strzałkę przy przedmiotach w podsumowaniu frekwencji +- naprawiono sortowanie ocen +- naprawiono zepsuty widok podsumowania frekwencji +- naprawiono przeglądanie skrzynki nadawczej na kontach opiekunów +- naprawiono logowanie w systemach Resman Rzeszów i podobnych -Mamy nową ikonę aplikacji! 🎉 - -Dodaliśmy nowe funkcje: -- przeglądanie wiadomości (wysyłanie pojawi się w przyszłości) -- zadania domowe -- statystyki frekwencji -- menadżer kont -- możliwość zmiany wagi plusów i minusów - -Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.6.0 +Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.6.2 From 7d1866c3041b3687656c3223d46fbf2e7c02d8a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Wed, 9 Jan 2019 17:29:55 +0100 Subject: [PATCH 009/192] Fix NPE on error dialog (#212) --- app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt index 667b46ffe..6e863c511 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt @@ -13,7 +13,7 @@ abstract class BaseFragment : DaggerFragment(), BaseView { if (messageContainer == null) (activity as? BaseActivity)?.showError(text, error) else messageContainer?.also { Snackbar.make(it, text, Snackbar.LENGTH_LONG).setAction(R.string.all_details) { - ErrorDialog.newInstance(error).show(fragmentManager, error.toString()) + ErrorDialog.newInstance(error).show(childFragmentManager, error.toString()) }.show() } } From ed49eb4c9c18f8d8cd119ccb8f45b3ed6e9f0cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Wed, 9 Jan 2019 17:30:31 +0100 Subject: [PATCH 010/192] Fix stable id in grade fragment (#211) --- .../wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt index 5dec00a9f..b58ac8c93 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt @@ -52,6 +52,8 @@ class GradeDetailsHeader( if (subject != other.subject) return false if (number != other.number) return false if (average != other.average) return false + if (newGrades != other.newGrades) return false + if (isExpandable != other.isExpandable) return false return true } @@ -60,6 +62,8 @@ class GradeDetailsHeader( var result = subject.hashCode() result = 31 * result + number.hashCode() result = 31 * result + average.hashCode() + result = 31 * result + newGrades + result = 31 * result + isExpandable.hashCode() return result } From c3d354cd5b4dd9c8a75a4239dc2180e7271ea412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Thu, 10 Jan 2019 17:10:10 +0100 Subject: [PATCH 011/192] Add chucker okhttp inspector (#205) --- .travis.yml | 4 ++++ app/build.gradle | 5 ++++- app/src/main/AndroidManifest.xml | 2 ++ .../github/wulkanowy/data/RepositoryModule.kt | 17 ++++++++++++++++- .../data/repositories/PreferencesRepository.kt | 4 ++++ .../io/github/wulkanowy/ui/base/ErrorHandler.kt | 4 +++- .../ui/base/session/SessionErrorHandler.kt | 3 ++- .../ui/modules/login/LoginErrorHandler.kt | 3 ++- .../ui/modules/settings/SettingsFragment.kt | 2 ++ .../ui/modules/settings/SettingsPresenter.kt | 8 +++++++- app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values/preferences_keys.xml | 1 + app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/scheme_preferences.xml | 5 +++++ 14 files changed, 54 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index a430c90ef..e144bdd77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,10 @@ cache: - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/ +branches: + only: + - master + android: licenses: - android-sdk-preview-license-.+ diff --git a/app/build.gradle b/app/build.gradle index 9325c91c7..5aa3a521a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -80,7 +80,7 @@ play { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation('io.github.wulkanowy:api:0.6.2') { exclude module: "threetenbp" } + implementation('io.github.wulkanowy:api:0.6.3') { exclude module: "threetenbp" } implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.appcompat:appcompat:1.0.2" @@ -118,6 +118,9 @@ dependencies { implementation 'com.google.firebase:firebase-core:16.0.6' implementation 'com.crashlytics.sdk.android:crashlytics:2.9.8' + releaseImplementation 'fr.o80.chucker:library-no-op:2.0.3' + debugImplementation 'fr.o80.chucker:library:2.0.3' + debugImplementation "com.amitshekhar.android:debug-db:1.0.4" testImplementation "junit:junit:4.12" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 10fe53119..2bc7e0a91 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,8 @@ package="io.github.wulkanowy" android:installLocation="internalOnly"> + + diff --git a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt index 3c58ea4bd..f5bb1b2a4 100644 --- a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt +++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt @@ -6,10 +6,14 @@ import android.content.res.Resources import androidx.preference.PreferenceManager import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.SocketInternetObservingStrategy +import com.readystatesoftware.chuck.api.ChuckCollector +import com.readystatesoftware.chuck.api.ChuckInterceptor +import com.readystatesoftware.chuck.api.RetentionManager import dagger.Module import dagger.Provides import io.github.wulkanowy.api.Api import io.github.wulkanowy.data.db.AppDatabase +import io.github.wulkanowy.data.repositories.PreferencesRepository import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor.Level.BASIC import okhttp3.logging.HttpLoggingInterceptor.Level.NONE @@ -30,15 +34,26 @@ internal class RepositoryModule { @Singleton @Provides - fun provideApi(): Api { + fun provideApi(chuckCollector: ChuckCollector, context: Context): Api { return Api().apply { logLevel = NONE androidVersion = android.os.Build.VERSION.RELEASE buildTag = android.os.Build.MODEL setInterceptor(HttpLoggingInterceptor(HttpLoggingInterceptor.Logger { Timber.d(it) }).setLevel(BASIC)) + + // for debug only + setInterceptor(ChuckInterceptor(context, chuckCollector).maxContentLength(250000L), true, 0) } } + @Singleton + @Provides + fun provideChuckCollector(context: Context, prefRepository: PreferencesRepository): ChuckCollector { + return ChuckCollector(context) + .showNotification(prefRepository.isShowChuckerNotification) + .retentionManager(RetentionManager(context, ChuckCollector.Period.ONE_HOUR)) + } + @Singleton @Provides fun provideDatabase(context: Context) = AppDatabase.newInstance(context) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt index 205baa3aa..d83ae667d 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt @@ -44,4 +44,8 @@ class PreferencesRepository @Inject constructor( val isNotificationsEnable: Boolean get() = sharedPref.getBoolean(context.getString(R.string.pref_key_notifications_enable), true) + + val isShowChuckerNotificationKey: String = context.getString(R.string.pref_key_debug_chucker_notification) + val isShowChuckerNotification: Boolean + get() = sharedPref.getBoolean(isShowChuckerNotificationKey, false) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt index e0e32e2c8..a8f210e67 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.base import android.content.res.Resources +import com.readystatesoftware.chuck.api.ChuckCollector import io.github.wulkanowy.R import io.github.wulkanowy.api.interceptor.ServiceUnavailableException import io.github.wulkanowy.api.login.NotLoggedInException @@ -9,11 +10,12 @@ import java.net.SocketTimeoutException import java.net.UnknownHostException import javax.inject.Inject -open class ErrorHandler @Inject constructor(protected val resources: Resources) { +open class ErrorHandler @Inject constructor(protected val resources: Resources, private val chuckCollector: ChuckCollector) { var showErrorMessage: (String, Throwable) -> Unit = { _, _ -> } fun dispatch(error: Throwable) { + chuckCollector.onError(error.javaClass.simpleName, error) Timber.e(error, "An exception occurred while the Wulkanowy was running") proceed(error) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/session/SessionErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/base/session/SessionErrorHandler.kt index 89654732a..f8ea6e3db 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/session/SessionErrorHandler.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/session/SessionErrorHandler.kt @@ -1,11 +1,12 @@ package io.github.wulkanowy.ui.base.session import android.content.res.Resources +import com.readystatesoftware.chuck.api.ChuckCollector import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.security.ScramblerException import javax.inject.Inject -class SessionErrorHandler @Inject constructor(resources: Resources) : ErrorHandler(resources) { +class SessionErrorHandler @Inject constructor(resources: Resources, chuckCollector: ChuckCollector) : ErrorHandler(resources, chuckCollector) { var onDecryptionFail: () -> Unit = {} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt index 40f1d711c..18c3a422a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt @@ -2,12 +2,13 @@ package io.github.wulkanowy.ui.modules.login import android.content.res.Resources import android.database.sqlite.SQLiteConstraintException +import com.readystatesoftware.chuck.api.ChuckCollector import io.github.wulkanowy.R import io.github.wulkanowy.api.login.BadCredentialsException import io.github.wulkanowy.ui.base.ErrorHandler import javax.inject.Inject -class LoginErrorHandler @Inject constructor(resources: Resources) : ErrorHandler(resources) { +class LoginErrorHandler @Inject constructor(resources: Resources, chuckCollector: ChuckCollector) : ErrorHandler(resources, chuckCollector) { var onBadCredentials: () -> Unit = {} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt index 7273e8e9a..57fcea099 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt @@ -6,6 +6,7 @@ import android.os.Bundle import androidx.appcompat.app.AppCompatDelegate import com.takisoft.preferencex.PreferenceFragmentCompat import dagger.android.support.AndroidSupportInjection +import io.github.wulkanowy.BuildConfig import io.github.wulkanowy.R import io.github.wulkanowy.ui.base.BaseActivity import io.github.wulkanowy.ui.modules.main.MainView @@ -36,6 +37,7 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.scheme_preferences) + findPreference(getString(R.string.pref_key_debug_chucker_notification)).isVisible = BuildConfig.DEBUG } override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt index 403689138..6a2087558 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt @@ -1,5 +1,7 @@ package io.github.wulkanowy.ui.modules.settings +import com.readystatesoftware.chuck.api.ChuckCollector +import io.github.wulkanowy.data.RepositoryModule_ProvideChuckCollectorFactory import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.services.job.ServiceHelper import io.github.wulkanowy.ui.base.BasePresenter @@ -13,7 +15,8 @@ class SettingsPresenter @Inject constructor( errorHandler: ErrorHandler, private val preferencesRepository: PreferencesRepository, private val serviceHelper: ServiceHelper, - private val analytics: FirebaseAnalyticsHelper + private val analytics: FirebaseAnalyticsHelper, + private val chuckCollector: ChuckCollector ) : BasePresenter(errorHandler) { override fun onAttachView(view: SettingsView) { @@ -37,6 +40,9 @@ class SettingsPresenter @Inject constructor( preferencesRepository.currentThemeKey -> { view?.setTheme(preferencesRepository.currentTheme) } + preferencesRepository.isShowChuckerNotificationKey -> { + chuckCollector.showNotification(preferencesRepository.isShowChuckerNotification) + } } analytics.logEvent("setting_changed", mapOf("name" to key)) diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index f2e48b4da..3c4a4ebba 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -227,6 +227,7 @@ Powiadomienia Pokazuj powiadomienia + Pokazuj powiadomienia debugowania Synchronizacja Automatyczna aktualizacja diff --git a/app/src/main/res/values/preferences_keys.xml b/app/src/main/res/values/preferences_keys.xml index ea2585e79..54cc2bbde 100644 --- a/app/src/main/res/values/preferences_keys.xml +++ b/app/src/main/res/values/preferences_keys.xml @@ -10,4 +10,5 @@ services_interval services_disable_wifi_only notifications_enable + chucker_notification diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a4cb76952..f6140ad04 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -210,6 +210,7 @@ Notifications Show notifications + Show debug notifications Synchronization Automatic update diff --git a/app/src/main/res/xml/scheme_preferences.xml b/app/src/main/res/xml/scheme_preferences.xml index 1ba8885a6..575fea63d 100644 --- a/app/src/main/res/xml/scheme_preferences.xml +++ b/app/src/main/res/xml/scheme_preferences.xml @@ -80,5 +80,10 @@ android:key="@string/pref_key_notifications_enable" android:title="@string/pref_notify_switch" app:iconSpaceReserved="false" /> + From c2bcbfaaa9a635bbc4e03a9d86e219913b743f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sat, 12 Jan 2019 14:16:59 +0100 Subject: [PATCH 012/192] Add grade id to equals (#213) --- .../modules/grade/details/GradeDetailsHeader.kt | 2 -- .../ui/modules/grade/details/GradeDetailsItem.kt | 15 +++++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt index b58ac8c93..0515208eb 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsHeader.kt @@ -52,7 +52,6 @@ class GradeDetailsHeader( if (subject != other.subject) return false if (number != other.number) return false if (average != other.average) return false - if (newGrades != other.newGrades) return false if (isExpandable != other.isExpandable) return false return true @@ -62,7 +61,6 @@ class GradeDetailsHeader( var result = subject.hashCode() result = 31 * result + number.hashCode() result = 31 * result + average.hashCode() - result = 31 * result + newGrades result = 31 * result + isExpandable.hashCode() return result } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt index 18c2656d6..e522a7805 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt @@ -14,8 +14,8 @@ import io.github.wulkanowy.utils.toFormattedString import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.main.item_grade_details.* -class GradeDetailsItem(val grade: Grade, private val weightString: String, private val valueColor: Int) - : AbstractFlexibleItem() { +class GradeDetailsItem(val grade: Grade, private val weightString: String, private val valueColor: Int) : + AbstractFlexibleItem() { override fun getLayoutRes() = R.layout.item_grade_details @@ -24,8 +24,10 @@ class GradeDetailsItem(val grade: Grade, private val weightString: String, priva } @SuppressLint("SetTextI18n") - override fun bindViewHolder(adapter: FlexibleAdapter>, holder: ViewHolder, - position: Int, payloads: MutableList?) { + override fun bindViewHolder( + adapter: FlexibleAdapter>, holder: ViewHolder, + position: Int, payloads: MutableList? + ) { holder.run { gradeItemValue.run { text = grade.entry @@ -45,6 +47,7 @@ class GradeDetailsItem(val grade: Grade, private val weightString: String, priva other as GradeDetailsItem if (grade != other.grade) return false + if (grade.id != other.grade.id) return false if (weightString != other.weightString) return false if (valueColor != other.valueColor) return false @@ -53,14 +56,14 @@ class GradeDetailsItem(val grade: Grade, private val weightString: String, priva override fun hashCode(): Int { var result = grade.hashCode() + result = 31 * result + grade.id.toInt() result = 31 * result + weightString.hashCode() result = 31 * result + valueColor return result } - class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), - LayoutContainer { + LayoutContainer { override val containerView: View get() = contentView From 65230a31ec167adf20fb8c8482e1baeeb5230082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sat, 12 Jan 2019 14:41:23 +0100 Subject: [PATCH 013/192] Version 0.6.3 --- .travis.yml | 4 ---- app/build.gradle | 4 ++-- app/src/main/play/pl-PL/whatsnew | 13 +++++-------- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index e144bdd77..a430c90ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,10 +11,6 @@ cache: - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/ -branches: - only: - - master - android: licenses: - android-sdk-preview-license-.+ diff --git a/app/build.gradle b/app/build.gradle index 5aa3a521a..f60cbb008 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,8 +23,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 28 - versionCode 21 - versionName "0.6.2" + versionCode 22 + versionName "0.6.3" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/pl-PL/whatsnew index 65998b20a..81ff753b0 100644 --- a/app/src/main/play/pl-PL/whatsnew +++ b/app/src/main/play/pl-PL/whatsnew @@ -1,10 +1,7 @@ -Wersja 0.6.2 +Wersja 0.6.3 -- zmieniono ikonę podsumowania frekwencji -- naprawiono niepokazującą się strzałkę przy przedmiotach w podsumowaniu frekwencji -- naprawiono sortowanie ocen -- naprawiono zepsuty widok podsumowania frekwencji -- naprawiono przeglądanie skrzynki nadawczej na kontach opiekunów -- naprawiono logowanie w systemach Resman Rzeszów i podobnych +- naprawiono problem ze stabilnością przy odczytywaniu ocen +- poprawiono komunikat o błędzie podczas przerwy technicznej dziennika +- (ponownie) naprawiono logowanie w systemach Resman Rzeszów i podobnych -Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.6.2 +Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.6.3 From 840b21a21350d639d9871a31682a7b97bf5e205f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sun, 13 Jan 2019 23:25:07 +0100 Subject: [PATCH 014/192] Fix dialog state (#214) --- .../wulkanowy/ui/modules/attendance/AttendanceFragment.kt | 2 +- .../java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt | 3 ++- .../ui/modules/grade/details/GradeDetailsFragment.kt | 3 ++- .../github/wulkanowy/ui/modules/homework/HomeworkFragment.kt | 3 ++- .../java/io/github/wulkanowy/ui/modules/main/MainActivity.kt | 5 +++++ .../java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt | 3 ++- .../wulkanowy/ui/modules/timetable/TimetableFragment.kt | 3 ++- 7 files changed, 16 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt index 3b60d8cb7..cdbde5075 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendanceFragment.kt @@ -130,7 +130,7 @@ class AttendanceFragment : BaseSessionFragment(), AttendanceView, MainView.MainC } override fun showAttendanceDialog(lesson: Attendance) { - AttendanceDialog.newInstance(lesson).show(fragmentManager, lesson.toString()) + (activity as? MainActivity)?.showDialogFragment(AttendanceDialog.newInstance(lesson)) } override fun openSummaryView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt index d39688d4f..dcafeb2ee 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamFragment.kt @@ -13,6 +13,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_exam.* @@ -106,7 +107,7 @@ class ExamFragment : BaseSessionFragment(), ExamView, MainView.MainChildView, Ma } override fun showExamDialog(exam: Exam) { - ExamDialog.newInstance(exam).show(fragmentManager, exam.toString()) + (activity as? MainActivity)?.showDialogFragment(ExamDialog.newInstance(exam)) } override fun onSaveInstanceState(outState: Bundle) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt index e1bc1e9b2..01b18f4ba 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsFragment.kt @@ -20,6 +20,7 @@ import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.ui.base.session.BaseSessionFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment import io.github.wulkanowy.ui.modules.grade.GradeView +import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_grade_details.* import javax.inject.Inject @@ -131,7 +132,7 @@ class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView. } override fun showGradeDialog(grade: Grade) { - GradeDetailsDialog.newInstance(grade).show(fragmentManager, grade.toString()) + (activity as? MainActivity)?.showDialogFragment(GradeDetailsDialog.newInstance(grade)) } override fun onParentLoadData(semesterId: Int, forceRefresh: Boolean) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt index 135098fbd..4d9b74708 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt @@ -10,6 +10,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_homework.* @@ -95,7 +96,7 @@ class HomeworkFragment : BaseSessionFragment(), HomeworkView, MainView.TitledVie } override fun showTimetableDialog(homework: Homework) { - HomeworkDialog.newInstance(homework).show(fragmentManager, homework.toString()) + (activity as? MainActivity)?.showDialogFragment(HomeworkDialog.newInstance(homework)) } override fun onSaveInstanceState(outState: Bundle) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt index 58c2f7c95..58517302a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt @@ -7,6 +7,7 @@ import android.view.Menu import android.view.MenuItem import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat +import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState.ALWAYS_SHOW import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem @@ -147,6 +148,10 @@ class MainActivity : BaseActivity(), MainView { (navController.currentStack?.get(0) as? MainView.MainChildView)?.onFragmentReselected() } + fun showDialogFragment(dialog: DialogFragment) { + navController.showDialogFragment(dialog) + } + fun pushView(fragment: Fragment) { navController.pushFragment(fragment) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt index 243f25757..9ae8f83a2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteFragment.kt @@ -12,6 +12,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Note import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_note.* @@ -57,7 +58,7 @@ class NoteFragment : BaseSessionFragment(), NoteView, MainView.TitledView { } override fun showNoteDialog(note: Note) { - NoteDialog.newInstance(note).show(fragmentManager, note.toString()) + (activity as? MainActivity)?.showDialogFragment(NoteDialog.newInstance(note)) } override fun updateData(data: List) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt index faf17665a..71c2f70ba 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetableFragment.kt @@ -10,6 +10,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_timetable.* @@ -107,7 +108,7 @@ class TimetableFragment : BaseSessionFragment(), TimetableView, MainView.MainChi } override fun showTimetableDialog(lesson: Timetable) { - TimetableDialog.newInstance(lesson).show(fragmentManager, lesson.toString()) + (activity as? MainActivity)?.showDialogFragment(TimetableDialog.newInstance(lesson)) } override fun onSaveInstanceState(outState: Bundle) { From 28f1430be0d64f134b2327243178296cf4d468f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sun, 13 Jan 2019 23:53:01 +0100 Subject: [PATCH 015/192] Fix crash on Meizu devices (#215) --- app/src/main/res/layout/fragment_login_form.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/fragment_login_form.xml b/app/src/main/res/layout/fragment_login_form.xml index a2ee86474..e21e476b9 100644 --- a/app/src/main/res/layout/fragment_login_form.xml +++ b/app/src/main/res/layout/fragment_login_form.xml @@ -69,7 +69,7 @@ android:layout_marginBottom="15dp" android:hint="@string/login_nickname_hint"> - - Date: Fri, 18 Jan 2019 12:41:11 +0100 Subject: [PATCH 016/192] Fix exam_no_items english translation (#217) Changed `exam_no_items` from **No exams in this week** to **No exams this week** --- app/src/main/res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f6140ad04..be6cec495 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -91,7 +91,7 @@ Group Hours Changes - No lessons on this day + No lessons this day @@ -115,7 +115,7 @@ - No exams in this week + No exams this week Type Entry date From e6d60e670e2929748496936754a29171d432e382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Fri, 18 Jan 2019 19:10:14 +0100 Subject: [PATCH 017/192] Fix crash on duplicate notes (#218) --- .../java/io/github/wulkanowy/ui/modules/note/NoteItem.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteItem.kt index 97635a2c8..71562fc49 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteItem.kt @@ -46,11 +46,14 @@ class NoteItem(val note: Note) : AbstractFlexibleItem() { other as NoteItem if (note != other.note) return false + if (note.id != other.note.id) return false return true } override fun hashCode(): Int { - return note.hashCode() + var result = note.hashCode() + result = 31 * result + note.id.toInt() + return result } class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer { From c5bab52fa2824060a6f1bb0fbae873ff3289e61d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sat, 19 Jan 2019 23:15:14 +0100 Subject: [PATCH 018/192] Add more logging (#219) --- .../ui/modules/about/AboutPresenter.kt | 5 +++ .../ui/modules/account/AccountPresenter.kt | 38 ++++++++++++++++--- .../modules/attendance/AttendancePresenter.kt | 13 ++++++- .../summary/AttendanceSummaryPresenter.kt | 18 ++++++++- .../ui/modules/exam/ExamPresenter.kt | 13 ++++++- .../ui/modules/grade/GradePresenter.kt | 14 ++++++- .../grade/details/GradeDetailsPresenter.kt | 27 +++++++++++-- .../grade/summary/GradeSummaryPresenter.kt | 5 +++ .../ui/modules/homework/HomeworkPresenter.kt | 12 +++++- .../ui/modules/login/LoginPresenter.kt | 3 ++ .../modules/login/form/LoginFormPresenter.kt | 9 ++++- .../login/options/LoginOptionsPresenter.kt | 9 ++++- .../wulkanowy/ui/modules/main/MainActivity.kt | 4 +- .../ui/modules/main/MainPresenter.kt | 22 +++++++++-- .../ui/modules/message/MessagePresenter.kt | 3 ++ .../preview/MessagePreviewPresenter.kt | 6 ++- .../message/tab/MessageTabPresenter.kt | 15 ++++++-- .../ui/modules/more/MorePresenter.kt | 5 +++ .../ui/modules/note/NotePresenter.kt | 16 ++++++-- .../ui/modules/settings/SettingsPresenter.kt | 5 ++- .../modules/timetable/TimetablePresenter.kt | 15 +++++++- 21 files changed, 221 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt index 9a512f70f..fa421b60a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutPresenter.kt @@ -15,6 +15,11 @@ class AboutPresenter @Inject constructor( private val analytics: FirebaseAnalyticsHelper ) : BasePresenter(errorHandler) { + override fun onAttachView(view: AboutView) { + super.onAttachView(view) + Timber.i("About view is attached") + } + fun onExtraSelect(type: Libs.SpecialButton?) { view?.run { when (type) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt index e1459fe7d..c5f9b35dd 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/account/AccountPresenter.kt @@ -6,6 +6,7 @@ import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.SchedulersProvider import io.reactivex.Single +import timber.log.Timber import javax.inject.Inject class AccountPresenter @Inject constructor( @@ -16,19 +17,23 @@ class AccountPresenter @Inject constructor( override fun onAttachView(view: AccountView) { super.onAttachView(view) + Timber.i("Account dialog is attached") view.initView() loadData() } fun onAddSelected() { + Timber.i("Select add account") view?.openLoginView() } fun onRemoveSelected() { + Timber.i("Select remove account") view?.showConfirmDialog() } fun onLogoutConfirm() { + Timber.i("Attempt to logout current user ") disposable.add(studentRepository.getCurrentStudent() .flatMapCompletable { studentRepository.logoutStudent(it) } .andThen(studentRepository.getSavedStudents(false)) @@ -41,31 +46,54 @@ class AccountPresenter @Inject constructor( .doFinally { view?.dismissView() } .subscribe({ view?.apply { - if (it.isEmpty()) openClearLoginView() - else recreateView() + if (it.isEmpty()) { + Timber.i("Logout result: Open login view") + openClearLoginView() + } else { + Timber.i("Logout result: Switch to another student") + recreateView() + } } - }, { errorHandler.dispatch(it) })) + }, { + Timber.i("Logout result: An exception occurred") + errorHandler.dispatch(it) + })) } fun onItemSelected(item: AbstractFlexibleItem<*>) { if (item is AccountItem) { + Timber.i("Select student item ${item.student.id}") if (item.student.isCurrent) { view?.dismissView() } else { + Timber.i("Attempt to change a student") disposable.add(studentRepository.switchStudent(item.student) .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) - .subscribe({ view?.recreateView() }, { errorHandler.dispatch(it) })) + .subscribe({ + Timber.i("Change a student result: Success") + view?.recreateView() + }, { + Timber.i("Change a student result: An exception occurred") + errorHandler.dispatch(it) + })) } } } private fun loadData() { + Timber.i("Loading account data started") disposable.add(studentRepository.getSavedStudents(false) .map { it.map { item -> AccountItem(item) } } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) - .subscribe({ view?.updateData(it) }, { errorHandler.dispatch(it) })) + .subscribe({ + Timber.i("Loading account result: Success") + view?.updateData(it) + }, { + Timber.i("Loading account result: An exception occurred") + errorHandler.dispatch(it) + })) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt index 9be87b441..c2c5226c6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt @@ -18,6 +18,7 @@ import io.github.wulkanowy.utils.toFormattedString import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate.now import org.threeten.bp.LocalDate.ofEpochDay +import timber.log.Timber import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject @@ -36,6 +37,7 @@ class AttendancePresenter @Inject constructor( fun onAttachView(view: AttendanceView, date: Long?) { super.onAttachView(view) + Timber.i("Attendance view is attached") view.initView() loadData(ofEpochDay(date ?: now().previousOrSameSchoolDay.toEpochDay())) reloadView() @@ -52,10 +54,12 @@ class AttendancePresenter @Inject constructor( } fun onSwipeRefresh() { + Timber.i("Force refreshing the attendance") loadData(currentDate, true) } fun onViewReselected() { + Timber.i("Attendance view is reselected") view?.also { view -> if (view.currentStackSize == 1) { now().previousOrSameSchoolDay.also { @@ -69,7 +73,10 @@ class AttendancePresenter @Inject constructor( } fun onAttendanceItemSelected(item: AbstractFlexibleItem<*>?) { - if (item is AttendanceItem) view?.showAttendanceDialog(item.attendance) + if (item is AttendanceItem) { + Timber.i("Select attendance item ${item.attendance.id}") + view?.showAttendanceDialog(item.attendance) + } } fun onSummarySwitchSelected(): Boolean { @@ -78,6 +85,7 @@ class AttendancePresenter @Inject constructor( } private fun loadData(date: LocalDate, forceRefresh: Boolean = false) { + Timber.i("Loading attendance data started") currentDate = date disposable.apply { clear() @@ -100,6 +108,7 @@ class AttendancePresenter @Inject constructor( } } .subscribe({ + Timber.i("Loading attendance result: Success") view?.apply { updateData(it) showEmpty(it.isEmpty()) @@ -107,6 +116,7 @@ class AttendancePresenter @Inject constructor( } analytics.logEvent("load_attendance", mapOf("items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))) }) { + Timber.i("Loading attendance result: An exception occurred") view?.run { showEmpty(isViewEmpty) } errorHandler.dispatch(it) } @@ -115,6 +125,7 @@ class AttendancePresenter @Inject constructor( } private fun reloadView() { + Timber.i("Reload attendance view with the date ${currentDate.toFormattedString()}") view?.apply { showProgress(true) showContent(false) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt index 5086e80cc..26741f3cc 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt @@ -12,6 +12,7 @@ import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.calculatePercentage import io.github.wulkanowy.utils.getFormattedName +import timber.log.Timber import java.lang.String.format import java.util.Locale.FRANCE import java.util.concurrent.TimeUnit.MILLISECONDS @@ -34,25 +35,31 @@ class AttendanceSummaryPresenter @Inject constructor( fun onAttachView(view: AttendanceSummaryView, subjectId: Int?) { super.onAttachView(view) + Timber.i("Attendance summary view is attached with subject id ${subjectId ?: -1}") view.initView() loadData(subjectId ?: -1) loadSubjects() } fun onSwipeRefresh() { + Timber.i("Force refreshing the attendance summary") loadData(currentSubjectId, true) } fun onSubjectSelected(name: String) { + Timber.i("Select attendance summary subject $name") view?.run { showContent(false) showProgress(true) clearView() } - loadData(subjects.singleOrNull { it.name == name }?.realId ?: -1) + (subjects.singleOrNull { it.name == name }?.realId ?: -1).let { + if (it != currentSubjectId) loadData(it) + } } private fun loadData(subjectId: Int, forceRefresh: Boolean = false) { + Timber.i("Loading attendance summary data started") currentSubjectId = subjectId disposable.apply { clear() @@ -70,6 +77,7 @@ class AttendanceSummaryPresenter @Inject constructor( } } .subscribe({ + Timber.i("Loading attendance summary result: Success") view?.apply { showEmpty(it.first.isEmpty()) showContent(it.first.isNotEmpty()) @@ -77,6 +85,7 @@ class AttendanceSummaryPresenter @Inject constructor( } analytics.logEvent("load_attendance_summary", mapOf("items" to it.first.size, "force_refresh" to forceRefresh, "item_id" to subjectId)) }) { + Timber.i("Loading attendance summary result: An exception occurred") view?.run { showEmpty(isViewEmpty) } errorHandler.dispatch(it) } @@ -85,6 +94,7 @@ class AttendanceSummaryPresenter @Inject constructor( } private fun loadSubjects() { + Timber.i("Loading attendance summary subjects started") disposable.add(studentRepository.getCurrentStudent() .flatMap { semesterRepository.getCurrentSemester(it) } .flatMap { subjectRepository.getSubjects(it) } @@ -93,11 +103,15 @@ class AttendanceSummaryPresenter @Inject constructor( .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .subscribe({ + Timber.i("Loading attendance summary subjects result: Success") view?.run { view?.updateSubjects(it) showSubjects(true) } - }, { errorHandler.dispatch(it) }) + }, { + Timber.i("Loading attendance summary subjects result: An exception occurred") + errorHandler.dispatch(it) + }) ) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt index 88a0eaa53..150147ea1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt @@ -18,6 +18,7 @@ import io.github.wulkanowy.utils.toFormattedString import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate.now import org.threeten.bp.LocalDate.ofEpochDay +import timber.log.Timber import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject @@ -35,6 +36,7 @@ class ExamPresenter @Inject constructor( fun onAttachView(view: ExamView, date: Long?) { super.onAttachView(view) + Timber.i("Exam view is attached") view.initView() loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay())) reloadView() @@ -51,14 +53,19 @@ class ExamPresenter @Inject constructor( } fun onSwipeRefresh() { + Timber.i("Force refreshing the exam") loadData(currentDate, true) } fun onExamItemSelected(item: AbstractFlexibleItem<*>?) { - if (item is ExamItem) view?.showExamDialog(item.exam) + if (item is ExamItem) { + Timber.i("Select exam item ${item.exam.id}") + view?.showExamDialog(item.exam) + } } fun onViewReselected() { + Timber.i("Exam view is reselected") now().nextOrSameSchoolDay.also { if (currentDate != it) { loadData(it) @@ -68,6 +75,7 @@ class ExamPresenter @Inject constructor( } private fun loadData(date: LocalDate, forceRefresh: Boolean = false) { + Timber.i("Loading exam data started") currentDate = date disposable.apply { clear() @@ -87,6 +95,7 @@ class ExamPresenter @Inject constructor( } } .subscribe({ + Timber.i("Loading exam result: Success") view?.apply { updateData(it) showEmpty(it.isEmpty()) @@ -94,6 +103,7 @@ class ExamPresenter @Inject constructor( } analytics.logEvent("load_exam", mapOf("items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))) }) { + Timber.i("Loading exam result: An exception occurred") view?.run { showEmpty(isViewEmpty) } errorHandler.dispatch(it) }) @@ -109,6 +119,7 @@ class ExamPresenter @Inject constructor( } private fun reloadView() { + Timber.i("Reload exam view with the date ${currentDate.toFormattedString()}") view?.apply { showProgress(true) showContent(false) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt index d2dd8031e..ca6822654 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt @@ -8,6 +8,7 @@ import io.github.wulkanowy.ui.base.session.SessionErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.reactivex.Completable +import timber.log.Timber import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject @@ -28,6 +29,7 @@ class GradePresenter @Inject constructor( fun onAttachView(view: GradeView, savedIndex: Int?) { super.onAttachView(view) + Timber.i("Grade view is attached") disposable.add(Completable.timer(150, MILLISECONDS, schedulers.mainThread) .subscribe { selectedIndex = savedIndex ?: 0 @@ -37,6 +39,7 @@ class GradePresenter @Inject constructor( } fun onViewReselected() { + Timber.i("Grade view is reselected") view?.run { notifyChildParentReselected(currentPageIndex) } } @@ -47,6 +50,7 @@ class GradePresenter @Inject constructor( fun onSemesterSelected(index: Int) { if (selectedIndex != index - 1) { + Timber.i("Change semester in grade view to ${index + 1}") selectedIndex = index + 1 loadedSemesterId.clear() view?.let { @@ -74,6 +78,7 @@ class GradePresenter @Inject constructor( } private fun loadData() { + Timber.i("Loading grade data started") disposable.add(studentRepository.getCurrentStudent() .flatMap { semesterRepository.getSemesters(it) } .doOnSuccess { @@ -84,7 +89,13 @@ class GradePresenter @Inject constructor( } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) - .subscribe({ view?.run { loadChild(currentPageIndex) } }) { + .subscribe({ + view?.run { + Timber.i("Loading grade result: Attempt load index $currentPageIndex") + loadChild(currentPageIndex) + } + }) { + Timber.i("Loading grade result: An exception occurred") errorHandler.dispatch(it) view?.run { showProgress(false) @@ -96,6 +107,7 @@ class GradePresenter @Inject constructor( private fun loadChild(index: Int, forceRefresh: Boolean = false) { semesters.first { it.semesterName == selectedIndex }.semesterId.also { if (forceRefresh || loadedSemesterId[index] != it) { + Timber.i("Load grade child view index: $index") view?.notifyChildLoadData(index, it, forceRefresh) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt index bc3b6c1e9..16cc0fa07 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt @@ -40,6 +40,7 @@ class GradeDetailsPresenter @Inject constructor( fun onGradeItemSelected(item: AbstractFlexibleItem<*>?) { if (item is GradeDetailsItem) { + Timber.i("Select grade item ${item.grade.id}") view?.apply { showGradeDialog(item.grade) if (!item.grade.isRead) { @@ -58,18 +59,29 @@ class GradeDetailsPresenter @Inject constructor( } fun onMarkAsReadSelected(): Boolean { + Timber.i("Select mark grades as read") disposable.add(studentRepository.getCurrentStudent() .flatMap { semesterRepository.getSemesters(it) } .flatMap { gradeRepository.getNewGrades(it.first { item -> item.semesterId == currentSemesterId }) } .map { it.map { grade -> grade.apply { isRead = true } } } - .flatMapCompletable { gradeRepository.updateGrades(it) } + .flatMapCompletable { + Timber.i("Mark as read ${it.size} grades") + gradeRepository.updateGrades(it) + } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) - .subscribe({ loadData(currentSemesterId, false) }, { errorHandler.dispatch(it) })) + .subscribe({ + Timber.i("Mark as read result: Success") + loadData(currentSemesterId, false) + }, { + Timber.i("Mark as read result: An exception occurred") + errorHandler.dispatch(it) + })) return true } fun onSwipeRefresh() { + Timber.i("Force refreshing the grade details") view?.notifyParentRefresh() } @@ -94,6 +106,7 @@ class GradeDetailsPresenter @Inject constructor( } private fun loadData(semesterId: Int, forceRefresh: Boolean) { + Timber.i("Loading grade details data started") disposable.add(studentRepository.getCurrentStudent() .flatMap { semesterRepository.getSemesters(it) } .flatMap { gradeRepository.getGrades(it.first { item -> item.semesterId == semesterId }, forceRefresh) } @@ -110,6 +123,7 @@ class GradeDetailsPresenter @Inject constructor( } } .subscribe({ + Timber.i("Loading grade details result: Success") view?.run { showEmpty(it.isEmpty()) showContent(it.isNotEmpty()) @@ -117,6 +131,7 @@ class GradeDetailsPresenter @Inject constructor( } analytics.logEvent("load_grade_details", mapOf("items" to it.size, "force_refresh" to forceRefresh)) }) { + Timber.i("Loading grade details result: An exception occurred") view?.run { showEmpty(isViewEmpty) } errorHandler.dispatch(it) }) @@ -152,10 +167,14 @@ class GradeDetailsPresenter @Inject constructor( } private fun updateGrade(grade: Grade) { + Timber.i("Attempt to update grade ${grade.id}") disposable.add(gradeRepository.updateGrade(grade) .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) - .subscribe({}) { error -> errorHandler.dispatch(error) }) - Timber.d("Grade ${grade.id} updated") + .subscribe({ Timber.i("Update grade result: Success") }) + { error -> + Timber.i("Update grade result: An exception occurred") + errorHandler.dispatch(error) + }) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt index 7920ca288..08db37d2c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt @@ -12,6 +12,7 @@ import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.calcAverage import io.github.wulkanowy.utils.changeModifier +import timber.log.Timber import java.lang.String.format import java.util.Locale.FRANCE import javax.inject.Inject @@ -33,6 +34,7 @@ class GradeSummaryPresenter @Inject constructor( } fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) { + Timber.i("Loading grade summary data started") disposable.add(studentRepository.getCurrentStudent() .flatMap { semesterRepository.getSemesters(it) } .map { semester -> semester.first { it.semesterId == semesterId } } @@ -64,6 +66,7 @@ class GradeSummaryPresenter @Inject constructor( notifyParentDataLoaded(semesterId) } }.subscribe({ + Timber.i("Loading grade summary result: Success") view?.run { showEmpty(it.first.isEmpty()) showContent(it.first.isNotEmpty()) @@ -71,12 +74,14 @@ class GradeSummaryPresenter @Inject constructor( } analytics.logEvent("load_grade_summary", mapOf("items" to it.first.size, "force_refresh" to forceRefresh)) }) { + Timber.i("Loading grade summary result: An exception occurred") view?.run { showEmpty(isViewEmpty) } errorHandler.dispatch(it) }) } fun onSwipeRefresh() { + Timber.i("Force refreshing the grade summary") view?.notifyParentRefresh() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt index e4d427450..e8c40ba89 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt @@ -15,6 +15,7 @@ import io.github.wulkanowy.utils.nextSchoolDay import io.github.wulkanowy.utils.previousSchoolDay import io.github.wulkanowy.utils.toFormattedString import org.threeten.bp.LocalDate +import timber.log.Timber import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -32,6 +33,7 @@ class HomeworkPresenter @Inject constructor( fun onAttachView(view: HomeworkView, date: Long?) { super.onAttachView(view) + Timber.i("Homework view is attached") view.initView() loadData(LocalDate.ofEpochDay(date ?: LocalDate.now().nextOrSameSchoolDay.toEpochDay())) reloadView() @@ -48,14 +50,19 @@ class HomeworkPresenter @Inject constructor( } fun onSwipeRefresh() { + Timber.i("Force refreshing the homework") loadData(currentDate, true) } fun onHomeworkItemSelected(item: AbstractFlexibleItem<*>?) { - if (item is HomeworkItem) view?.showTimetableDialog(item.homework) + if (item is HomeworkItem) { + Timber.i("Select homework item ${item.homework.id}") + view?.showTimetableDialog(item.homework) + } } private fun loadData(date: LocalDate, forceRefresh: Boolean = false) { + Timber.i("Loading homework data started") currentDate = date disposable.apply { clear() @@ -73,6 +80,7 @@ class HomeworkPresenter @Inject constructor( } } .subscribe({ + Timber.i("Loading homework result: Success") view?.apply { updateData(it) showEmpty(it.isEmpty()) @@ -80,6 +88,7 @@ class HomeworkPresenter @Inject constructor( } analytics.logEvent("load_homework", mapOf("items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))) }) { + Timber.i("Loading homework result: An exception occurred") view?.run { showEmpty(isViewEmpty()) } errorHandler.dispatch(it) }) @@ -87,6 +96,7 @@ class HomeworkPresenter @Inject constructor( } private fun reloadView() { + Timber.i("Reload homework view with the date ${currentDate.toFormattedString()}") view?.apply { showProgress(true) showContent(false) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt index 0687e2f21..d4308959a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginPresenter.kt @@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.login import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler +import timber.log.Timber import javax.inject.Inject class LoginPresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresenter(errorHandler) { @@ -12,6 +13,7 @@ class LoginPresenter @Inject constructor(errorHandler: ErrorHandler) : BasePrese initAdapter() hideActionBar() } + Timber.i("Login view is attached") } fun onPageSelected(index: Int) { @@ -23,6 +25,7 @@ class LoginPresenter @Inject constructor(errorHandler: ErrorHandler) : BasePrese } fun onBackPressed(default: () -> Unit) { + Timber.i("Back pressed in login view") view?.run { if (currentViewIndex == 1) { switchView(0) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt index a1bbc1f05..7f963527b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt @@ -45,6 +45,7 @@ class LoginFormPresenter @Inject constructor( showProgress(true) showContent(false) } + Timber.i("Login started") } .doFinally { view?.apply { @@ -58,17 +59,21 @@ class LoginFormPresenter @Inject constructor( showSymbolInput() wasEmpty = true analytics.logEvent("sign_up_send", mapOf(SUCCESS to false, "students" to 0, "endpoint" to endpoint, GROUP_ID to symbol.ifEmpty { "null" })) + Timber.i("Login result: Empty student list") } else if (it.isEmpty() && wasEmpty) { showSymbolInput() setErrorSymbolIncorrect() - analytics.logEvent("sign_up_send", mapOf(SUCCESS to false, "students" to it.size, "endpoint" to endpoint, GROUP_ID to symbol.ifEmpty { "nil" })) + analytics.logEvent("sign_up_send", mapOf(SUCCESS to false, "students" to it.size, "endpoint" to endpoint, GROUP_ID to symbol.ifEmpty { "null" })) + Timber.i("Login result: Wrong symbol") } else { analytics.logEvent("sign_up_send", mapOf(SUCCESS to true, "students" to it.size, "endpoint" to endpoint, GROUP_ID to symbol)) + Timber.i("Login result: Success") switchOptionsView() } } }, { - analytics.logEvent(SIGN_UP, mapOf(SUCCESS to false, "endpoint" to endpoint, "message" to it.localizedMessage, GROUP_ID to symbol.ifEmpty { "nil" })) + analytics.logEvent(SIGN_UP, mapOf(SUCCESS to false, "endpoint" to endpoint, "message" to it.localizedMessage, GROUP_ID to symbol.ifEmpty { "null" })) + Timber.i("Login result: An exception occurred") errorHandler.dispatch(it) })) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/options/LoginOptionsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/options/LoginOptionsPresenter.kt index 6740d0582..1e2c39334 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/options/LoginOptionsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/options/LoginOptionsPresenter.kt @@ -12,6 +12,7 @@ import io.github.wulkanowy.ui.modules.login.LoginErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.reactivex.Single +import timber.log.Timber import javax.inject.Inject class LoginOptionsPresenter @Inject constructor( @@ -26,7 +27,10 @@ class LoginOptionsPresenter @Inject constructor( super.onAttachView(view) view.run { initView() - errorHandler.onStudentDuplicate = { showMessage(it) } + errorHandler.onStudentDuplicate = { + showMessage(it) + Timber.i("The student already registered in the app was selected") + } } } @@ -58,11 +62,14 @@ class LoginOptionsPresenter @Inject constructor( showContent(false) showActionBar(false) } + Timber.i("Registration started") } .subscribe({ analytics.logEvent(SIGN_UP, mapOf(SUCCESS to true, "endpoint" to student.endpoint, "message" to "Success", GROUP_ID to student.symbol)) + Timber.i("Registration result: Success") view?.openMainView() }, { + Timber.i("Registration result: An exception occurred ") errorHandler.dispatch(it) view?.apply { showProgress(false) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt index 58517302a..efe5cc3a4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt @@ -71,7 +71,7 @@ class MainActivity : BaseActivity(), MainView { override fun onStart() { super.onStart() - presenter.onViewStart() + presenter.onViewChange() } override fun initView() { @@ -98,7 +98,7 @@ class MainActivity : BaseActivity(), MainView { } navController.run { - setOnViewChangeListener { presenter.onViewStart() } + setOnViewChangeListener { presenter.onViewChange() } fragmentHideStrategy = HIDE rootFragments = listOf( GradeFragment.newInstance(), diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt index f18bd9eb0..0ef59c2b1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt @@ -10,6 +10,7 @@ import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.reactivex.Completable +import timber.log.Timber import javax.inject.Inject class MainPresenter @Inject constructor( @@ -23,6 +24,7 @@ class MainPresenter @Inject constructor( fun onAttachView(view: MainView, initMenuIndex: Int) { super.onAttachView(view) + Timber.i("Main view is attached with $initMenuIndex menu index") view.run { cancelNotifications() startMenuIndex = if (initMenuIndex != -1) initMenuIndex else prefRepository.startMenuIndex @@ -38,7 +40,7 @@ class MainPresenter @Inject constructor( })) } - fun onViewStart() { + fun onViewChange() { view?.apply { currentViewTitle?.let { setViewTitle(it) } currentStackSize?.let { @@ -49,16 +51,19 @@ class MainPresenter @Inject constructor( } fun onAccountManagerSelected(): Boolean { + Timber.i("Select account manager") view?.showAccountPicker() return true } fun onUpNavigate(): Boolean { + Timber.i("Up navigate pressed") view?.popView() return true } fun onBackPressed(default: () -> Unit) { + Timber.i("Back pressed in main view") view?.run { if (isRootView) default() else popView() @@ -67,6 +72,7 @@ class MainPresenter @Inject constructor( fun onTabSelected(index: Int, wasSelected: Boolean): Boolean { return view?.run { + Timber.i("Switch main tab index: $index, reselected: $wasSelected") if (wasSelected) { notifyMenuViewReselected() false @@ -78,15 +84,25 @@ class MainPresenter @Inject constructor( } fun onLoginSelected() { + Timber.i("Attempt to switch the student after the session expires") disposable.add(studentRepository.getCurrentStudent(false) .flatMapCompletable { studentRepository.logoutStudent(it) } .andThen(studentRepository.getSavedStudents(false)) .flatMapCompletable { - if (it.isNotEmpty()) studentRepository.switchStudent(it[0]) + if (it.isNotEmpty()) { + Timber.i("Switching current student") + studentRepository.switchStudent(it[0]) + } else Completable.complete() } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) - .subscribe({ view?.openLoginView() }, { errorHandler.dispatch(it) })) + .subscribe({ + Timber.i("Switch student result: Open login view") + view?.openLoginView() + }, { + Timber.i("Switch student result: An exception occurred") + errorHandler.dispatch(it) + })) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt index 360b9bfc1..11ec94d8e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt @@ -4,6 +4,7 @@ import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.SchedulersProvider import io.reactivex.Completable +import timber.log.Timber import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject @@ -14,6 +15,7 @@ class MessagePresenter @Inject constructor( override fun onAttachView(view: MessageView) { super.onAttachView(view) + Timber.i("Message view is attached") disposable.add(Completable.timer(150, MILLISECONDS, schedulers.mainThread) .subscribe { view.initView() @@ -30,6 +32,7 @@ class MessagePresenter @Inject constructor( } private fun loadChild(index: Int, forceRefresh: Boolean = false) { + Timber.i("Load message child view index: $index") view?.notifyChildLoadData(index, forceRefresh) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt index 3197e9914..aae11b77f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt @@ -8,6 +8,7 @@ import io.github.wulkanowy.ui.base.session.SessionErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.toFormattedString +import timber.log.Timber import javax.inject.Inject class MessagePreviewPresenter @Inject constructor( @@ -26,6 +27,7 @@ class MessagePreviewPresenter @Inject constructor( } private fun loadData(id: Int) { + Timber.i("Loading message $id preview started") messageId = id disposable.apply { clear() @@ -35,6 +37,7 @@ class MessagePreviewPresenter @Inject constructor( .observeOn(schedulers.mainThread) .doFinally { view?.showProgress(false) } .subscribe({ message -> + Timber.i("Loading message $id preview result: Success ") view?.run { message.let { setSubject(if (it.subject.isNotBlank()) it.subject else noSubjectString) @@ -45,8 +48,9 @@ class MessagePreviewPresenter @Inject constructor( else setSender(it.sender) } } - analytics.logEvent("load_attendance", mapOf(START_DATE to message.date?.toFormattedString("yyyy.MM.dd"), "lenght" to message.content?.length)) + analytics.logEvent("load_message_preview", mapOf(START_DATE to message.date?.toFormattedString("yyyy.MM.dd"), "lenght" to message.content?.length)) }) { + Timber.i("Loading message $id preview result: An excception occurred ") view?.showMessageError() errorHandler.dispatch(it) }) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt index 0e1a9d84f..0d413b99c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt @@ -29,10 +29,12 @@ class MessageTabPresenter @Inject constructor( } fun onSwipeRefresh() { + Timber.i("Force refreshing the $folder message") onParentViewLoadData(true) } fun onParentViewLoadData(forceRefresh: Boolean) { + Timber.i("Loading $folder message data started") disposable.apply { clear() add(studentRepository.getCurrentStudent() @@ -48,6 +50,7 @@ class MessageTabPresenter @Inject constructor( } } .subscribe({ + Timber.i("Loading $folder message result: Success") view?.run { showEmpty(it.isEmpty()) showContent(it.isNotEmpty()) @@ -55,6 +58,7 @@ class MessageTabPresenter @Inject constructor( } analytics.logEvent("load_messages", mapOf("items" to it.size, "folder" to folder.name)) }) { + Timber.i("Loading $folder message result: An exception occurred") view?.run { showEmpty(isViewEmpty) } errorHandler.dispatch(it) }) @@ -63,6 +67,7 @@ class MessageTabPresenter @Inject constructor( fun onMessageItemSelected(item: AbstractFlexibleItem<*>) { if (item is MessageItem) { + Timber.i("Select message ${item.message.realId} item") view?.run { openMessage(item.message.realId) if (item.message.unread == true) { @@ -75,12 +80,14 @@ class MessageTabPresenter @Inject constructor( } private fun updateMessage(message: Message) { + Timber.i("Attempt to update message ${message.realId}") disposable.add(messagesRepository.updateMessage(message) .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) - .subscribe({ - Timber.d("Message ${message.realId} updated") - }) { error -> errorHandler.dispatch(error) } - ) + .subscribe({ Timber.d("Update message ${message.realId} result: Success") }) + { error -> + Timber.i("Update message ${message.realId} result: An exception occurred") + errorHandler.dispatch(error) + }) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt index 61b187f1b..6becc8ad1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt @@ -3,18 +3,21 @@ package io.github.wulkanowy.ui.modules.more import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler +import timber.log.Timber import javax.inject.Inject class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresenter(errorHandler) { override fun onAttachView(view: MoreView) { super.onAttachView(view) + Timber.i("More view is attached") view.initView() loadData() } fun onItemSelected(item: AbstractFlexibleItem<*>?) { if (item is MoreItem) { + Timber.i("Select more item \"${item.title}\"") view?.run { when (item.title) { messagesRes?.first -> openMessagesView() @@ -28,10 +31,12 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresen } fun onViewReselected() { + Timber.i("More view is reselected") view?.popView() } private fun loadData() { + Timber.i("Load items for more view") view?.run { updateData(listOfNotNull( messagesRes?.let { MoreItem(it.first, it.second) }, diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt index c388a3f78..4bf3de3de 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NotePresenter.kt @@ -23,15 +23,18 @@ class NotePresenter @Inject constructor( override fun onAttachView(view: NoteView) { super.onAttachView(view) + Timber.i("Note view is attached") view.initView() loadData() } fun onSwipeRefresh() { + Timber.i("Force refreshing the note") loadData(true) } private fun loadData(forceRefresh: Boolean = false) { + Timber.i("Loading note data started") disposable.add(studentRepository.getCurrentStudent() .flatMap { semesterRepository.getCurrentSemester(it) } .flatMap { noteRepository.getNotes(it, forceRefresh) } @@ -45,6 +48,7 @@ class NotePresenter @Inject constructor( showProgress(false) } }.subscribe({ + Timber.i("Loading note result: Success") view?.apply { updateData(it) showEmpty(it.isEmpty()) @@ -52,6 +56,7 @@ class NotePresenter @Inject constructor( } analytics.logEvent("load_note", mapOf("items" to it.size, "force_refresh" to forceRefresh)) }, { + Timber.i("Loading note result: An exception occurred") view?.run { showEmpty(isViewEmpty) } errorHandler.dispatch(it) }) @@ -60,6 +65,7 @@ class NotePresenter @Inject constructor( fun onNoteItemSelected(item: AbstractFlexibleItem<*>?) { if (item is NoteItem) { + Timber.i("Select note item ${item.note.id}") view?.run { showNoteDialog(item.note) if (!item.note.isRead) { @@ -72,12 +78,14 @@ class NotePresenter @Inject constructor( } private fun updateNote(note: Note) { + Timber.i("Attempt to update note ${note.id}") disposable.add(noteRepository.updateNote(note) .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) - .subscribe({ - Timber.d("Note ${note.id} updated") - }) { error -> errorHandler.dispatch(error) } - ) + .subscribe({ Timber.i("Update note result: Success") }) + { error -> + Timber.i("Update note result: An exception occurred") + errorHandler.dispatch(error) + }) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt index 6a2087558..dff39d202 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt @@ -1,7 +1,6 @@ package io.github.wulkanowy.ui.modules.settings import com.readystatesoftware.chuck.api.ChuckCollector -import io.github.wulkanowy.data.RepositoryModule_ProvideChuckCollectorFactory import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.services.job.ServiceHelper import io.github.wulkanowy.ui.base.BasePresenter @@ -9,6 +8,7 @@ import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.isHolidays import org.threeten.bp.LocalDate.now +import timber.log.Timber import javax.inject.Inject class SettingsPresenter @Inject constructor( @@ -21,6 +21,7 @@ class SettingsPresenter @Inject constructor( override fun onAttachView(view: SettingsView) { super.onAttachView(view) + Timber.i("Settings view is attached") view.run { setServicesSuspended(preferencesRepository.serviceEnablesKey, now().isHolidays) @@ -28,6 +29,7 @@ class SettingsPresenter @Inject constructor( } fun onSharedPreferenceChanged(key: String) { + Timber.i("Change settings $key") when (key) { preferencesRepository.serviceEnablesKey -> { if (preferencesRepository.isServiceEnabled) serviceHelper.startFullSyncService() @@ -44,7 +46,6 @@ class SettingsPresenter @Inject constructor( chuckCollector.showNotification(preferencesRepository.isShowChuckerNotification) } } - analytics.logEvent("setting_changed", mapOf("name" to key)) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt index 27a9db998..ac0dcca4c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt @@ -17,6 +17,7 @@ import io.github.wulkanowy.utils.toFormattedString import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate.now import org.threeten.bp.LocalDate.ofEpochDay +import timber.log.Timber import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject @@ -34,6 +35,7 @@ class TimetablePresenter @Inject constructor( fun onAttachView(view: TimetableView, date: Long?) { super.onAttachView(view) + Timber.i("Timetable is attached") view.initView() loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay())) reloadView() @@ -50,10 +52,12 @@ class TimetablePresenter @Inject constructor( } fun onSwipeRefresh() { + Timber.i("Force refreshing the timetable") loadData(currentDate, true) } fun onViewReselected() { + Timber.i("Exam view is reselected") now().nextOrSameSchoolDay.also { if (currentDate != it) { loadData(it) @@ -63,10 +67,14 @@ class TimetablePresenter @Inject constructor( } fun onTimetableItemSelected(item: AbstractFlexibleItem<*>?) { - if (item is TimetableItem) view?.showTimetableDialog(item.lesson) + if (item is TimetableItem) { + Timber.i("Select exam item ${item.lesson.id}") + view?.showTimetableDialog(item.lesson) + } } private fun loadData(date: LocalDate, forceRefresh: Boolean = false) { + Timber.i("Loading timetable data started") currentDate = date disposable.apply { clear() @@ -85,13 +93,15 @@ class TimetablePresenter @Inject constructor( } } .subscribe({ + Timber.i("Loading timetable result: Success") view?.apply { updateData(it) showEmpty(it.isEmpty()) showContent(it.isNotEmpty()) } - analytics.logEvent("load_attendance", mapOf("items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))) + analytics.logEvent("load_timetable", mapOf("items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))) }) { + Timber.i("Loading timetable result: An exception occurred") view?.run { showEmpty(isViewEmpty) } errorHandler.dispatch(it) }) @@ -99,6 +109,7 @@ class TimetablePresenter @Inject constructor( } private fun reloadView() { + Timber.i("Reload timetable view with the date ${currentDate.toFormattedString()}") view?.apply { showProgress(true) showContent(false) From a174ae998d028ff765e9ce9dc8f4bdb0366b88ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sun, 20 Jan 2019 14:16:24 +0100 Subject: [PATCH 019/192] Add api initialization to the message repository (#220) --- .../data/repositories/MessagesRepository.kt | 82 ++++++++++--------- .../wulkanowy/services/job/SyncWorker.kt | 22 ++--- .../preview/MessagePreviewPresenter.kt | 2 +- .../message/tab/MessageTabPresenter.kt | 2 +- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 3 +- 6 files changed, 61 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/MessagesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/MessagesRepository.kt index 06a0f6f95..85a1e076c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/MessagesRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/MessagesRepository.kt @@ -2,6 +2,7 @@ package io.github.wulkanowy.data.repositories import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings +import io.github.wulkanowy.data.ApiHelper import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.local.MessagesLocal @@ -16,7 +17,8 @@ import javax.inject.Singleton class MessagesRepository @Inject constructor( private val settings: InternetObservingSettings, private val local: MessagesLocal, - private val remote: MessagesRemote + private val remote: MessagesRemote, + private val apiHelper: ApiHelper ) { enum class MessageFolder(val id: Int = 1) { @@ -25,44 +27,50 @@ class MessagesRepository @Inject constructor( TRASHED(3) } - fun getMessages(studentId: Int, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single> { - return local.getMessages(studentId, folder).filter { !forceRefresh } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) remote.getMessages(studentId, folder) - else Single.error(UnknownHostException()) - }.flatMap { new -> - local.getMessages(studentId, folder).toSingle(emptyList()) - .doOnSuccess { old -> - local.deleteMessages(old - new) - local.saveMessages((new - old) - .onEach { - it.isNotified = !notify - }) - } - }.flatMap { local.getMessages(studentId, folder).toSingle(emptyList()) } - ) + fun getMessages(student: Student, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single> { + return Single.just(apiHelper.initApi(student)) + .flatMap { _ -> + local.getMessages(student.studentId, folder).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMap { + if (it) remote.getMessages(student.studentId, folder) + else Single.error(UnknownHostException()) + }.flatMap { new -> + local.getMessages(student.studentId, folder).toSingle(emptyList()) + .doOnSuccess { old -> + local.deleteMessages(old - new) + local.saveMessages((new - old) + .onEach { + it.isNotified = !notify + }) + } + }.flatMap { local.getMessages(student.studentId, folder).toSingle(emptyList()) } + ) + } } - fun getMessage(studentId: Int, messageId: Int, markAsRead: Boolean = false): Single { - return local.getMessage(studentId, messageId) - .filter { !it.content.isNullOrEmpty() } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) local.getMessage(studentId, messageId).toSingle() - else Single.error(UnknownHostException()) - } - .flatMap { dbMessage -> - remote.getMessagesContent(dbMessage, markAsRead).doOnSuccess { - local.updateMessage(dbMessage.copy(unread = false).apply { - id = dbMessage.id - content = it - }) - } - }.flatMap { - local.getMessage(studentId, messageId).toSingle() - } - ) + fun getMessage(student: Student, messageId: Int, markAsRead: Boolean = false): Single { + return Single.just(apiHelper.initApi(student)) + .flatMap { _ -> + local.getMessage(student.studentId, messageId) + .filter { !it.content.isNullOrEmpty() } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMap { + if (it) local.getMessage(student.studentId, messageId).toSingle() + else Single.error(UnknownHostException()) + } + .flatMap { dbMessage -> + remote.getMessagesContent(dbMessage, markAsRead).doOnSuccess { + local.updateMessage(dbMessage.copy(unread = false).apply { + id = dbMessage.id + content = it + }) + } + }.flatMap { + local.getMessage(student.studentId, messageId).toSingle() + } + ) + } } fun getNewMessages(student: Student): Single> { diff --git a/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt b/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt index 65fb3abcf..c958c22d0 100644 --- a/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt +++ b/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt @@ -84,19 +84,19 @@ class SyncWorker : SimpleJobService() { var error: Throwable? = null disposable.add(student.getCurrentStudent() - .flatMap { semester.getCurrentSemester(it, true) } + .flatMap { semester.getCurrentSemester(it, true).map { semester -> semester to it } } .flatMapPublisher { Single.merge( listOf( - gradesDetails.getGrades(it, true, true), - gradesSummary.getGradesSummary(it, true), - attendance.getAttendance(it, start, end, true), - exam.getExams(it, start, end, true), - timetable.getTimetable(it, start, end, true), - message.getMessages(it.studentId, RECEIVED, true, true), - note.getNotes(it, true, true), - homework.getHomework(it, LocalDate.now(), true), - homework.getHomework(it, LocalDate.now().plusDays(1), true) + gradesDetails.getGrades(it.first, true, true), + gradesSummary.getGradesSummary(it.first, true), + attendance.getAttendance(it.first, start, end, true), + exam.getExams(it.first, start, end, true), + timetable.getTimetable(it.first, start, end, true), + message.getMessages(it.second, RECEIVED, true, true), + note.getNotes(it.first, true, true), + homework.getHomework(it.first, LocalDate.now(), true), + homework.getHomework(it.first, LocalDate.now().plusDays(1), true) ) ) } @@ -138,7 +138,7 @@ class SyncWorker : SimpleJobService() { disposable.add(student.getCurrentStudent() .flatMap { message.getNewMessages(it) } .map { it.filter { message -> !message.isNotified } } - .doOnSuccess{ + .doOnSuccess { if (it.isNotEmpty()) { Timber.d("Found ${it.size} unread messages") MessageNotification(applicationContext).sendNotification(it) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt index aae11b77f..d0ce92504 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt @@ -32,7 +32,7 @@ class MessagePreviewPresenter @Inject constructor( disposable.apply { clear() add(studentRepository.getCurrentStudent() - .flatMap { messagesRepository.getMessage(it.studentId, messageId, true) } + .flatMap { messagesRepository.getMessage(it, messageId, true) } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doFinally { view?.showProgress(false) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt index 0d413b99c..9636e4df3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt @@ -38,7 +38,7 @@ class MessageTabPresenter @Inject constructor( disposable.apply { clear() add(studentRepository.getCurrentStudent() - .flatMap { messagesRepository.getMessages(it.studentId, folder, forceRefresh) } + .flatMap { messagesRepository.getMessages(it, folder, forceRefresh) } .map { items -> items.map { MessageItem(it, view?.noSubjectString.orEmpty()) } } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) diff --git a/build.gradle b/build.gradle index 629b4a48e..fdd750f74 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.3.0' classpath 'com.google.gms:google-services:4.2.0' classpath "io.fabric.tools:gradle:1.26.1" classpath "com.github.triplet.gradle:play-publisher:1.2.2" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3f0f9be63..acee7e1ba 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Sun Jan 20 00:47:56 CET 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip From 8476f0e62e307c834db8b5a67b3fa04cfd4835fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sun, 20 Jan 2019 15:00:33 +0100 Subject: [PATCH 020/192] Update dependencies (#221) --- app/build.gradle | 18 +++++++++--------- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f60cbb008..dd6258e1e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -92,9 +92,9 @@ dependencies { implementation "com.mikepenz:aboutlibraries:6.2.0" implementation "com.firebase:firebase-jobdispatcher:0.8.5" - implementation "com.google.dagger:dagger-android-support:2.19" - kapt "com.google.dagger:dagger-compiler:2.19" - kapt "com.google.dagger:dagger-android-processor:2.19" + implementation "com.google.dagger:dagger-android-support:2.21" + kapt "com.google.dagger:dagger-compiler:2.21" + kapt "com.google.dagger:dagger-android-processor:2.21" implementation "androidx.room:room-runtime:2.1.0-alpha03" implementation "androidx.room:room-rxjava2:2.1.0-alpha03" @@ -103,14 +103,14 @@ dependencies { implementation "eu.davidea:flexible-adapter:5.1.0" implementation "eu.davidea:flexible-adapter-ui:1.0.0" - implementation "com.aurelhubert:ahbottomnavigation:2.2.0" - implementation 'com.ncapdevi:frag-nav:3.0.0' + implementation "com.aurelhubert:ahbottomnavigation:2.3.4" + implementation 'com.ncapdevi:frag-nav:3.1.0' - implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.1' + implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.2' implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' - implementation "io.reactivex.rxjava2:rxjava:2.2.4" + implementation "io.reactivex.rxjava2:rxjava:2.2.5" - implementation "com.jakewharton.threetenabp:threetenabp:1.1.0" + implementation "com.jakewharton.threetenabp:threetenabp:1.1.1" implementation "com.jakewharton.timber:timber:4.7.1" implementation "at.favre.lib:slf4j-timber:1.0.1" @@ -124,7 +124,7 @@ dependencies { debugImplementation "com.amitshekhar.android:debug-db:1.0.4" testImplementation "junit:junit:4.12" - testImplementation "io.mockk:mockk:1.8.13.kotlin13" + testImplementation "io.mockk:mockk:1.9" testImplementation "org.mockito:mockito-inline:2.23.4" testImplementation 'org.threeten:threetenbp:1.3.8' diff --git a/build.gradle b/build.gradle index fdd750f74..d2f68da07 100644 --- a/build.gradle +++ b/build.gradle @@ -11,9 +11,9 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.android.tools.build:gradle:3.3.0' classpath 'com.google.gms:google-services:4.2.0' - classpath "io.fabric.tools:gradle:1.26.1" + classpath "io.fabric.tools:gradle:1.27.0" classpath "com.github.triplet.gradle:play-publisher:1.2.2" - classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2" + classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7" classpath 'com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta02' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index acee7e1ba..f95599f57 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Sun Jan 20 00:47:56 CET 2019 +#Sun Jan 20 13:58:58 CET 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME From 20d9313257361100223d6afeeb04f80b4b137c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 20 Jan 2019 15:39:11 +0100 Subject: [PATCH 021/192] Version 0.6.4 --- app/build.gradle | 6 +++--- app/src/main/play/pl-PL/whatsnew | 13 ++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index dd6258e1e..46349f1d3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,8 +23,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 28 - versionCode 22 - versionName "0.6.3" + versionCode 23 + versionName "0.6.4" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true @@ -80,7 +80,7 @@ play { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation('io.github.wulkanowy:api:0.6.3') { exclude module: "threetenbp" } + implementation('io.github.wulkanowy:api:0.6.4') { exclude module: "threetenbp" } implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.appcompat:appcompat:1.0.2" diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/pl-PL/whatsnew index 81ff753b0..ab5ec9776 100644 --- a/app/src/main/play/pl-PL/whatsnew +++ b/app/src/main/play/pl-PL/whatsnew @@ -1,7 +1,10 @@ -Wersja 0.6.3 +Wersja 0.6.4 -- naprawiono problem ze stabilnością przy odczytywaniu ocen -- poprawiono komunikat o błędzie podczas przerwy technicznej dziennika -- (ponownie) naprawiono logowanie w systemach Resman Rzeszów i podobnych +- naprawiono problemy ze stabilnością podczas logowania na urządzeniach marki Meizu +- naprawiono problemy ze stabilnością w uwagach +- naprawiono błąd pobierania podglądu wiadomości, gdy otworzono aplikację z powiadomienia +- zoptymalizowano pobieranie wiadomości wysłanych +- poprawiono wyświetlanie odbiorców wiadomości wysłanych +- naprawiono problem z liczeniem średniej z ocen zawierających minus -Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.6.3 +Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.6.4 From e29886560e8fcbd4e3179c6d9d46ad1f668b3c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sun, 20 Jan 2019 22:43:50 +0100 Subject: [PATCH 022/192] Disable obfuscate in R8 (#222) --- app/build.gradle | 1 - app/proguard-rules.pro | 1 + gradle.properties | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 46349f1d3..e5bb803c0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -48,7 +48,6 @@ android { release { buildConfigField "boolean", "CRASHLYTICS_ENABLED", "true" minifyEnabled true - useProguard false shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index cebd3d94d..589b5f34b 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -5,6 +5,7 @@ -dontskipnonpubliclibraryclasses -dontskipnonpubliclibraryclassmembers -dontpreverify +-dontobfuscate -allowaccessmodification -repackageclasses '' -verbose diff --git a/gradle.properties b/gradle.properties index 9e6fce102..24e69b6ac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,6 +11,7 @@ # The setting is particularly useful for tweaking memory settings. android.enableJetifier=true android.useAndroidX=true +android.enableR8=true org.gradle.jvmargs=-Xmx1536m # When configured, Gradle will run in incubating parallel mode. From 2061d6408fee725e5097ec924e14408b3fc422cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 20 Jan 2019 23:36:16 +0100 Subject: [PATCH 023/192] Change icon of semester switch (#223) --- app/src/main/res/drawable/ic_menu_grade_semester_24dp.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/drawable/ic_menu_grade_semester_24dp.xml b/app/src/main/res/drawable/ic_menu_grade_semester_24dp.xml index dbc32c27d..2a03f6300 100644 --- a/app/src/main/res/drawable/ic_menu_grade_semester_24dp.xml +++ b/app/src/main/res/drawable/ic_menu_grade_semester_24dp.xml @@ -1,9 +1,9 @@ + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + android:pathData="M21,17V8H7V17H21M21,3A2,2 0,0 1,23 5V17A2,2 0,0 1,21 19H7C5.89,19 5,18.1 5,17V5A2,2 0,0 1,7 3H8V1H10V3H18V1H20V3H21M3,21H17V23H3C1.89,23 1,22.1 1,21V9H3V21M19,15H15V11H19V15Z" /> From 189830e0f494c25df2598f5a6310bccbd4c6ca85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 20 Jan 2019 23:38:02 +0100 Subject: [PATCH 024/192] Version 0.6.5 --- app/build.gradle | 4 ++-- app/src/main/play/pl-PL/whatsnew | 12 ++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e5bb803c0..4d199db2d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,8 +23,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 28 - versionCode 23 - versionName "0.6.4" + versionCode 24 + versionName "0.6.5" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/pl-PL/whatsnew index ab5ec9776..70c0352ad 100644 --- a/app/src/main/play/pl-PL/whatsnew +++ b/app/src/main/play/pl-PL/whatsnew @@ -1,10 +1,6 @@ -Wersja 0.6.4 +Wersja 0.6.5 -- naprawiono problemy ze stabilnością podczas logowania na urządzeniach marki Meizu -- naprawiono problemy ze stabilnością w uwagach -- naprawiono błąd pobierania podglądu wiadomości, gdy otworzono aplikację z powiadomienia -- zoptymalizowano pobieranie wiadomości wysłanych -- poprawiono wyświetlanie odbiorców wiadomości wysłanych -- naprawiono problem z liczeniem średniej z ocen zawierających minus +- zmieniono ikonę zmiany semestru w ocenach +- naprawiono wyświetlanie szczegółowych informacji o błędach -Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.6.4 +Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.6.5 From 941765a3a353446f87a1eb0619268650321d3c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Wed, 23 Jan 2019 18:28:51 +0100 Subject: [PATCH 025/192] Fix empty Maybe in student repository (#224) --- .../github/wulkanowy/data/repositories/StudentRepository.kt | 5 ++++- .../main/java/io/github/wulkanowy/services/job/SyncWorker.kt | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt index 97210da0b..a7a6f6eaa 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt @@ -7,6 +7,7 @@ import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.local.StudentLocal import io.github.wulkanowy.data.repositories.remote.StudentRemote import io.reactivex.Completable +import io.reactivex.Maybe import io.reactivex.Single import java.net.UnknownHostException import javax.inject.Inject @@ -41,7 +42,9 @@ class StudentRepository @Inject constructor( } fun getCurrentStudent(decryptPass: Boolean = true): Single { - return local.getCurrentStudent(decryptPass).toSingle() + return local.getCurrentStudent(decryptPass) + .switchIfEmpty(Maybe.error(NoSuchElementException("No current student"))) + .toSingle() } fun saveStudent(student: Student): Single { diff --git a/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt b/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt index c958c22d0..6e8566718 100644 --- a/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt +++ b/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt @@ -80,6 +80,7 @@ class SyncWorker : SimpleJobService() { val end = LocalDate.now().friday if (start.isHolidays) return RESULT_FAIL_NORETRY + if (!student.isStudentSaved) return RESULT_FAIL_RETRY var error: Throwable? = null From c78fb837748875b14f3080383656173d710eccd0 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Thu, 24 Jan 2019 18:32:51 +0100 Subject: [PATCH 026/192] Fix receiving a lot of notifications after turning them off for a while (#225) --- .../io/github/wulkanowy/services/job/SyncWorker.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt b/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt index 6e8566718..cf09728a6 100644 --- a/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt +++ b/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt @@ -84,18 +84,20 @@ class SyncWorker : SimpleJobService() { var error: Throwable? = null + val notify = prefRepository.isNotificationsEnable + disposable.add(student.getCurrentStudent() .flatMap { semester.getCurrentSemester(it, true).map { semester -> semester to it } } .flatMapPublisher { Single.merge( listOf( - gradesDetails.getGrades(it.first, true, true), + gradesDetails.getGrades(it.first, true, notify), gradesSummary.getGradesSummary(it.first, true), attendance.getAttendance(it.first, start, end, true), exam.getExams(it.first, start, end, true), timetable.getTimetable(it.first, start, end, true), - message.getMessages(it.second, RECEIVED, true, true), - note.getNotes(it.first, true, true), + message.getMessages(it.second, RECEIVED, true, notify), + note.getNotes(it.first, true, notify), homework.getHomework(it.first, LocalDate.now(), true), homework.getHomework(it.first, LocalDate.now().plusDays(1), true) ) @@ -104,7 +106,7 @@ class SyncWorker : SimpleJobService() { .subscribe({}, { error = it })) return if (null === error) { - if (prefRepository.isNotificationsEnable) sendNotifications() + if (notify) sendNotifications() Timber.d("Synchronization successful") RESULT_SUCCESS } else { From d3c13b8fc3d7863054f513ff79b373abb52795d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Thu, 24 Jan 2019 21:16:22 +0100 Subject: [PATCH 027/192] Fix empty fragment list in fragment manager (#226) --- .../ui/base/BaseFragmentPagerAdapter.kt | 36 +++++++++++++++++++ .../wulkanowy/ui/base/BasePagerAdapter.kt | 32 ----------------- .../ui/modules/grade/GradeFragment.kt | 17 ++++----- .../wulkanowy/ui/modules/grade/GradeModule.kt | 4 +-- .../ui/modules/login/LoginActivity.kt | 12 +++---- .../wulkanowy/ui/modules/login/LoginModule.kt | 4 +-- .../ui/modules/message/MessageFragment.kt | 15 ++++---- .../ui/modules/message/MessageModule.kt | 4 +-- 8 files changed, 65 insertions(+), 59 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/base/BaseFragmentPagerAdapter.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/ui/base/BasePagerAdapter.kt diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragmentPagerAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragmentPagerAdapter.kt new file mode 100644 index 000000000..bccb8f78c --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragmentPagerAdapter.kt @@ -0,0 +1,36 @@ +package io.github.wulkanowy.ui.base + +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter + +class BaseFragmentPagerAdapter(private val fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager) { + + private val pages = mutableMapOf() + + private var containerId = 0 + + fun getFragmentInstance(position: Int): Fragment? { + return fragmentManager.findFragmentByTag("android:switcher:$containerId:$position") + } + + fun addFragments(fragments: List) { + fragments.forEach { pages[it] = null } + } + + fun addFragmentsWithTitle(pages: Map) { + this.pages.putAll(pages) + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + containerId = container.id + return super.instantiateItem(container, position) + } + + override fun getItem(position: Int) = pages.keys.elementAt(position) + + override fun getCount() = pages.size + + override fun getPageTitle(position: Int) = pages.values.elementAt(position) +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BasePagerAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BasePagerAdapter.kt deleted file mode 100644 index 000efdcd3..000000000 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BasePagerAdapter.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.wulkanowy.ui.base - -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentStatePagerAdapter - -class BasePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) { - - val fragments = mutableMapOf() - - val registeredFragments = mutableMapOf() - - override fun getItem(position: Int) = fragments.values.elementAt(position) - - override fun getCount() = fragments.size - - override fun getPageTitle(position: Int): CharSequence? { - return fragments.keys.elementAtOrNull(position) - } - - override fun instantiateItem(container: ViewGroup, position: Int): Any { - return super.instantiateItem(container, position).also { - registeredFragments[position] = it as Fragment - } - } - - override fun destroyItem(container: ViewGroup, position: Int, fragment: Any) { - registeredFragments.remove(position) - super.destroyItem(container, position, fragment) - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt index a4d948a92..d56eca9a2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt @@ -11,7 +11,7 @@ import android.view.View.VISIBLE import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import io.github.wulkanowy.R -import io.github.wulkanowy.ui.base.BasePagerAdapter +import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter import io.github.wulkanowy.ui.base.session.BaseSessionFragment import io.github.wulkanowy.ui.modules.grade.details.GradeDetailsFragment import io.github.wulkanowy.ui.modules.grade.summary.GradeSummaryFragment @@ -26,7 +26,7 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView, lateinit var presenter: GradePresenter @Inject - lateinit var pagerAdapter: BasePagerAdapter + lateinit var pagerAdapter: BaseFragmentPagerAdapter companion object { private const val SAVED_SEMESTER_KEY = "CURRENT_SEMESTER" @@ -59,10 +59,11 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView, } override fun initView() { - pagerAdapter.fragments.putAll(mapOf( - getString(R.string.all_details) to GradeDetailsFragment.newInstance(), - getString(R.string.grade_menu_summary) to GradeSummaryFragment.newInstance() + pagerAdapter.addFragmentsWithTitle(mapOf( + GradeDetailsFragment.newInstance() to getString(R.string.all_details), + GradeSummaryFragment.newInstance() to getString(R.string.grade_menu_summary) )) + gradeViewPager.run { adapter = pagerAdapter setOnSelectPageListener { presenter.onPageSelected(it) } @@ -117,15 +118,15 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView, } override fun notifyChildLoadData(index: Int, semesterId: Int, forceRefresh: Boolean) { - (childFragmentManager.fragments[index] as GradeView.GradeChildView).onParentLoadData(semesterId, forceRefresh) + (pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentLoadData(semesterId, forceRefresh) } override fun notifyChildParentReselected(index: Int) { - (pagerAdapter.registeredFragments[index] as? GradeView.GradeChildView)?.onParentReselected() + (pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentReselected() } override fun notifyChildSemesterChange(index: Int) { - (pagerAdapter.registeredFragments[index] as? GradeView.GradeChildView)?.onParentChangeSemester() + (pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentChangeSemester() } override fun onSaveInstanceState(outState: Bundle) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeModule.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeModule.kt index c47ddc574..b7b52f218 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeModule.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeModule.kt @@ -5,7 +5,7 @@ import dagger.Provides import dagger.android.ContributesAndroidInjector import io.github.wulkanowy.di.scopes.PerChildFragment import io.github.wulkanowy.di.scopes.PerFragment -import io.github.wulkanowy.ui.base.BasePagerAdapter +import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter import io.github.wulkanowy.ui.modules.grade.details.GradeDetailsFragment import io.github.wulkanowy.ui.modules.grade.summary.GradeSummaryFragment @@ -18,7 +18,7 @@ abstract class GradeModule { @JvmStatic @PerFragment @Provides - fun provideGradePagerAdapter(fragment: GradeFragment) = BasePagerAdapter(fragment.childFragmentManager) + fun provideGradeAdapter(fragment: GradeFragment) = BaseFragmentPagerAdapter(fragment.childFragmentManager) } @PerChildFragment diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt index c9c1aeb41..db3124e4a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt @@ -5,7 +5,7 @@ import android.content.Intent import android.os.Bundle import io.github.wulkanowy.R import io.github.wulkanowy.ui.base.BaseActivity -import io.github.wulkanowy.ui.base.BasePagerAdapter +import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter import io.github.wulkanowy.ui.modules.login.form.LoginFormFragment import io.github.wulkanowy.ui.modules.login.options.LoginOptionsFragment import io.github.wulkanowy.utils.setOnSelectPageListener @@ -18,7 +18,7 @@ class LoginActivity : BaseActivity(), LoginView { lateinit var presenter: LoginPresenter @Inject - lateinit var loginAdapter: BasePagerAdapter + lateinit var loginAdapter: BaseFragmentPagerAdapter companion object { fun getStartIntent(context: Context) = Intent(context, LoginActivity::class.java) @@ -36,9 +36,9 @@ class LoginActivity : BaseActivity(), LoginView { } override fun initAdapter() { - loginAdapter.fragments.putAll(mapOf( - "1" to LoginFormFragment.newInstance(), - "2" to LoginOptionsFragment.newInstance() + loginAdapter.addFragments(listOf( + LoginFormFragment.newInstance(), + LoginOptionsFragment.newInstance() )) loginViewpager.run { @@ -52,7 +52,7 @@ class LoginActivity : BaseActivity(), LoginView { } override fun notifyOptionsViewLoadData() { - (supportFragmentManager.fragments[1] as? LoginOptionsFragment)?.onParentLoadData() + (loginAdapter.getFragmentInstance(1) as? LoginOptionsFragment)?.onParentLoadData() } fun onChildFragmentSwitchOptions() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginModule.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginModule.kt index 3cdf83679..1758d59a2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginModule.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginModule.kt @@ -5,7 +5,7 @@ import dagger.Provides import dagger.android.ContributesAndroidInjector import io.github.wulkanowy.di.scopes.PerActivity import io.github.wulkanowy.di.scopes.PerFragment -import io.github.wulkanowy.ui.base.BasePagerAdapter +import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter import io.github.wulkanowy.ui.modules.login.form.LoginFormFragment import io.github.wulkanowy.ui.modules.login.options.LoginOptionsFragment @@ -18,7 +18,7 @@ internal abstract class LoginModule { @JvmStatic @PerActivity @Provides - fun provideLoginAdapter(activity: LoginActivity) = BasePagerAdapter(activity.supportFragmentManager) + fun provideLoginAdapter(activity: LoginActivity) = BaseFragmentPagerAdapter(activity.supportFragmentManager) } @PerFragment diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageFragment.kt index f75c6131d..df6ceca7d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageFragment.kt @@ -11,7 +11,7 @@ import io.github.wulkanowy.data.repositories.MessagesRepository.MessageFolder.RE import io.github.wulkanowy.data.repositories.MessagesRepository.MessageFolder.SENT import io.github.wulkanowy.data.repositories.MessagesRepository.MessageFolder.TRASHED import io.github.wulkanowy.ui.base.BaseFragment -import io.github.wulkanowy.ui.base.BasePagerAdapter +import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.message.tab.MessageTabFragment import io.github.wulkanowy.utils.setOnSelectPageListener @@ -24,7 +24,7 @@ class MessageFragment : BaseFragment(), MessageView, MainView.TitledView { lateinit var presenter: MessagePresenter @Inject - lateinit var pagerAdapter: BasePagerAdapter + lateinit var pagerAdapter: BaseFragmentPagerAdapter companion object { fun newInstance() = MessageFragment() @@ -46,11 +46,12 @@ class MessageFragment : BaseFragment(), MessageView, MainView.TitledView { } override fun initView() { - pagerAdapter.fragments.putAll(mapOf( - getString(R.string.message_inbox) to MessageTabFragment.newInstance(RECEIVED), - getString(R.string.message_sent) to MessageTabFragment.newInstance(SENT), - getString(R.string.message_trash) to MessageTabFragment.newInstance(TRASHED) + pagerAdapter.addFragmentsWithTitle(mapOf( + MessageTabFragment.newInstance(RECEIVED) to getString(R.string.message_inbox), + MessageTabFragment.newInstance(SENT) to getString(R.string.message_sent), + MessageTabFragment.newInstance(TRASHED) to getString(R.string.message_trash) )) + messageViewPager.run { adapter = pagerAdapter offscreenPageLimit = 2 @@ -73,7 +74,7 @@ class MessageFragment : BaseFragment(), MessageView, MainView.TitledView { } override fun notifyChildLoadData(index: Int, forceRefresh: Boolean) { - (childFragmentManager.fragments[index] as MessageView.MessageChildView).onParentLoadData(forceRefresh) + (pagerAdapter.getFragmentInstance(index) as? MessageView.MessageChildView)?.onParentLoadData(forceRefresh) } override fun onDestroyView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageModule.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageModule.kt index dd7a22ae8..e4c202d9f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageModule.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageModule.kt @@ -5,7 +5,7 @@ import dagger.Provides import dagger.android.ContributesAndroidInjector import io.github.wulkanowy.di.scopes.PerChildFragment import io.github.wulkanowy.di.scopes.PerFragment -import io.github.wulkanowy.ui.base.BasePagerAdapter +import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter import io.github.wulkanowy.ui.modules.message.tab.MessageTabFragment @Module @@ -17,7 +17,7 @@ abstract class MessageModule { @JvmStatic @PerFragment @Provides - fun provideGradePagerAdapter(fragment: MessageFragment) = BasePagerAdapter(fragment.childFragmentManager) + fun provideMessageAdapter(fragment: MessageFragment) = BaseFragmentPagerAdapter(fragment.childFragmentManager) } @PerChildFragment From ffc2ef9a4e27bb925c1ac08569c4424b748b4bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Fri, 25 Jan 2019 19:20:13 +0100 Subject: [PATCH 028/192] Remove renaming source file in R8 (#227) --- app/proguard-rules.pro | 1 - build.gradle | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 589b5f34b..12360845c 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -14,7 +14,6 @@ #Config for anallitycs -keepattributes *Annotation* -keepattributes SourceFile,LineNumberTable --renamesourcefileattribute SourceFile -keep class com.crashlytics.** {*;} -keep public class * extends java.lang.Exception -dontwarn com.crashlytics.** diff --git a/build.gradle b/build.gradle index d2f68da07..26becfc7c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.3.11' + ext.kotlin_version = '1.3.20' repositories { mavenCentral() google() From 43f6048c27b0e895168350a7b9bf683042e94212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Fri, 25 Jan 2019 20:41:03 +0100 Subject: [PATCH 029/192] Upgrade to Gradle Play Publisher v2 (#228) --- .circleci/config.yml | 2 +- .travis.yml | 6 +++++- app/build.gradle | 14 ++++---------- app/src/main/ic_launcher-web.png | Bin 19242 -> 0 bytes .../play/{contactEmail => contact-email.txt} | 0 .../play/{contactPhone => contact-phone.txt} | 0 .../{contactWebsite => contact-website.txt} | 0 .../{defaultLanguage => default-language.txt} | 0 .../pl-PL/full-description.txt} | 0 .../pl-PL/graphics/feature-graphic}/feature.png | Bin .../play/listings/pl-PL/graphics/icon/icon.png | Bin 0 -> 38676 bytes .../phone-screenshots}/account-switcher.png | Bin .../phone-screenshots}/attendance-dialog.png | Bin .../attendance-statistics.png | Bin .../graphics/phone-screenshots}/grades.png | Bin .../pl-PL/graphics/phone-screenshots}/more.png | Bin .../phone-screenshots}/timetable-dialog.png | Bin .../phone-screenshots}/timetable-widget.png | Bin .../pl-PL/short-description.txt} | 0 .../listing/title => listings/pl-PL/title.txt} | 0 app/src/main/play/pl-PL/listing/icon/icon.png | Bin 19242 -> 0 bytes app/src/main/play/pl-PL/listing/video | 0 .../pl-PL/default.txt} | 0 build.gradle | 2 +- 24 files changed, 11 insertions(+), 13 deletions(-) delete mode 100644 app/src/main/ic_launcher-web.png rename app/src/main/play/{contactEmail => contact-email.txt} (100%) rename app/src/main/play/{contactPhone => contact-phone.txt} (100%) rename app/src/main/play/{contactWebsite => contact-website.txt} (100%) rename app/src/main/play/{defaultLanguage => default-language.txt} (100%) rename app/src/main/play/{pl-PL/listing/fulldescription => listings/pl-PL/full-description.txt} (100%) rename app/src/main/play/{pl-PL/listing/featureGraphic => listings/pl-PL/graphics/feature-graphic}/feature.png (100%) create mode 100644 app/src/main/play/listings/pl-PL/graphics/icon/icon.png rename app/src/main/play/{pl-PL/listing/phoneScreenshots => listings/pl-PL/graphics/phone-screenshots}/account-switcher.png (100%) rename app/src/main/play/{pl-PL/listing/phoneScreenshots => listings/pl-PL/graphics/phone-screenshots}/attendance-dialog.png (100%) rename app/src/main/play/{pl-PL/listing/phoneScreenshots => listings/pl-PL/graphics/phone-screenshots}/attendance-statistics.png (100%) rename app/src/main/play/{pl-PL/listing/phoneScreenshots => listings/pl-PL/graphics/phone-screenshots}/grades.png (100%) rename app/src/main/play/{pl-PL/listing/phoneScreenshots => listings/pl-PL/graphics/phone-screenshots}/more.png (100%) rename app/src/main/play/{pl-PL/listing/phoneScreenshots => listings/pl-PL/graphics/phone-screenshots}/timetable-dialog.png (100%) rename app/src/main/play/{pl-PL/listing/phoneScreenshots => listings/pl-PL/graphics/phone-screenshots}/timetable-widget.png (100%) rename app/src/main/play/{pl-PL/listing/shortdescription => listings/pl-PL/short-description.txt} (100%) rename app/src/main/play/{pl-PL/listing/title => listings/pl-PL/title.txt} (100%) delete mode 100644 app/src/main/play/pl-PL/listing/icon/icon.png delete mode 100644 app/src/main/play/pl-PL/listing/video rename app/src/main/play/{pl-PL/whatsnew => release-notes/pl-PL/default.txt} (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1ae402f53..d4e59be19 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -159,7 +159,7 @@ jobs: openssl aes-256-cbc -d -in ./app/upload-key-encrypted.jks -k $ENCRYPT_KEY >> ./app/upload-key.jks - run: name: Publish release - command: ./gradlew publishRelease --no-daemon --stacktrace --console=plain -PenableCrashlytics -PdisablePreDex + command: ./gradlew publish --no-daemon --stacktrace --console=plain -PenableCrashlytics -PdisablePreDex workflows: version: 2 diff --git a/.travis.yml b/.travis.yml index a430c90ef..e2f4c9511 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,10 @@ cache: - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/ +branches: + only: + - master + android: licenses: - android-sdk-preview-license-.+ @@ -56,7 +60,7 @@ script: gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg; gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg; gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg; - ./gradlew publishRelease -PenableCrashlytics --stacktrace; + ./gradlew publish -PenableCrashlytics --stacktrace; fi after_success: diff --git a/app/build.gradle b/app/build.gradle index 4d199db2d..ef33e2343 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,13 +11,6 @@ android { compileSdkVersion 28 buildToolsVersion '28.0.3' - playAccountConfigs { - defaultAccountConfig { - serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") - pk12File = file('key.p12') - } - } - defaultConfig { applicationId "io.github.wulkanowy" testApplicationId "io.github.tests.wulkanowy" @@ -28,7 +21,6 @@ android { multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true - playAccountConfig = playAccountConfigs.defaultAccountConfig manifestPlaceholders = [ fabric_api_key: System.getenv("FABRIC_API_KEY") ?: "null", crashlytics_enabled: project.hasProperty("enableCrashlytics") @@ -72,14 +64,16 @@ androidExtensions { } play { + serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf" + serviceAccountCredentials = file('key.p12') + defaultToAppBundles = true track = 'alpha' - uploadImages = false } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation('io.github.wulkanowy:api:0.6.4') { exclude module: "threetenbp" } + implementation('com.github.wulkanowy:api:0fe0fbc69d') { exclude module: "threetenbp" } implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.appcompat:appcompat:1.0.2" diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png deleted file mode 100644 index de216d36b258956f80fca256b2f0e7dca99ed3e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19242 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 N;pyt{!{3*-O* diff --git a/app/src/main/play/contactEmail b/app/src/main/play/contact-email.txt similarity index 100% rename from app/src/main/play/contactEmail rename to app/src/main/play/contact-email.txt diff --git a/app/src/main/play/contactPhone b/app/src/main/play/contact-phone.txt similarity index 100% rename from app/src/main/play/contactPhone rename to app/src/main/play/contact-phone.txt diff --git a/app/src/main/play/contactWebsite b/app/src/main/play/contact-website.txt similarity index 100% rename from app/src/main/play/contactWebsite rename to app/src/main/play/contact-website.txt diff --git a/app/src/main/play/defaultLanguage b/app/src/main/play/default-language.txt similarity index 100% rename from app/src/main/play/defaultLanguage rename to app/src/main/play/default-language.txt diff --git a/app/src/main/play/pl-PL/listing/fulldescription b/app/src/main/play/listings/pl-PL/full-description.txt similarity index 100% rename from app/src/main/play/pl-PL/listing/fulldescription rename to app/src/main/play/listings/pl-PL/full-description.txt diff --git a/app/src/main/play/pl-PL/listing/featureGraphic/feature.png b/app/src/main/play/listings/pl-PL/graphics/feature-graphic/feature.png similarity index 100% rename from app/src/main/play/pl-PL/listing/featureGraphic/feature.png rename to app/src/main/play/listings/pl-PL/graphics/feature-graphic/feature.png diff --git a/app/src/main/play/listings/pl-PL/graphics/icon/icon.png b/app/src/main/play/listings/pl-PL/graphics/icon/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8c33c2f929170781210ac8b2bb25aeceed0d12a0 GIT binary patch literal 38676 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�R6`1j-{2W!5S8;mZL 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 UPO9Q$1_lNOPgg&ebxsLQ0L?Fx!2kdN literal 0 HcmV?d00001 diff --git a/app/src/main/play/pl-PL/listing/phoneScreenshots/account-switcher.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/account-switcher.png similarity index 100% rename from app/src/main/play/pl-PL/listing/phoneScreenshots/account-switcher.png rename to app/src/main/play/listings/pl-PL/graphics/phone-screenshots/account-switcher.png diff --git a/app/src/main/play/pl-PL/listing/phoneScreenshots/attendance-dialog.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/attendance-dialog.png similarity index 100% rename from app/src/main/play/pl-PL/listing/phoneScreenshots/attendance-dialog.png rename to app/src/main/play/listings/pl-PL/graphics/phone-screenshots/attendance-dialog.png diff --git a/app/src/main/play/pl-PL/listing/phoneScreenshots/attendance-statistics.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/attendance-statistics.png similarity index 100% rename from app/src/main/play/pl-PL/listing/phoneScreenshots/attendance-statistics.png rename to app/src/main/play/listings/pl-PL/graphics/phone-screenshots/attendance-statistics.png diff --git a/app/src/main/play/pl-PL/listing/phoneScreenshots/grades.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/grades.png similarity index 100% rename from app/src/main/play/pl-PL/listing/phoneScreenshots/grades.png rename to app/src/main/play/listings/pl-PL/graphics/phone-screenshots/grades.png diff --git a/app/src/main/play/pl-PL/listing/phoneScreenshots/more.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/more.png similarity index 100% rename from app/src/main/play/pl-PL/listing/phoneScreenshots/more.png rename to app/src/main/play/listings/pl-PL/graphics/phone-screenshots/more.png diff --git a/app/src/main/play/pl-PL/listing/phoneScreenshots/timetable-dialog.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/timetable-dialog.png similarity index 100% rename from app/src/main/play/pl-PL/listing/phoneScreenshots/timetable-dialog.png rename to app/src/main/play/listings/pl-PL/graphics/phone-screenshots/timetable-dialog.png diff --git a/app/src/main/play/pl-PL/listing/phoneScreenshots/timetable-widget.png b/app/src/main/play/listings/pl-PL/graphics/phone-screenshots/timetable-widget.png similarity index 100% rename from app/src/main/play/pl-PL/listing/phoneScreenshots/timetable-widget.png rename to app/src/main/play/listings/pl-PL/graphics/phone-screenshots/timetable-widget.png diff --git a/app/src/main/play/pl-PL/listing/shortdescription b/app/src/main/play/listings/pl-PL/short-description.txt similarity index 100% rename from app/src/main/play/pl-PL/listing/shortdescription rename to app/src/main/play/listings/pl-PL/short-description.txt diff --git a/app/src/main/play/pl-PL/listing/title b/app/src/main/play/listings/pl-PL/title.txt similarity index 100% rename from app/src/main/play/pl-PL/listing/title rename to app/src/main/play/listings/pl-PL/title.txt diff --git a/app/src/main/play/pl-PL/listing/icon/icon.png b/app/src/main/play/pl-PL/listing/icon/icon.png deleted file mode 100644 index de216d36b258956f80fca256b2f0e7dca99ed3e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19242 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 N;pyt{!{3*-O* diff --git a/app/src/main/play/pl-PL/listing/video b/app/src/main/play/pl-PL/listing/video deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/release-notes/pl-PL/default.txt similarity index 100% rename from app/src/main/play/pl-PL/whatsnew rename to app/src/main/play/release-notes/pl-PL/default.txt diff --git a/build.gradle b/build.gradle index 26becfc7c..444088e1c 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ buildscript { classpath 'com.android.tools.build:gradle:3.3.0' classpath 'com.google.gms:google-services:4.2.0' classpath "io.fabric.tools:gradle:1.27.0" - classpath "com.github.triplet.gradle:play-publisher:1.2.2" + classpath "com.github.triplet.gradle:play-publisher:2.1.0" classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7" classpath 'com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta02' } From 4da812af392ffbdf55960f8bb8d0d0f46721531b Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Fri, 25 Jan 2019 20:54:27 +0100 Subject: [PATCH 030/192] Add lucky numbers (#216) --- .travis.yml | 2 +- .../local/LuckyNumberLocalTest.kt | 47 +++++++++++ .../github/wulkanowy/data/RepositoryModule.kt | 4 + .../github/wulkanowy/data/db/AppDatabase.kt | 15 +++- .../wulkanowy/data/db/dao/LuckyNumberDao.kt | 29 +++++++ .../wulkanowy/data/db/entities/LuckyNumber.kt | 28 +++++++ .../data/db/migrations/Migration2.kt | 16 ++++ .../repositories/LuckyNumberRepository.kt | 52 +++++++++++++ .../repositories/local/LuckyNumberLocal.kt | 30 +++++++ .../repositories/remote/LuckyNumberRemote.kt | 26 +++++++ .../wulkanowy/services/job/SyncWorker.kt | 44 ++++++++--- .../notification/LuckyNumberNotification.kt | 48 ++++++++++++ .../luckynumber/LuckyNumberFragment.kt | 64 +++++++++++++++ .../luckynumber/LuckyNumberPresenter.kt | 65 ++++++++++++++++ .../ui/modules/luckynumber/LuckyNumberView.kt | 21 +++++ .../wulkanowy/ui/modules/main/MainModule.kt | 5 ++ .../wulkanowy/ui/modules/more/MoreFragment.kt | 13 ++++ .../ui/modules/more/MorePresenter.kt | 2 + .../wulkanowy/ui/modules/more/MoreView.kt | 4 + .../ic_stat_notify_lucky_number.xml | 14 ++++ .../ic_stat_notify_lucky_number.png | Bin 0 -> 473 bytes .../ic_stat_notify_lucky_number.png | Bin 0 -> 343 bytes .../ic_stat_notify_lucky_number.png | Bin 0 -> 713 bytes .../ic_stat_notify_lucky_number.png | Bin 0 -> 1088 bytes .../drawable/ic_more_lucky_number_24dp.xml | 9 +++ .../main/res/layout/fragment_lucky_number.xml | 73 ++++++++++++++++++ app/src/main/res/values-pl/strings.xml | 9 +++ app/src/main/res/values/strings.xml | 9 +++ .../remote/LuckyNumberRemoteTest.kt | 44 +++++++++++ 29 files changed, 658 insertions(+), 15 deletions(-) create mode 100644 app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/LuckyNumberLocalTest.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/dao/LuckyNumberDao.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/entities/LuckyNumber.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration2.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/LuckyNumberRepository.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/local/LuckyNumberLocal.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/remote/LuckyNumberRemote.kt create mode 100644 app/src/main/java/io/github/wulkanowy/services/notification/LuckyNumberNotification.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt create mode 100644 app/src/main/res/drawable-anydpi-v24/ic_stat_notify_lucky_number.xml create mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_lucky_number.png create mode 100644 app/src/main/res/drawable-mdpi/ic_stat_notify_lucky_number.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_lucky_number.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_stat_notify_lucky_number.png create mode 100644 app/src/main/res/drawable/ic_more_lucky_number_24dp.xml create mode 100644 app/src/main/res/layout/fragment_lucky_number.xml create mode 100644 app/src/test/java/io/github/wulkanowy/data/repositories/remote/LuckyNumberRemoteTest.kt diff --git a/.travis.yml b/.travis.yml index a430c90ef..9034de610 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ before_script: - "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | sudo bash" script: - - ./gradlew build -x test -x lint -x fabricGenerateResourcesRelease -x packageRelease --stacktrace --daemon + - ./gradlew dependencies --stacktrace --daemon - fossa --no-ansi || true - ./gradlew lint -x fabricGenerateResourcesRelease --stacktrace --daemon - ./gradlew test -x fabricGenerateResourcesRelease --stacktrace --daemon diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/LuckyNumberLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/LuckyNumberLocalTest.kt new file mode 100644 index 000000000..67ac4c2b4 --- /dev/null +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/LuckyNumberLocalTest.kt @@ -0,0 +1,47 @@ +package io.github.wulkanowy.data.repositories.local + +import androidx.room.Room +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.github.wulkanowy.data.db.AppDatabase +import io.github.wulkanowy.data.db.entities.LuckyNumber +import io.github.wulkanowy.data.db.entities.Semester +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.threeten.bp.LocalDate +import kotlin.test.assertEquals + +@RunWith(AndroidJUnit4::class) +class LuckyNumberLocalTest { + + private lateinit var luckyNumberLocal: LuckyNumberLocal + + private lateinit var testDb: AppDatabase + + @Before + fun createDb() { + testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java) + .build() + luckyNumberLocal = LuckyNumberLocal(testDb.luckyNumberDao) + } + + @After + fun closeDb() { + testDb.close() + } + + @Test + fun saveAndReadTest() { + luckyNumberLocal.saveLuckyNumber(LuckyNumber(1, LocalDate.of(2019, 1, 20), 14)) + + val luckyNumber = luckyNumberLocal.getLuckyNumber(Semester(1, 1, 2, "", 3, 1), + LocalDate.of(2019, 1, 20) + ).blockingGet() + + assertEquals(1, luckyNumber.studentId) + assertEquals(LocalDate.of(2019, 1, 20), luckyNumber.date) + assertEquals(14, luckyNumber.luckyNumber) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt index f5bb1b2a4..e72175bb8 100644 --- a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt +++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt @@ -113,4 +113,8 @@ internal class RepositoryModule { @Singleton @Provides fun provideSubjectDao(database: AppDatabase) = database.subjectDao + + @Singleton + @Provides + fun provideLuckyNumberDao(database: AppDatabase) = database.luckyNumberDao } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt index 30c957b43..974d5daba 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt @@ -6,6 +6,8 @@ import androidx.room.Room import androidx.room.RoomDatabase import androidx.room.RoomDatabase.JournalMode.TRUNCATE import androidx.room.TypeConverters +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase import io.github.wulkanowy.data.db.dao.AttendanceDao import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao import io.github.wulkanowy.data.db.dao.ExamDao @@ -13,6 +15,7 @@ import io.github.wulkanowy.data.db.dao.GradeDao import io.github.wulkanowy.data.db.dao.GradeSummaryDao import io.github.wulkanowy.data.db.dao.MessagesDao import io.github.wulkanowy.data.db.dao.HomeworkDao +import io.github.wulkanowy.data.db.dao.LuckyNumberDao import io.github.wulkanowy.data.db.dao.NoteDao import io.github.wulkanowy.data.db.dao.SemesterDao import io.github.wulkanowy.data.db.dao.StudentDao @@ -25,11 +28,13 @@ import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Homework +import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.Note import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Subject import io.github.wulkanowy.data.db.entities.Timetable +import io.github.wulkanowy.data.db.migrations.Migration2 import javax.inject.Singleton @Singleton @@ -46,9 +51,10 @@ import javax.inject.Singleton Message::class, Note::class, Homework::class, - Subject::class + Subject::class, + LuckyNumber::class ], - version = 1, + version = 2, exportSchema = false ) @TypeConverters(Converters::class) @@ -58,6 +64,9 @@ abstract class AppDatabase : RoomDatabase() { fun newInstance(context: Context): AppDatabase { return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database") .setJournalMode(TRUNCATE) + .addMigrations( + Migration2() + ) .build() } } @@ -85,4 +94,6 @@ abstract class AppDatabase : RoomDatabase() { abstract val homeworkDao: HomeworkDao abstract val subjectDao: SubjectDao + + abstract val luckyNumberDao: LuckyNumberDao } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/LuckyNumberDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/LuckyNumberDao.kt new file mode 100644 index 000000000..05736e42d --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/LuckyNumberDao.kt @@ -0,0 +1,29 @@ +package io.github.wulkanowy.data.db.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import io.github.wulkanowy.data.db.entities.LuckyNumber +import io.reactivex.Maybe +import org.threeten.bp.LocalDate +import javax.inject.Singleton + +@Singleton +@Dao +interface LuckyNumberDao { + + @Insert + fun insert(luckyNumber: LuckyNumber) + + @Update + fun update(luckyNumber: LuckyNumber) + + @Delete + fun delete(luckyNumber: LuckyNumber) + + @Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date") + fun loadFromDate(studentId: Int, date: LocalDate): Maybe + +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/LuckyNumber.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/LuckyNumber.kt new file mode 100644 index 000000000..6144b7429 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/LuckyNumber.kt @@ -0,0 +1,28 @@ +package io.github.wulkanowy.data.db.entities + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import org.threeten.bp.LocalDate +import java.io.Serializable + +@Entity(tableName = "LuckyNumbers") +data class LuckyNumber ( + + @ColumnInfo(name = "student_id") + var studentId: Int, + + var date: LocalDate, + + @ColumnInfo(name = "lucky_number") + var luckyNumber: Int + +) : Serializable { + + @PrimaryKey(autoGenerate = true) + var id: Long = 0 + + @ColumnInfo(name = "is_notified") + var isNotified: Boolean = true + +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration2.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration2.kt new file mode 100644 index 000000000..30ddc3bbb --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration2.kt @@ -0,0 +1,16 @@ +package io.github.wulkanowy.data.db.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration2 : Migration(1, 2) { + + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("CREATE TABLE LuckyNumbers (" + + "id INTEGER NOT NULL PRIMARY KEY, " + + "is_notified INTEGER NOT NULL, " + + "student_id INTEGER NOT NULL, " + + "date INTEGER NOT NULL, " + + "lucky_number INTEGER NOT NULL)") + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/LuckyNumberRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/LuckyNumberRepository.kt new file mode 100644 index 000000000..737dc925b --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/LuckyNumberRepository.kt @@ -0,0 +1,52 @@ +package io.github.wulkanowy.data.repositories + +import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork +import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings +import io.github.wulkanowy.data.db.entities.LuckyNumber +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.repositories.local.LuckyNumberLocal +import io.github.wulkanowy.data.repositories.remote.LuckyNumberRemote +import io.reactivex.Completable +import io.reactivex.Maybe +import org.threeten.bp.LocalDate +import java.net.UnknownHostException +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class LuckyNumberRepository @Inject constructor( + private val settings: InternetObservingSettings, + private val local: LuckyNumberLocal, + private val remote: LuckyNumberRemote +) { + + fun getLuckyNumber(semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Maybe { + return local.getLuckyNumber(semester, LocalDate.now()).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMapMaybe { + if (it) remote.getLuckyNumber(semester) + else Maybe.error(UnknownHostException()) + }.flatMap { new -> + local.getLuckyNumber(semester, LocalDate.now()) + .doOnSuccess { old -> + if (new != old) { + local.deleteLuckyNumber(old) + local.saveLuckyNumber(new.apply { + if (notify) isNotified = false + }) + } + } + .doOnComplete { + local.saveLuckyNumber(new.apply { + if (notify) isNotified = false + }) + } + }.flatMap({ local.getLuckyNumber(semester, LocalDate.now()) }, { Maybe.error(it) }, + { local.getLuckyNumber(semester, LocalDate.now()) }) + ) + } + + fun updateLuckyNumber(luckyNumber: LuckyNumber): Completable { + return local.updateLuckyNumber(luckyNumber) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/LuckyNumberLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/local/LuckyNumberLocal.kt new file mode 100644 index 000000000..a04ea7404 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/local/LuckyNumberLocal.kt @@ -0,0 +1,30 @@ +package io.github.wulkanowy.data.repositories.local + +import io.github.wulkanowy.data.db.dao.LuckyNumberDao +import io.github.wulkanowy.data.db.entities.LuckyNumber +import io.github.wulkanowy.data.db.entities.Semester +import io.reactivex.Completable +import io.reactivex.Maybe +import org.threeten.bp.LocalDate +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class LuckyNumberLocal @Inject constructor(private val luckyNumberDb: LuckyNumberDao) { + + fun getLuckyNumber(semester: Semester, date: LocalDate): Maybe { + return luckyNumberDb.loadFromDate(semester.studentId, date) + } + + fun saveLuckyNumber(luckyNumber: LuckyNumber) { + luckyNumberDb.insert(luckyNumber) + } + + fun updateLuckyNumber(luckyNumber: LuckyNumber): Completable { + return Completable.fromCallable { luckyNumberDb.update(luckyNumber) } + } + + fun deleteLuckyNumber(luckyNumber: LuckyNumber) { + luckyNumberDb.delete(luckyNumber) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/LuckyNumberRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/remote/LuckyNumberRemote.kt new file mode 100644 index 000000000..36ff57f94 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/remote/LuckyNumberRemote.kt @@ -0,0 +1,26 @@ +package io.github.wulkanowy.data.repositories.remote + +import io.github.wulkanowy.api.Api +import io.github.wulkanowy.data.db.entities.LuckyNumber +import io.github.wulkanowy.data.db.entities.Semester +import io.reactivex.Maybe +import io.reactivex.Single +import org.threeten.bp.LocalDate +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class LuckyNumberRemote @Inject constructor(private val api: Api) { + + fun getLuckyNumber(semester: Semester): Maybe { + return Single.just(api.apply { diaryId = semester.diaryId }) + .flatMapMaybe { it.getLuckyNumber() } + .map { + LuckyNumber( + studentId = semester.studentId, + date = LocalDate.now(), + luckyNumber = it + ) + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt b/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt index cf09728a6..5ad8ce0ff 100644 --- a/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt +++ b/app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt @@ -8,6 +8,7 @@ import io.github.wulkanowy.data.repositories.ExamRepository import io.github.wulkanowy.data.repositories.GradeRepository import io.github.wulkanowy.data.repositories.GradeSummaryRepository import io.github.wulkanowy.data.repositories.HomeworkRepository +import io.github.wulkanowy.data.repositories.LuckyNumberRepository import io.github.wulkanowy.data.repositories.MessagesRepository import io.github.wulkanowy.data.repositories.MessagesRepository.MessageFolder.RECEIVED import io.github.wulkanowy.data.repositories.NoteRepository @@ -16,12 +17,13 @@ import io.github.wulkanowy.data.repositories.SemesterRepository import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.repositories.TimetableRepository import io.github.wulkanowy.services.notification.GradeNotification +import io.github.wulkanowy.services.notification.LuckyNumberNotification import io.github.wulkanowy.services.notification.MessageNotification import io.github.wulkanowy.services.notification.NoteNotification import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.isHolidays import io.github.wulkanowy.utils.monday -import io.reactivex.Single +import io.reactivex.Completable import io.reactivex.disposables.CompositeDisposable import org.threeten.bp.LocalDate import timber.log.Timber @@ -59,6 +61,9 @@ class SyncWorker : SimpleJobService() { @Inject lateinit var homework: HomeworkRepository + @Inject + lateinit var luckyNumber: LuckyNumberRepository + @Inject lateinit var prefRepository: PreferencesRepository @@ -88,18 +93,19 @@ class SyncWorker : SimpleJobService() { disposable.add(student.getCurrentStudent() .flatMap { semester.getCurrentSemester(it, true).map { semester -> semester to it } } - .flatMapPublisher { - Single.merge( + .flatMapCompletable { + Completable.merge( listOf( - gradesDetails.getGrades(it.first, true, notify), - gradesSummary.getGradesSummary(it.first, true), - attendance.getAttendance(it.first, start, end, true), - exam.getExams(it.first, start, end, true), - timetable.getTimetable(it.first, start, end, true), - message.getMessages(it.second, RECEIVED, true, notify), - note.getNotes(it.first, true, notify), - homework.getHomework(it.first, LocalDate.now(), true), - homework.getHomework(it.first, LocalDate.now().plusDays(1), true) + gradesDetails.getGrades(it.first, true, notify).ignoreElement(), + gradesSummary.getGradesSummary(it.first, true).ignoreElement(), + attendance.getAttendance(it.first, start, end, true).ignoreElement(), + exam.getExams(it.first, start, end, true).ignoreElement(), + timetable.getTimetable(it.first, start, end, true).ignoreElement(), + message.getMessages(it.second, RECEIVED, true, notify).ignoreElement(), + note.getNotes(it.first, true, notify).ignoreElement(), + homework.getHomework(it.first, LocalDate.now(), true).ignoreElement(), + homework.getHomework(it.first, LocalDate.now().plusDays(1), true).ignoreElement(), + luckyNumber.getLuckyNumber(it.first, true, notify).ignoreElement() ) ) } @@ -119,6 +125,7 @@ class SyncWorker : SimpleJobService() { sendGradeNotifications() sendMessageNotification() sendNoteNotification() + sendLuckyNumberNotification() } private fun sendGradeNotifications() { @@ -170,6 +177,19 @@ class SyncWorker : SimpleJobService() { ) } + private fun sendLuckyNumberNotification() { + disposable.add(student.getCurrentStudent() + .flatMap { semester.getCurrentSemester(it) } + .flatMapMaybe { luckyNumber.getLuckyNumber(it) } + .filter { !it.isNotified } + .doOnSuccess { + LuckyNumberNotification(applicationContext).sendNotification(it) + } + .map { it.apply { isNotified = true } } + .flatMapCompletable { luckyNumber.updateLuckyNumber(it) } + .subscribe({}, { Timber.e("Lucky number notification sending failed") })) + } + override fun onDestroy() { super.onDestroy() disposable.clear() diff --git a/app/src/main/java/io/github/wulkanowy/services/notification/LuckyNumberNotification.kt b/app/src/main/java/io/github/wulkanowy/services/notification/LuckyNumberNotification.kt new file mode 100644 index 000000000..9db159aad --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/services/notification/LuckyNumberNotification.kt @@ -0,0 +1,48 @@ +package io.github.wulkanowy.services.notification + +import android.annotation.TargetApi +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import androidx.core.app.NotificationCompat +import androidx.core.content.ContextCompat +import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.LuckyNumber +import io.github.wulkanowy.ui.modules.main.MainActivity + +class LuckyNumberNotification(context: Context) : BaseNotification(context) { + + private val channelId = "Lucky_Number_Notify" + + @TargetApi(26) + override fun createChannel(channelId: String) { + notificationManager.createNotificationChannel(NotificationChannel( + channelId, context.getString(R.string.notify_lucky_number_channel), NotificationManager.IMPORTANCE_HIGH + ).apply { + enableLights(true) + enableVibration(true) + lockscreenVisibility = Notification.VISIBILITY_PUBLIC + }) + } + + fun sendNotification(luckyNumber: LuckyNumber) { + notify(notificationBuilder(channelId) + .setContentTitle(context.getString(R.string.notify_lucky_number_new_item_title)) + .setContentText(context.getString(R.string.notify_lucky_number_new_item, luckyNumber.luckyNumber)) + .setSmallIcon(R.drawable.ic_stat_notify_lucky_number) + .setAutoCancel(true) + .setDefaults(NotificationCompat.DEFAULT_ALL) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setColor(ContextCompat.getColor(context, R.color.colorPrimary)) + .setContentIntent( + PendingIntent.getActivity(context, 0, + MainActivity.getStartIntent(context).putExtra(MainActivity.EXTRA_START_MENU_INDEX, 4), + PendingIntent.FLAG_UPDATE_CURRENT + ) + ) + .build() + ) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt new file mode 100644 index 000000000..d535e8255 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberFragment.kt @@ -0,0 +1,64 @@ +package io.github.wulkanowy.ui.modules.luckynumber + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.LuckyNumber +import io.github.wulkanowy.ui.base.session.BaseSessionFragment +import io.github.wulkanowy.ui.modules.main.MainView +import kotlinx.android.synthetic.main.fragment_lucky_number.* +import javax.inject.Inject + +class LuckyNumberFragment : BaseSessionFragment(), LuckyNumberView, MainView.TitledView { + + @Inject + lateinit var presenter: LuckyNumberPresenter + + companion object { + fun newInstance() = LuckyNumberFragment() + } + + override val titleStringId: Int + get() = R.string.lucky_number_title + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_lucky_number, container, false) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + presenter.onAttachView(this) + } + + override fun initView() { + showContent(false) + showProgress(true) + luckyNumberSwipe.setOnRefreshListener { presenter.onSwipeRefresh() } + } + + override fun updateData(data: LuckyNumber) { + luckyNumberText.text = data.luckyNumber.toString() + } + + override fun hideRefresh() { + luckyNumberSwipe.isRefreshing = false + } + + override fun showEmpty(show: Boolean) { + luckyNumberEmpty.visibility = if (show) View.VISIBLE else View.GONE + } + + override fun showProgress(show: Boolean) { + luckyNumberProgress.visibility = if (show) View.VISIBLE else View.GONE + } + + override fun showContent(show: Boolean) { + luckyNumberContent.visibility = if (show) View.VISIBLE else View.GONE + } + + override fun isViewEmpty(): Boolean { + return luckyNumberText.text.isBlank() + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt new file mode 100644 index 000000000..50de42e57 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt @@ -0,0 +1,65 @@ +package io.github.wulkanowy.ui.modules.luckynumber + +import io.github.wulkanowy.data.repositories.LuckyNumberRepository +import io.github.wulkanowy.data.repositories.SemesterRepository +import io.github.wulkanowy.data.repositories.StudentRepository +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.utils.FirebaseAnalyticsHelper +import io.github.wulkanowy.utils.SchedulersProvider +import io.reactivex.MaybeSource +import javax.inject.Inject + +class LuckyNumberPresenter @Inject constructor( + private val errorHandler: SessionErrorHandler, + private val schedulers: SchedulersProvider, + private val luckyNumberRepository: LuckyNumberRepository, + private val studentRepository: StudentRepository, + private val semesterRepository: SemesterRepository, + private val analytics: FirebaseAnalyticsHelper +) : BasePresenter(errorHandler) { + + override fun onAttachView(view: LuckyNumberView) { + super.onAttachView(view) + view.initView() + loadData() + } + + private fun loadData(forceRefresh: Boolean = false) { + disposable.apply { + clear() + add(studentRepository.getCurrentStudent() + .flatMap { semesterRepository.getCurrentSemester(it) } + .flatMapMaybe { luckyNumberRepository.getLuckyNumber(it, forceRefresh) } + .subscribeOn(schedulers.backgroundThread) + .observeOn(schedulers.mainThread) + .doFinally { + view?.run { + hideRefresh() + showProgress(false) + } + } + .subscribe({ + view?.apply { + updateData(it) + showContent(true) + showEmpty(false) + } + analytics.logEvent("load_lucky_number", mapOf("force_refresh" to forceRefresh)) + }, { + view?.run { showEmpty(isViewEmpty()) } + errorHandler.dispatch(it) + }, { + view?.run { + showContent(false) + showEmpty(true) + } + }) + ) + } + } + + fun onSwipeRefresh() { + loadData(true) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt new file mode 100644 index 000000000..eece5b705 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberView.kt @@ -0,0 +1,21 @@ +package io.github.wulkanowy.ui.modules.luckynumber + +import io.github.wulkanowy.data.db.entities.LuckyNumber +import io.github.wulkanowy.ui.base.session.BaseSessionView + +interface LuckyNumberView : BaseSessionView { + + fun initView() + + fun updateData(data: LuckyNumber) + + fun hideRefresh() + + fun showEmpty(show: Boolean) + + fun showProgress(show: Boolean) + + fun showContent(show: Boolean) + + fun isViewEmpty(): Boolean +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt index 9d1c44c07..1d98ce636 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt @@ -16,6 +16,7 @@ import io.github.wulkanowy.ui.modules.exam.ExamFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment import io.github.wulkanowy.ui.modules.grade.GradeModule import io.github.wulkanowy.ui.modules.homework.HomeworkFragment +import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment import io.github.wulkanowy.ui.modules.message.MessageFragment import io.github.wulkanowy.ui.modules.message.MessageModule import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment @@ -86,6 +87,10 @@ abstract class MainModule { @ContributesAndroidInjector abstract fun bindHomeworkFragment(): HomeworkFragment + @PerFragment + @ContributesAndroidInjector + abstract fun bindLuckyNumberFragment(): LuckyNumberFragment + @PerFragment @ContributesAndroidInjector abstract fun bindsAccountDialog(): AccountDialog diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt index 226fccd6d..5bbf6247a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreFragment.kt @@ -13,6 +13,7 @@ import io.github.wulkanowy.R import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.about.AboutFragment import io.github.wulkanowy.ui.modules.homework.HomeworkFragment +import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.message.MessageFragment @@ -60,6 +61,14 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai } } + override val luckyNumberRes: Pair? + get() { + return context?.run { + getString(R.string.lucky_number_title) to + ContextCompat.getDrawable(this, R.drawable.ic_more_lucky_number_24dp) + } + } + override val settingsRes: Pair? get() { return context?.run { @@ -114,6 +123,10 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai (activity as? MainActivity)?.pushView(NoteFragment.newInstance()) } + override fun openLuckyNumberView() { + (activity as? MainActivity)?.pushView(LuckyNumberFragment.newInstance()) + } + override fun openSettingsView() { (activity as? MainActivity)?.pushView(SettingsFragment.newInstance()) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt index 6becc8ad1..5fea241c7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MorePresenter.kt @@ -23,6 +23,7 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresen messagesRes?.first -> openMessagesView() homeworkRes?.first -> openHomeworkView() noteRes?.first -> openNoteView() + luckyNumberRes?.first -> openLuckyNumberView() settingsRes?.first -> openSettingsView() aboutRes?.first -> openAboutView() } @@ -42,6 +43,7 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresen messagesRes?.let { MoreItem(it.first, it.second) }, homeworkRes?.let { MoreItem(it.first, it.second) }, noteRes?.let { MoreItem(it.first, it.second) }, + luckyNumberRes?.let { MoreItem(it.first, it.second) }, settingsRes?.let { MoreItem(it.first, it.second) }, aboutRes?.let { MoreItem(it.first, it.second) }) ) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreView.kt index 08ff82adb..333edc5df 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/more/MoreView.kt @@ -11,6 +11,8 @@ interface MoreView : BaseView { val noteRes: Pair? + val luckyNumberRes: Pair? + val settingsRes: Pair? val aboutRes: Pair? @@ -30,4 +32,6 @@ interface MoreView : BaseView { fun openHomeworkView() fun openNoteView() + + fun openLuckyNumberView() } diff --git a/app/src/main/res/drawable-anydpi-v24/ic_stat_notify_lucky_number.xml b/app/src/main/res/drawable-anydpi-v24/ic_stat_notify_lucky_number.xml new file mode 100644 index 000000000..00538168f --- /dev/null +++ b/app/src/main/res/drawable-anydpi-v24/ic_stat_notify_lucky_number.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/app/src/main/res/drawable-hdpi/ic_stat_notify_lucky_number.png b/app/src/main/res/drawable-hdpi/ic_stat_notify_lucky_number.png new file mode 100644 index 0000000000000000000000000000000000000000..b91c4ae6cd7f35cc89f9920e42527c8f3bc816b1 GIT binary patch literal 473 zcmeAS@N?(olHy`uVBq!ia0y~yU{C>J4mJh`hKCF@W-u@?F7R}545_&FcKX4rLk^HI4e`@E{W(jW5cs4o`c&(|y*&vL)d`4zHZPFPZYiiOX}HiBJERiT}5hzu2vLf1k<) zBlGQ3RW4j)dZEHuvVpmu`nKlzTOla_>}q zmG9o}^*{N?8p+lETmDX+DkHnjbLFlBjui(EzF3@_vLRFbh4BH#TE`OCty8wGnzBK| zzUE|AMsnZ+*GUfP+zXmjE}Ud~p~1Oj6GN02(^p-+E?f6Y0gu{t=q=x2Cm#Ni;reS? hp*7DzLHdm~=Xb)|NwfG)GB7YOc)I$ztaD0e0sv<**-Zcd literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_stat_notify_lucky_number.png b/app/src/main/res/drawable-mdpi/ic_stat_notify_lucky_number.png new file mode 100644 index 0000000000000000000000000000000000000000..bfced4eb088c8e2818255e0c50634dd72673fee9 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJo}P4L!)$WWe*a zDScuAv&|=MiMo~#st589h%>~wzCWODxqC?`?VSHd%SX%G}erEMClwhujoQ1uW{FUcAs{)^cdt7pIVa(n-r_ zr7~xUH`4)5gS8X-f8_6Mh|_XCDsZ%6<`16X9-sOST5mT9+>Ps??ZMhSmA@XUxbW0 yJGk(B@a7j&yRSAow=n(nnY8irv`6P}3d@E6IhTJtZ2~)jkNY=b`A6=dTqJxR6m>ZmvWE>N2bs62rVu#sjqV;T1uR&K6~fU zvK#z%LV4fIp5H$H=1iR4^9K(eG<>kh=d9pa!>sOfYIy^DNczI*Jo?P}d-i8A9Pd0k z;gi^gl-oa)KHTg+#%##-P>F}sW#=#hT5ac{v@!iWBbPcFMjDJ-G?WBukd6^c=K=VizmI3R{S+8=Pqxa+HuqK zPR*cyYePR@0da*H-&r(H#B?XITdztUj7c5Z8*>jq2)7u%%XT*1`wm8A3 z$~3KYp-ZfwS4gYzMh(FW;)U0RS=f@M@*KP)#oFSTk*UAt(VE?NXYvZo{0% zRtHy4-D2rD@s6haO+Hn5*0clNNx}OzF`fvXbS3R+{1l(FGftdg(>N>5ZF7EkOjhCM z2#zh5PPM#$-PhG*DXg^LUa5W2OyR+~X&(=>>2Gtpdv%f10fpEzX{=Q{>Y`7-xYW?V zJ$rV=wFB&ZN$1ou^jq#Kn%-1j=5{33-}1Wl0hKnp2eK_k-%Uxrvhv)d-#V`zJowNp Z-&}TvbH0zEI|Bm)gQu&X%Q~loCIG__N1Olv literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_stat_notify_lucky_number.png b/app/src/main/res/drawable-xxhdpi/ic_stat_notify_lucky_number.png new file mode 100644 index 0000000000000000000000000000000000000000..9bab1373178182d45ec40c6ad1e84181190e5611 GIT binary patch literal 1088 zcmeAS@N?(olHy`uVBq!ia0y~yVDJE84mJh`hS0a0-5D5I*gahwLn>~)o$c!_?I>}4 z@y18ouOdIJk$1ev>x=~h>@P2G>1?=W%5=*_@It4X z!*Vqyt7{xDF1R>kOEIpU!I2T5ykJLXgOrMTjpJA0nCw?E8Gg(QG$*HDDt*A+T5#@w z>C%czoFCZgr^q)>Kd8Ugiu-WjNRP_Yi^tN=DV{PE7R&f@4 zbjs%CDrK&FY7LVQKA3G_^`2`D^LbS_*5y2ZR1a|0o|rH2XD!Qn))m^_r8^qxc>=`Q zJ}eSxi0Z8S`lr+Oq2Ljxt<9;i3yfL*zFNXy;#PA1#4bMp#az*VGH;F9s;@4yur6Rd zG<$WmNP>X9ZlK!RT`t-k?~*H*dKH@OQN5G$ytZ$y_$DRkBegRZGMKDM;G6u7HEAuDE?+c>D`@>9SM|7{^ES7tx&EzPu{TaMd*eN&WnY$Z zyqG5=aDHn0TcPZQEL+46&HlnDI>*g*|D*qPXCA-EUBqA_@~HEX0qcU90{W)UG#Hk0 zSa0#(5OG%ETY4kY1(vI4rfS>?Jh+%iL~1d^70(M3a}^V|2^V}xl%3D<>#7%{#;HHw z#ZSd31%|5_NEe8N?b5sWo$=KngCfbRi|xWvF8u2)n0!{C_t=UFxjS`}RPQfVdaEq` z?SP2S^h3wLYzip1E)MeD6twy0WXst`=WC^oEs<4w|BC6!l@wFGErEyUEO|QBU(%;) z)m=^|-Vj6e-tL!ogr6-b|7g6d`n7G}dyPjz6JkrsDz~&RFyQU$Jf(ckeU80q#LC=n zPv+VtzbZNCbLZhJCX=IAvd@KBY&~=H&XOpJT^R;~0drnnUeMVPX2KL@EO=p|o5OK6 zCabF)FOIl4%$8zYJDWpep + + diff --git a/app/src/main/res/layout/fragment_lucky_number.xml b/app/src/main/res/layout/fragment_lucky_number.xml new file mode 100644 index 000000000..fb05c7e49 --- /dev/null +++ b/app/src/main/res/layout/fragment_lucky_number.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 3c4a4ebba..a379c39de 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -184,6 +184,15 @@ Brak zadań domowych + + Szczęśliwy numerek + Dzisiejszym szczęśliwym numerkiem jest + Brak informacji o szczęśliwym numerku + + + Nowe szczęśliwe numerki + Szczęśliwy numerek na dzisiaj + Dziś szczęśliwym numerkiem jest: %d Dodaj konto diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index be6cec495..2013deac7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -167,6 +167,15 @@ No info about homework + + Lucky number + Today\'s lucky number is + No info about the lucky number + + + New lucky numbers + Lucky number for today + Today\'s lucky number is: %d Add account diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/remote/LuckyNumberRemoteTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/remote/LuckyNumberRemoteTest.kt new file mode 100644 index 000000000..b4f0b0cec --- /dev/null +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/remote/LuckyNumberRemoteTest.kt @@ -0,0 +1,44 @@ +package io.github.wulkanowy.data.repositories.remote + +import io.github.wulkanowy.api.Api +import io.github.wulkanowy.data.db.entities.Semester +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.SpyK +import io.reactivex.Maybe +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.threeten.bp.LocalDate + +class LuckyNumberRemoteTest { + + @SpyK + private var mockApi = Api() + + @MockK + private lateinit var semesterMock: Semester + + @Before + fun initApi() { + MockKAnnotations.init(this) + } + + @Test + fun getLuckyNumberTest() { + every { mockApi.getLuckyNumber() } returns Maybe.just(14) + + every { mockApi.diaryId } returns 1 + every { semesterMock.studentId } returns 1 + every { semesterMock.diaryId } returns 1 + + val luckyNumber = LuckyNumberRemote(mockApi) + .getLuckyNumber(semesterMock) + .blockingGet() + + assertEquals(14, luckyNumber.luckyNumber) + assertEquals(LocalDate.now(), luckyNumber.date) + assertEquals(semesterMock.studentId, luckyNumber.studentId) + } +} From 7f162441e2864cacb7021038a065f482062fb71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Fri, 25 Jan 2019 21:42:53 +0100 Subject: [PATCH 031/192] Version 0.6.6 --- .travis.yml | 6 +++--- app/build.gradle | 6 +++--- app/src/main/play/release-notes/pl-PL/default.txt | 9 +++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index e2f4c9511..de271c930 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ cache: - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/ -branches: - only: - - master +#branches: +# only: +# - master android: licenses: diff --git a/app/build.gradle b/app/build.gradle index ef33e2343..7d87553a4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 28 - versionCode 24 - versionName "0.6.5" + versionCode 25 + versionName "0.6.6" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true @@ -73,7 +73,7 @@ play { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation('com.github.wulkanowy:api:0fe0fbc69d') { exclude module: "threetenbp" } + implementation('io.github.wulkanowy:api:0.6.6') { exclude module: "threetenbp" } implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.appcompat:appcompat:1.0.2" diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt index 70c0352ad..c8a56ad42 100644 --- a/app/src/main/play/release-notes/pl-PL/default.txt +++ b/app/src/main/play/release-notes/pl-PL/default.txt @@ -1,6 +1,7 @@ -Wersja 0.6.5 +Wersja 0.6.6 -- zmieniono ikonę zmiany semestru w ocenach -- naprawiono wyświetlanie szczegółowych informacji o błędach +- poprawiono problemy ze stabilnością w widoku ocen i wiadomości +- naprawiono wyświetlanie powiadomień po ich ponownym włączeniu po długim czasie +- ograniczono ilość zbędnych informacji na widżecie planu lekcji -Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.6.5 +Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.6.6 From 2f87779647812675814e56bdcac314faed544877 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Tue, 5 Feb 2019 18:18:49 +0100 Subject: [PATCH 032/192] Add Firebase Analytics for the loaded lucky number (#233) --- .../wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt index 50de42e57..e03071b7e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumber/LuckyNumberPresenter.kt @@ -45,7 +45,7 @@ class LuckyNumberPresenter @Inject constructor( showContent(true) showEmpty(false) } - analytics.logEvent("load_lucky_number", mapOf("force_refresh" to forceRefresh)) + analytics.logEvent("load_lucky_number", mapOf("lucky_number" to it.luckyNumber, "force_refresh" to forceRefresh)) }, { view?.run { showEmpty(isViewEmpty()) } errorHandler.dispatch(it) From 1b1f2ae3bb06bf30bd32a44abb26f89e44940a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Mon, 11 Feb 2019 02:04:24 +0100 Subject: [PATCH 033/192] Split login form for two fragments (#230) --- .idea/codeStyles/Project.xml | 1 - app/build.gradle | 18 ++- .../io/github/wulkanowy/data/ApiHelper.kt | 2 +- .../wulkanowy/data/db/entities/Student.kt | 3 +- .../data/repositories/StudentRepository.kt | 10 +- .../data/repositories/remote/GradeRemote.kt | 4 +- .../data/repositories/remote/StudentRemote.kt | 16 +-- .../java/io/github/wulkanowy/di/AppModule.kt | 7 ++ .../ui/modules/about/AboutPresenter.kt | 4 +- .../modules/attendance/AttendancePresenter.kt | 2 +- .../summary/AttendanceSummaryPresenter.kt | 2 +- .../ui/modules/exam/ExamPresenter.kt | 2 +- .../ui/modules/grade/GradePresenter.kt | 2 +- .../grade/details/GradeDetailsPresenter.kt | 2 +- .../grade/summary/GradeSummaryPresenter.kt | 2 +- .../ui/modules/homework/HomeworkPresenter.kt | 2 +- .../ui/modules/login/LoginActivity.kt | 38 ++++--- .../wulkanowy/ui/modules/login/LoginModule.kt | 13 ++- .../ui/modules/login/LoginPresenter.kt | 44 ++++++-- .../wulkanowy/ui/modules/login/LoginView.kt | 9 +- .../modules/login/form/LoginFormFragment.kt | 92 +++++---------- .../modules/login/form/LoginFormPresenter.kt | 45 ++------ .../ui/modules/login/form/LoginFormView.kt | 19 +--- .../LoginStudentSelectFragment.kt} | 33 ++++-- .../LoginStudentSelectItem.kt} | 6 +- .../LoginStudentSelectPresenter.kt} | 37 +++--- .../LoginStudentSelectView.kt} | 6 +- .../login/symbol/LoginSymbolFragment.kt | 106 ++++++++++++++++++ .../login/symbol/LoginSymbolPresenter.kt | 82 ++++++++++++++ .../modules/login/symbol/LoginSymbolView.kt | 25 +++++ .../luckynumber/LuckyNumberPresenter.kt | 3 +- .../ui/modules/main/MainPresenter.kt | 4 +- .../preview/MessagePreviewPresenter.kt | 4 +- .../message/tab/MessageTabPresenter.kt | 2 +- .../ui/modules/note/NotePresenter.kt | 2 +- .../ui/modules/settings/SettingsPresenter.kt | 2 +- .../modules/timetable/TimetablePresenter.kt | 2 +- .../timetable/TimetableWidgetProvider.kt | 2 +- .../utils/FirebaseAnalyticsHelper.kt | 12 +- .../main/res/layout/fragment_login_form.xml | 89 +++++---------- ....xml => fragment_login_student_select.xml} | 9 +- .../main/res/layout/fragment_login_symbol.xml | 88 +++++++++++++++ .../repositories/remote/StudentRemoteTest.kt | 6 +- .../ui/modules/login/LoginPresenterTest.kt | 22 +--- .../login/form/LoginFormPresenterTest.kt | 41 ++----- .../LoginStudentSelectPresenterTest.kt} | 48 +++----- build.gradle | 5 +- 47 files changed, 597 insertions(+), 378 deletions(-) rename app/src/main/java/io/github/wulkanowy/ui/modules/login/{options/LoginOptionsFragment.kt => studentselect/LoginStudentSelectFragment.kt} (68%) rename app/src/main/java/io/github/wulkanowy/ui/modules/login/{options/LoginOptionsItem.kt => studentselect/LoginStudentSelectItem.kt} (87%) rename app/src/main/java/io/github/wulkanowy/ui/modules/login/{options/LoginOptionsPresenter.kt => studentselect/LoginStudentSelectPresenter.kt} (68%) rename app/src/main/java/io/github/wulkanowy/ui/modules/login/{options/LoginOptionsView.kt => studentselect/LoginStudentSelectView.kt} (56%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt rename app/src/main/res/layout/{fragment_login_options.xml => fragment_login_student_select.xml} (83%) create mode 100644 app/src/main/res/layout/fragment_login_symbol.xml rename app/src/test/java/io/github/wulkanowy/ui/modules/login/{options/LoginOptionsPresenterTest.kt => studentselect/LoginStudentSelectPresenterTest.kt} (57%) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index eb4efba71..0c64df610 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -19,7 +19,6 @@